diff --git a/app/assets/javascripts/clients.js b/app/assets/javascripts/clients.js index f28100b..3a433e5 100644 --- a/app/assets/javascripts/clients.js +++ b/app/assets/javascripts/clients.js @@ -1,41 +1,46 @@ $(document).ready(function() { if ($('#select-files').size() > 0) { $('#file-selector').hide(); $('#reset-button').hide(); $('#select-files').click(function() { $('#file-selector').show(); $('#reset-button').show(); }); } }); $(document).ready(function() { if ($('#file-submitter').size() > 0) { $("#file-tree").on("select_node.jstree", function(evt, data) { - add_input(data.node.id); + if (data.instance.is_leaf(data.node)) { + add_input(data.node.id, $('#file-tree').jstree(true).get_path(data.node, '/')); + } }); $("#file-tree").on("deselect_node.jstree", function(evt, data) { remove_input(data.node.id); }); } if ($('#invitation_user_id').size() > 0) { $('#invitation_user_id').chosen(); } }); -function add_input(id) { +function add_input(id, name) { $('#file-submitter'). append(''); + $('#restore_data_files'). + append('
  • ' + name + '
  • '); if ($('.js-file-input').size() > 0 && $('#file-submitter > input[type="submit"]').attr('disabled') == 'disabled') { $('#file-submitter > input[type="submit"]').attr('disabled', false); } } function remove_input(id) { $('#js-file-id-' + id).remove(); + $('#restore_data_files_' + id).remove(); if ($('.js-file-input').size() == 0) { $('#file-submitter > input[type="submit"]').attr('disabled', true); } } diff --git a/app/controllers/clients_controller.rb b/app/controllers/clients_controller.rb index 8ddbc87..c915113 100644 --- a/app/controllers/clients_controller.rb +++ b/app/controllers/clients_controller.rb @@ -1,189 +1,189 @@ class ClientsController < ApplicationController before_action :require_logged_in before_action :fetch_client, only: [:show, :jobs, :logs, :stats, :users, :restore, :run_restore, :restore_selected, :remove_user] before_action :fetch_logs, only: [:logs] before_action :require_non_blocked_client, only: [:restore, :restore_selected, :run_restore] # GET /clients # POST /clients def index @client_ids = Client.for_user(current_user.id).pluck(:ClientId) @clients = Client.where(ClientId: @client_ids).includes(:jobs) @hosts = current_user.hosts.not_baculized fetch_jobs_info get_charts end # GET /clients/1 def show @schedules = @client.host.job_templates.map(&:schedule) @filesets = @client.host.job_templates.map(&:fileset) @jobs = @client.jobs.backup_type.terminated.group(:name).maximum(:EndTime) end # GET /clients/1/jobs def jobs @jobs = @client.recent_jobs.page(params[:page]) end # GET /clients/1/logs def logs; end # GET /clients/1/stats # POST /clients/1/stats def stats get_charts end # GET /clients/1/users def users @users = @client.host.users if @client.manually_inserted? @invitation = @client.host.invitations.new excluded_ids = @users.pluck(:id) + @client.host.invitations.pluck(:user_id) @available_users = User.where(enabled: true).institutional. where.not(id: excluded_ids).pluck(:username, :id) end end # DELETE /clients/1/user def remove_user user = @client.host.users.find(params[:user_id]) redirect_path = users_client_path(@client) if @client.host.users.count == 1 flash[:alert] = 'You can not remove the last user' elsif @client.host.users.delete(user) flash[:success] = if @client.manually_inserted? 'User successfully removed' else 'User must be removed from the VM\'s list from your VM provider too (ViMa or Okeanos).' end if user.id == current_user.id redirect_path = clients_path end else flash[:alert] = 'User not removed, something went wrong' end redirect_to redirect_path end # GET /clients/1/restore def restore @restore_clients = Client.for_user(current_user.id) return if @client.is_backed_up? flash[:error] = 'Can not issue a restore for this client' redirect_to client_path(@client) end # POST /clients/1/run_restore def run_restore @location = params[:restore_location].blank? ? '/tmp/bacula_restore' : params[:restore_location] fileset = params[:fileset] - restore_point = fetch_restore_point - restore_client = fetch_restore_client + fetch_restore_point + fetch_restore_client if params[:commit] == 'Restore All Files' if @location.nil? || fileset.nil? || - !@client.host.restore(fileset, @location, restore_point, restore_client) + !@client.host.restore(fileset, @location, @restore_point, @restore_client) flash[:error] = 'Something went wrong, try again later' else msg = "Restore job issued successfully, files will be soon available in #{@location}" msg << " of client #{restore_client}" if restore_client.present? flash[:success] = msg end render js: "window.location = '#{client_path(@client)}'" else - session[:job_ids] = @client.get_job_ids(fileset, restore_point) - session[:restore_client] = restore_client + session[:job_ids] = @client.get_job_ids(fileset, @restore_point) + session[:restore_client] = @restore_client Bvfs.new(@client, session[:job_ids]).update_cache render 'select_files' end end # POST /clients/1/restore_selected def restore_selected Bvfs.new(@client, session[:job_ids]). restore_selected_files(params[:files], params[:location], nil, session[:restore_client]) session.delete(:job_ids) session.delete(:restore_client) flash[:success] = "Restore job issued successfully, files will be soon available in #{params[:location]}" redirect_to client_path(@client) end # GET /clients/1/tree?id=1 def tree @client = Client.for_user(current_user.id).find(params[:client_id]) bvfs = Bvfs.new(@client, session[:job_ids]) pathid = params[:id].to_i if pathid.nonzero? bvfs.fetch_dirs(pathid) else bvfs.fetch_dirs end tree = bvfs.extract_dir_id_and_name.map do |id, name| { id: id, text: name, state: { checkbox_disabled: true }, children: true } end if pathid.nonzero? bvfs.fetch_files(pathid) bvfs.extract_file_id_and_name.each do |id, name| tree << { id: id, text: name, type: 'file' } end end render json: tree end private def require_non_blocked_client if @client.host.blocked? flash[:error] = 'Client disabled by admins' redirect_to clients_path end end def fetch_client @client = Client.for_user(current_user.id).find(params[:id]) @client_ids = [@client.id] end def fetch_restore_client if params[:restore_client] - Client.for_user(current_user.id).find_by(ClientId: params[:restore_client]).try(:name) + @restore_client = Client.for_user(current_user.id).find_by(ClientId: params[:restore_client]).try(:name) end end def fetch_jobs_info @stats = JobStats.new(@client_ids) end def get_charts @job_status = ChartGenerator.job_statuses(@client_ids, days_ago) @job_stats = ChartGenerator.job_stats(@client_ids, days_ago - 1) end def fetch_restore_point if params['restore_time(4i)'].blank? || params['restore_time(5i)'].blank? || params[:restore_date].blank? return nil end - restore_point = - "#{params[:restore_date]} #{params['restore_time(4i)']}:#{params['restore_time(5i)']}:00" - begin - DateTime.strptime(restore_point, '%Y-%m-%d %H:%M:%S') - rescue - return nil - end - restore_point + @restore_point = + begin + DateTime.strptime( + "#{params[:restore_date]} #{params['restore_time(4i)']}:#{params['restore_time(5i)']}:00", + '%Y-%m-%d %H:%M:%S') + rescue + nil + end end end diff --git a/app/views/clients/_file_selector.html.erb b/app/views/clients/_file_selector.html.erb index 7b7c98c..aef99b9 100644 --- a/app/views/clients/_file_selector.html.erb +++ b/app/views/clients/_file_selector.html.erb @@ -1,22 +1,57 @@

    Files

    LOADING

    -
    - <%= form_tag(restore_selected_client_path, { id: 'file-submitter', style: 'display:none' }) do %> - <%= submit_tag 'Restore Selected Files', class: 'btn btn-default', disabled: true %> - <% end %> -
    +
    + diff --git a/app/views/clients/restore.html.erb b/app/views/clients/restore.html.erb index 8e356f0..7399d41 100644 --- a/app/views/clients/restore.html.erb +++ b/app/views/clients/restore.html.erb @@ -1,77 +1,74 @@
    <% if @client.is_backed_up? %>

    Restore files for "<%= @client.name %>"

    <%= bootstrap_form_tag(url: run_restore_client_path(@client), remote: true, layout: :horizontal, label_col: 'col-xs-4', control_col: 'col-xs-7', html: { id: 'basic-form' } ) do |f| %> <%= help_block('Restore to most recent backup by leaving date and time blank', 'col-xs-4', 'col-xs-7') %> <%= f.text_field :restore_date %> <%= f.time_select :restore_time, ignore_date: true, minute_step: 30, prompt: true %> <%= f.select(:fileset, options_from_collection_for_select(@client.file_sets, :id, :file_set)) %> <%= f.text_field :restore_location, placeholder: '/tmp/default_restore' %>
    <%= help_block( 'Restore and backup clients must have the same encryption key'.html_safe, 'col-xs-4', 'col-xs-7') %> <%= f.select( :restore_client, options_from_collection_for_select(@restore_clients, :id, :name, @client.id), label: tooltip_label('Restore Client', 'Client where the backup will be restored to')) %>
    -
    +
    <%= f.submit 'Select Specific Files', id: 'select-files', class: 'btn btn-primary' %>
    -
    -
    -
    -
    +
    <%= f.submit 'Restore All Files', class: 'btn btn-warning text-right', data: { confirm: "This will restore all your files" } %>
    <% end %>
    <% else %>

    Can not issue a restore for this client. It does not have any successful backups

    <% end %> <%= link_to client_path(@client), class: 'btn btn-default' do %> Back to client <% end %>
    <%= render partial: 'file_selector' %>
    diff --git a/app/views/clients/select_files.js.erb b/app/views/clients/select_files.js.erb index c92a56e..77c4f70 100644 --- a/app/views/clients/select_files.js.erb +++ b/app/views/clients/select_files.js.erb @@ -1,27 +1,30 @@ $('#basic-form input').attr('disabled', true); $('#basic-form select').attr('disabled', true); $('.loader').hide(); $('#file-tree').jstree({ 'core': { 'data' : { "url" : "<%= escape_javascript(tree_client_path(client_id: @client.id)) %>", "data" : function(node) { return { "id" : node.id }; }, "dataType" : "json" } }, 'checkbox' : { 'three_state': false }, "types" : { "file" : { "icon" : "glyphicon glyphicon-file" } }, "plugins" : ["types", "checkbox"] }); -$('#file-submitter').show(); +$('#restore-details').show(); $('#file-submitter'). append(''); +$('#restore_data_point').html("<%= @restore_point || Time.now.strftime('%Y-%m-%d %H:%M:%S') %>"); +$('#restore_data_location').html("<%= @location %>"); +$('#restore_data_client').html("<%= @restore_client || @client.name %>");