diff --git a/app/controllers/hosts_controller.rb b/app/controllers/hosts_controller.rb index d6907a0..971f7f1 100644 --- a/app/controllers/hosts_controller.rb +++ b/app/controllers/hosts_controller.rb @@ -1,64 +1,71 @@ class HostsController < ApplicationController - before_action :fetch_host, only: [:show, :edit, :update, :destroy, :submit_config, :revoke] + before_action :fetch_host, only: [:show, :edit, :update, :destroy, :submit_config, + :revoke, :restore] # GET /hosts/new def new @host = Host.new end # POST /hosts def create @host = Host.new(fetch_params) if @host.save current_user.hosts << @host redirect_to host_path @host else render :new end end # GET /hosts/1 def show; end # GET /hosts/1/edit def edit; end # PATCH /hosts/1 def update updates = fetch_params.slice(:port, :password) if updates.present? && @host.update_attributes(updates) @host.recalculate redirect_to host_path @host else render :edit end end # DELETE /hosts/1 def destroy @host.destroy redirect_to root_path end # POST /hosts/1/submit_config def submit_config @host.dispatch_to_bacula redirect_to host_path(@host) end # DELETE /hosts/1/revoke def revoke @host.remove_from_bacula redirect_to root_path end + # POST /hosts/1/restore + def restore + @host.restore + redirect_to client_path(@host.client) + end + private def fetch_host @host = current_user.hosts.includes(job_templates: [:fileset, :schedule]).find(params[:id]) end def fetch_params params.require(:host).permit(:fqdn, :port, :password) end end diff --git a/app/models/client.rb b/app/models/client.rb index e9d5bbd..eb68a58 100644 --- a/app/models/client.rb +++ b/app/models/client.rb @@ -1,84 +1,91 @@ class Client < ActiveRecord::Base self.table_name = :Client self.primary_key = :ClientId alias_attribute :name, :Name alias_attribute :uname, :Uname alias_attribute :auto_prune, :AutoPrune alias_attribute :file_retention, :FileRetention alias_attribute :job_retention, :JobRetention has_many :jobs, foreign_key: :ClientId has_one :host, foreign_key: :name, primary_key: :Name scope :for_user, ->(user_id) { joins(host: :users).where(users: { id: user_id }) } DAY_SECS = 60 * 60 * 24 RECENT_JOBS_COUNT = 5 # Fetches the client's job_templates that are already persisted to # Bacula's configuration # # @return [ActiveRecord::Relation] of `JobTemplate` def persisted_jobs host.job_templates.where(baculized: true).includes(:fileset, :schedule) end # Fetches the client's performed jobs in reverse chronological order # # @return [ActiveRecord::Relation] of `Job` def recent_jobs jobs.order(EndTime: :desc).limit(RECENT_JOBS_COUNT).includes(:file_set) end # Helper method. It shows the client's job retention, # (which is expressed in seconds) in days. # # @return [Integer] def job_retention_days job_retention / DAY_SECS end # Helper method. It shows the client's file retention, # (which is expressed in seconds) in days. # # @return [Integer] def file_retention_days file_retention / DAY_SECS end # Helper method for auto_prune # # @return [String] 'yes' or 'no' def auto_prune_human auto_prune == 1 ? 'yes' : 'no' end # Helper method for displayin the last job's datetime in a nice format. def last_job_date_formatted if job_time = jobs.backup_type.last.try(:end_time) I18n.l(job_time, format: :long) end end + # Shows if a client has any backup jobs to Bacule config + # + # @return [Boolean] + def is_backed_up? + jobs.backup_type.any? + end + # Shows the total file size of the jobs that run for a specific client # # @return [Integer] Size in Bytes def backup_jobs_size jobs.backup_type.map(&:job_bytes).sum end # Shows the total files' count for the jobs that run for a specific client # # @return [Integer] File count def files_count jobs.map(&:job_files).sum end # Fetches the client's jobs that are running at the moment # # @return [Integer] def running_jobs jobs.running.count end end diff --git a/app/views/clients/_client_details.html.erb b/app/views/clients/_client_details.html.erb index fe365ec..8057c98 100644 --- a/app/views/clients/_client_details.html.erb +++ b/app/views/clients/_client_details.html.erb @@ -1,47 +1,54 @@
Name <%= @client.name %>
Uname <%= @client.uname %>
Active Jobs <%= @client.running_jobs %>
Last Backup <%= @client.last_job_date_formatted %>
File Retention <%= @client.file_retention_days %> days
Job Retention <%= @client.job_retention_days %> days
Total Space Used <%= number_to_human_size @client.backup_jobs_size %>
Files count <%= number_by_magnitude(@client.files_count) %>
Auto Prune <%= @client.auto_prune_human %>
- <%= link_to 'Restore Files', '#', class: "btn btn-warning", role: "button" %> + <% if @client.is_backed_up? %> + <%= link_to 'Restore Files', restore_host_path(@client.host), + class: "btn btn-warning", role: "button", method: :post, + data: { + confirm: "This will restore all your files at the most recent backup (#{@client.last_job_date_formatted})" + } + %> + <% end %>
diff --git a/config/routes.rb b/config/routes.rb index e4ad367..dad4797 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,22 +1,23 @@ Rails.application.routes.draw do resources :clients, only: [:index, :show] resources :hosts, only: [:new, :create, :show, :edit, :update, :destroy] do member do post :submit_config + post :restore 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 :schedules, only: [:show, :new, :edit, :create, :update, :destroy] end root 'clients#index' end diff --git a/spec/routing/host_routing_spec.rb b/spec/routing/host_routing_spec.rb index 4b2e28d..3d02b1c 100644 --- a/spec/routing/host_routing_spec.rb +++ b/spec/routing/host_routing_spec.rb @@ -1,37 +1,42 @@ require 'spec_helper' describe HostsController do it 'routes GET /hosts/new' do expect(get('/hosts/new')).to route_to(controller: 'hosts', action: 'new') end it 'routes POST /hosts' do expect(post('/hosts')).to route_to(controller: 'hosts', action: 'create') end it 'routes GET /hosts/1' do expect(get('/hosts/1')).to route_to(controller: 'hosts', action: 'show', id: '1') end it 'routes GET /hosts/1/edit' do expect(get('/hosts/1/edit')).to route_to(controller: 'hosts', action: 'edit', id: '1') end it 'routes PUT /hosts/1' do expect(put('/hosts/1')).to route_to(controller: 'hosts', action: 'update', id: '1') end it 'routes DELETE /hosts/1' do expect(delete('/hosts/1')).to route_to(controller: 'hosts', action: 'destroy', id: '1') end it 'routes POST /hosts/1/submit_config' do expect(post('/hosts/1/submit_config')). to route_to(controller: 'hosts', action: 'submit_config', id: '1') end it 'routes DELETE /hosts/1/revoke' do expect(delete('/hosts/1/revoke')). to route_to(controller: 'hosts', action: 'revoke', id: '1') end + + it 'routes POST /hosts/1/restore' do + expect(post('/hosts/1/restore')). + to route_to(controller: 'hosts', action: 'restore', id: '1') + end end