diff --git a/app/controllers/filesets_controller.rb b/app/controllers/filesets_controller.rb index 8fbac37..77c6c0c 100644 --- a/app/controllers/filesets_controller.rb +++ b/app/controllers/filesets_controller.rb @@ -1,51 +1,82 @@ class FilesetsController < ApplicationController before_action :require_logged_in - before_action :fetch_host, only: [:new, :create, :show] - before_action :fetch_job_id, only: [:new, :create] + before_action :fetch_host, only: [:new, :create, :show, :edit, :update] + before_action :fetch_job_id, only: [:new, :create, :edit, :update] + before_action :fetch_fileset, only: [:show, :edit, :update] def new @fileset = @host.filesets.new + @fileset.include_directions = { 'file' => [nil] } end def show @fileset = @host.filesets.find(params[:id]) respond_to do |format| format.js {} end end + # GET /hosts/:host_id/filesets/:id/edit + def edit + @fileset.include_files = @fileset.include_directions['file'] + end + + # PATCH /hosts/:host_id/filesets/:id/ + def update + if @fileset.update(fetch_params) + flash[:success] = 'Fileset updated successfully' + participating_hosts = @fileset.participating_hosts + if participating_hosts.size.nonzero? + participating_hosts.each(&:recalculate) + flash[:alert] = 'You will need to redeploy the afffected clients: ' + + participating_hosts.map(&:name).join(', ') + end + if @job_id + redirect_to edit_host_job_path(@host, @job_id, fileset_id: @fileset.id) + else + redirect_to new_host_job_path(@host, fileset_id: @fileset.id) + end + else + render :edit + end + end + def create @fileset = @host.filesets.new(fetch_params) if @fileset.save flash[:success] = 'Fileset created' if @job_id.present? redirect_to edit_host_job_path(@host, @job_id, fileset_id: @fileset.id) else redirect_to new_host_job_path(@host, fileset_id: @fileset.id) end else @fileset.include_files = nil @fileset.exclude_directions = nil render :new end end def destroy end private def fetch_host @host = current_user.hosts.find(params[:host_id]) end def fetch_job_id @job_id = @host.job_templates.find(params[:job_id]).id if params[:job_id].present? end + def fetch_fileset + @fileset = @host.filesets.find(params[:id]) + end + def fetch_params params.require(:fileset).permit(:name, exclude_directions: [], include_files: []) end end diff --git a/app/models/fileset.rb b/app/models/fileset.rb index 686754a..7056f3a 100644 --- a/app/models/fileset.rb +++ b/app/models/fileset.rb @@ -1,98 +1,105 @@ # Fileset model is the application representation of Bacula's Fileset. # It has references to a host and job templates. class Fileset < ActiveRecord::Base serialize :exclude_directions serialize :include_directions, JSON attr_accessor :include_files belongs_to :host has_many :job_templates validates :name, presence: true, uniqueness: { scope: :host } validate :has_included_files, on: :create validates_with NameValidator before_save :sanitize_exclude_directions, :sanitize_include_directions DEFAULT_EXCLUDED = %w{/var/lib/bacula /proc /tmp /.journal /.fsck /bacula} DEFAULT_INCLUDE_OPTIONS = { signature: :SHA1, compression: :GZIP } DEFAULT_INCLUDE_FILE_LIST = ['/'] # Constructs an array where each element is a line for the Fileset's bacula config # # @return [Array] def to_bacula_config_array ['FileSet {'] + [" Name = \"#{name_for_config}\""] + include_directions_to_config_array + exclude_directions_to_config_array + ['}'] end # Generates a name that will be used for the configuration file. # It is the name that will be sent to Bacula through the configuration # files. # # @return [String] def name_for_config [host.name, name].join(' ') end + # Returns the hosts that have enabled jobs that use this fileset + # + # @return [ActiveRecord::Relation] the participating hosts + def participating_hosts + Host.joins(:job_templates).where(job_templates: { enabled: true, fileset_id: id }).uniq + end + private def has_included_files if include_files.blank? || include_files.all?(&:blank?) errors.add(:include_files, :cant_be_blank) end end def sanitize_include_directions files = include_files.compact.uniq.keep_if(&:present?) return false if files.blank? self.include_directions = { options: DEFAULT_INCLUDE_OPTIONS, file: files } end def sanitize_exclude_directions self.exclude_directions = exclude_directions.keep_if(&:present?).uniq rescue nil end def exclude_directions_to_config_array return [] if exclude_directions.empty? [' Exclude {'] + exclude_directions.map { |x| " File = \"#{x}\"" } + [' }'] end def include_directions_to_config_array return [] if include_directions.blank? [" Include {"] + included_options + included_files + [' }'] end def included_options formatted = [" Options {"] options = include_directions.deep_symbolize_keys[:options]. reverse_merge(DEFAULT_INCLUDE_OPTIONS) options.each do |k,v| if not [:wildfile].include? k formatted << " #{k} = #{v}" else formatted << v.map { |f| " #{k} = \"#{f}\"" } end end formatted << " }" formatted end def included_files include_directions['file'].map { |f| " File = #{f}" } end def included_wildfile include_directions['wildfile'].map { |f| " wildfile = \"#{f}\"" }.join("\n") end end diff --git a/app/views/filesets/_form.html.erb b/app/views/filesets/_form.html.erb index 3bc01df..8d0a7df 100644 --- a/app/views/filesets/_form.html.erb +++ b/app/views/filesets/_form.html.erb @@ -1,16 +1,19 @@ -<%= bootstrap_form_for(@fileset, url: host_filesets_path(@host, @fileset), layout: :horizontal, +<%= bootstrap_form_for(@fileset, url: url, method: method, layout: :horizontal, label_col: 'col-xs-3', control_col: 'col-xs-8') do |f| %>
<%= f.text_field :name %> - <%= text_with_errors_and_plus(@fileset, :fileset, :include_files, 'Files', '/') %> + + <% @fileset.include_directions['file'].each do |file| %> + <%= text_with_errors_and_plus(@fileset, :fileset, :include_files, 'Files', '/', file) %> + <% end %> <%= text_with_errors_and_plus(@fileset, :fileset, :exclude_directions, 'Exclude', '/bacula') %> <%= (hidden_field_tag :job_id, @job_id) if @job_id%>
<%= f.submit class: 'btn btn-success' %>
<% end %> diff --git a/app/views/filesets/edit.html.erb b/app/views/filesets/edit.html.erb new file mode 100644 index 0000000..de7cc5a --- /dev/null +++ b/app/views/filesets/edit.html.erb @@ -0,0 +1,22 @@ +
+
+
+
+

Edit Fileset: <%= @fileset.name %>

+
+ +
+ + <%= render partial: 'form', + locals: { url: host_fileset_path(@host, @fileset.id, job_id: @job_id), method: :patch } %> +
+
+
+ +
+
+ <%= link_to 'Cancel', + @job_id.present? ? edit_host_job_path(@host, @job_id) : new_host_job_path(@host), + role: 'button', class: 'btn btn-danger'%> +
+
diff --git a/app/views/filesets/new.html.erb b/app/views/filesets/new.html.erb index 05870e6..73a04f1 100644 --- a/app/views/filesets/new.html.erb +++ b/app/views/filesets/new.html.erb @@ -1,8 +1,9 @@

New Fileset

- <%= render 'form' %> + <%= render partial: 'form', + locals: { url: host_filesets_path(@host), method: :post } %>
<%= link_to 'Back to job', @job_id.present? ? edit_host_job_path(@host, @job_id) : new_host_job_path(@host) %> diff --git a/app/views/jobs/_fileset.html.erb b/app/views/jobs/_fileset.html.erb index a33c495..784969f 100644 --- a/app/views/jobs/_fileset.html.erb +++ b/app/views/jobs/_fileset.html.erb @@ -1,9 +1,20 @@ +<% if job_id = (@job.try(:id) || @job_id) %> + <% url_options = { job_id: job_id } %> +<% else %> + <% url_options = {} %> +<% end %> +
-

Fileset "<%= fileset.name %>"

+

+ Fileset "<%= fileset.name %>" + <%= link_to edit_host_fileset_path(@host, fileset.id, url_options) do %> + + <% end %> +


 <%= fileset.to_bacula_config_array.join("\n") %>
   
diff --git a/app/views/jobs/edit.html.erb b/app/views/jobs/edit.html.erb index 5d8b988..9ea285f 100644 --- a/app/views/jobs/edit.html.erb +++ b/app/views/jobs/edit.html.erb @@ -1,32 +1,26 @@

Edit Job Template <%= @job.name %>

Job Attributes


<%= render 'form' %>
+ <%= link_to 'Cancel', host_job_path(@host, @job), class: 'btn btn-danger right', + role: 'button' %>
<% fileset = @fileset || @job.fileset %> <%= render partial: 'fileset', locals: { fileset: fileset } if fileset %>
<% schedule = @schedule || @job.schedule %> <%= render partial: 'schedule', locals: { schedule: schedule } if schedule %>
- -
- -
-
- <%= link_to 'Cancel', host_job_path(@host, @job), class: 'btn btn-danger', role: 'button' %> -
-
diff --git a/config/routes.rb b/config/routes.rb index 90f83d0..d4a12c2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,84 +1,84 @@ Rails.application.routes.draw do root 'application#index' post 'grnet' => 'application#grnet' get 'institutional' => 'application#institutional' match 'vima', to: 'application#vima', :via => [:get, :post] get 'logout' => 'application#logout' resources :clients, only: [:index, :show] do member do get :jobs get :logs get :stats post :stats get :users get :restore post :run_restore end collection do post :index end end resources :hosts, only: [:new, :create, :show, :edit, :update, :destroy] do member do post :submit_config post :disable delete :revoke end resources :jobs, only: [:new, :create, :show, :edit, :update, :destroy] do member do patch :toggle_enable post :backup_now end end - resources :filesets, only: [:show, :new, :create, :destroy] + resources :filesets, only: [:show, :new, :create, :edit, :update, :destroy] resources :schedules, only: [:show, :new, :edit, :create, :update, :destroy] end namespace :admin do match '/', to: 'base#index', via: [:get, :post] get '/login' => 'base#login', as: :login resources :settings, only: [:index, :new, :create, :edit, :update] do member do delete :reset end end resources :clients, only: [:index, :show] do member do get :jobs get :logs get :stats post :stats get :configuration post :disable post :block post :unblock delete :revoke end end resources :hosts, only: [:show] do collection do get :unverified end member do post :verify end end resources :users, only: [:index, :new, :create, :show, :edit, :update] do member do patch :ban patch :unban end end end end diff --git a/spec/routing/fileset_routing_spec.rb b/spec/routing/fileset_routing_spec.rb index 2c60272..b07ae07 100644 --- a/spec/routing/fileset_routing_spec.rb +++ b/spec/routing/fileset_routing_spec.rb @@ -1,23 +1,33 @@ require 'spec_helper' describe FilesetsController do it 'routes GET /hosts/:host_id/filesets/new' do expect(get('/hosts/1/filesets/new')). to route_to(controller: 'filesets', action: 'new', host_id: '1') end it 'routes POST /hosts/:host_id/filesets' do expect(post('/hosts/1/filesets')). to route_to(controller: 'filesets', action: 'create', host_id: '1') end it 'routes GET /hosts/:host_id/filesets/:id' do expect(get('/hosts/1/filesets/2')). to route_to(controller: 'filesets', action: 'show', host_id: '1', id: '2') end + it 'routes GET /hosts/:host_id/filesets/:id/edit' do + expect(get('/hosts/1/filesets/2/edit')). + to route_to(controller: 'filesets', action: 'edit', host_id: '1', id: '2') + end + + it 'routes PATCH /hosts/:host_id/filesets/:id' do + expect(patch('/hosts/1/filesets/2')). + to route_to(controller: 'filesets', action: 'update', host_id: '1', id: '2') + end + it 'routes DELETE /hosts/:host_id/filesets/:id' do expect(delete('/hosts/1/filesets/2')). to route_to(controller: 'filesets', action: 'destroy', host_id: '1', id: '2') end end