', { 'class': 'well restore-well' });
div.append(top);
div.append(bottom);
return div;
}
/* rudimentary check for trying to escape homedir.
* the backend will do a better check later */
function good_path(path) {
path = path.replace(/^\/+/, '').replace(/\/+$/, '').split('/');
var backs = 0;
var forwards = 0;
for (var i = 0; i < path.length; i++) {
if (path[i] == '..') {
backs += 1;
} else {
forwards += 1;
}
}
return forwards >= backs;
}
/* runs whenever a dump path is changed */
function check_path(input) {
input = $(input);
var err_div = $(input.data('check-error'));
if (good_path(input.val())) {
err_div.hide();
} else {
err_div.show();
}
}
/* displays a log viewer when "View Fail Log" is clicked on a restore */
function view_fail_log(link) {
link = $(link);
var div = $('#log-modal-body');
div.empty();
$.each(link.data('log'), function(e_id, entry) {
var date = stamp_to_human(entry[0], true)
var msg = entry[1];
var p = $('
');
p.append($('', { text: date }));
p.append(' '.concat(msg));
div.append(p);
});
$('#log-modal').modal('show');
}
/* Shows the "Submit Ticket" popup modal */
function ticket_modal(link) {
link = $(link);
var tag = link.data('tag');
if (link.data('sent') == 'y') {
return;
}
if (window.tickets_submitted.indexOf(tag) != -1) {
return;
}
// access data attrs of the link and place them on the modal before showing
var log = link.data('log');
var title = link.data('title');
var params = link.data('params');
var task = link.data('task');
var modal = $('#ticket-modal');
$('#ticket-do-btn').prop('disabled', false);
$('#ticket-do-btn').text('Submit Ticket');
$('#ticket-error').hide();
modal.data('tag', tag);
modal.data('task', task);
modal.data('log', log);
modal.data('title', title);
modal.data('params', params);
modal.modal('show');
}
/* when "Submit Ticket" is clicked in the popup modal, this emails support */
function make_ticket() {
var modal = $('#ticket-modal')
var log = modal.data('log');
var title = modal.data('title');
var task = modal.data('task');
var backup_params = modal.data('params');
var tag = modal.data('tag');
$('#ticket-do-btn').prop('disabled', true);
$('#ticket-do-btn').text('Please wait...');
var params = {
title: title,
task: task,
ipaddr: window.remote_ip,
log: log,
params: backup_params,
msg: $('#ticket-body').val()
};
do_post('make_ticket', params, function(data) {
if (data.status == 0) {
window.tickets_submitted.push(tag);
$('.ticket-submit').each(function(index, alert) { // show the success message
alert = $(alert);
if (alert.data('tag') == tag) {
alert.empty();
alert.addClass('ticket-submitted alert alert-success');
alert.append($('', { 'class': 'fa fa-check-circle ticket-success-icon' }));
alert.append('A ticket was submitted with the restore log for troubleshooting');
}
});
$('.ticket-submit-btn').each(function(index, btn) { // disable the button
btn = $(btn);
if (btn.data('tag') == tag) {
btn.css('color', '#666');
btn.data('sent', 'y');
}
});
modal.modal('hide');
$('#ticket-body').val('');
} else {
console.log(data);
$('#ticket-error').show();
}
});
}
/* update a progress-bar div */
function set_bar(elem, numerator, denominator, show_msg) {
if (numerator == '?') {
// we were not able to fetch dir sizes from cPanel
// and the customer selected for custom backups
elem.css('background-color', 'orangered');
elem.css('width', '100%');
elem.text("Data Unavailable");
return;
}
if (denominator == 0) {
if (show_msg) {
elem.text('DISABLED');
}
var percent = 100;
} else if (numerator > denominator) {
if (show_msg) {
elem.text('OVER QUOTA');
}
var percent = 100;
} else {
elem.text('');
var percent = numerator / denominator * 100
}
if (percent <= 30) {
var color = 'green';
} else if (percent <= 50) {
var color = 'goldenrod';
} else if (percent <= 80) {
var color = 'orangered';
} else {
var color = 'red';
}
elem.css('background-color', color);
elem.css('width', String(percent).concat('%'));
}
/* then the cancel button next to an ongoing restore is clicked */
function cancel_restore_item(link) {
link = $(link);
var well = link.closest('.well');
do_post('cancel_restore', { tag: link.data('tag') }, function(data) {
if (data.status == 0) {
update_restore_queues();
}
});
}
/* calculate homedir selection size, return '?' or a number in GB */
function calc_home_usage() {
if (!get_switch_state('homedir_enabled')) {
$('#homedir-apply-btn').prop('disabled', false);
console.log('homedir disabled, so its size is 0MB');
return 0; // disabled
}
var home_mode = $('input[name=mode_homedir]:checked').val();
if (home_mode == 'whitelist') {
var homedir_mb = 0;
var included = get_browser_selected('#homedir-include-browser');
$('#homedir-apply-btn').prop('disabled', included.length == 0);
var all_sizes = $('#homedir-include-browser').data('all-sizes');
$.each(included, function(index, included_item) {
if (!(included_item in all_sizes)) return '?';
if (all_sizes[included_item] === null) return '?';
homedir_mb += all_sizes[included_item];
});
console.log('homedir whitelist total: '.concat(homedir_mb).concat('MB'));
return homedir_mb;
} else if (home_mode == 'blacklist') {
var homedir_mb = $('#homedir-size').data('homedir-size');
var quotactl_mb = homedir_mb;
if (homedir_mb == '?') return '?';
var excluded = get_browser_selected('#homedir-exclude-browser');
$('#homedir-apply-btn').prop('disabled', excluded.length == 0);
var all_sizes = $('#homedir-exclude-browser').data('all-sizes');
$.each(excluded, function(index, excluded_item) {
if (!(excluded_item in all_sizes)) return '?';
if (all_sizes[excluded_item] === null) return '?';
homedir_mb -= all_sizes[excluded_item];
});
console.log('homedir size after blacklist: '.concat(homedir_mb).concat('MB (quotactl was ').concat(quotactl_mb).concat('MB)'));
return homedir_mb;
} else { // entire homedir selected
$('#homedir-apply-btn').prop('disabled', false);
var homedir_mb = $('#homedir-size').data('homedir-size');
if (homedir_mb == '?') return '?';
console.log('homedir size from quotactl is '.concat(homedir_mb).concat('MB'));
return homedir_mb;
}
}
/* set the total usage bar at the top of the page from usage in mb */
function recalculate_usage() {
var total_gb_span = $('#total_gb');
var avail_gb_span = $('#avail_gb');
var quota_mb = Number(total_gb_span.data('quota-mb'));
var srv_unused = total_gb_span.data('srv-unused');
var mb_usage = 0;
// Add homedir usage
var homedir_mb = calc_home_usage();
// update totals under custom selections for homedir
$('.total-selected-homedir').text(to_gb(homedir_mb));
$('.usage_gb_homedir').text(to_gb(homedir_mb));
if (homedir_mb === '?') {
mb_usage = '?';
} else {
mb_usage += homedir_mb;
}
// Add MySQL and PgSQL usage
$.each(['mysql', 'pgsql'], function(i, dbtype) {
var dbase_mode = $('input[name=mode_'.concat(dbtype).concat(']:checked')).val();
if (dbase_mode != undefined) { // it's on the page
if (!get_switch_state(dbtype.concat('_enabled'))) {
console.log(dbtype.concat(' disabled, so its size is 0MB'));
var dbase_mb = 0; // disabled
$('#'.concat(dbtype).concat('-apply-btn')).prop('disabled', false);
} else if (dbase_mode == 'whitelist') {
var dbase_mb = get_custom_db_usage(dbtype, true);
console.log(dbtype.concat(' whitelist total: '.concat(dbase_mb).concat('MB')));
} else if (dbase_mode == 'blacklist') {
var total_all_dbs = get_custom_db_total(dbtype);
if (total_all_dbs != '?') {
var dbase_mb = total_all_dbs - get_custom_db_usage(dbtype, false);
} else {
var dbase_mb = '?';
}
console.log(dbtype.concat(' size after blacklist: ').concat(dbase_mb).concat('MB (total was ').concat(total_all_dbs).concat('MB)'));
} else { // all databases
$('#'.concat(dbtype).concat('-apply-btn')).prop('disabled', false);
var dbase_mb = get_custom_db_total(dbtype);
console.log(dbtype.concat(' total (all) is ').concat(dbase_mb).concat('MB'));
}
// update totals under custom selections for databases
$('.total-selected-'.concat(dbtype)).text(to_gb(dbase_mb));
$('.usage_gb_'.concat(dbtype)).text(to_gb(dbase_mb));
if (mb_usage != '?') {
mb_usage += dbase_mb;
}
}
});
// If the child accounts tab is shown, update the usage for the parent
var parent_usage = $('#parent_usage');
if (parent_usage.length > 0) { // it exists
parent_usage.text(to_gb(mb_usage));
parent_bar = $('#parent_progressbar');
set_bar(parent_bar, mb_usage, quota_mb, true);
if (mb_usage != '?') {
mb_usage += get_child_total();
}
}
// Set the total at the top
total_gb_span.text(to_gb(mb_usage));
if (mb_usage == "?") {
avail_gb_span.text("?");
} else {
var avail = quota_mb - mb_usage;
if (srv_unused != undefined && srv_unused < avail) {
avail = srv_unused;
}
if (avail < 0) {
avail = Math.abs(avail);
$('#avail_denominator').hide();
$("#avail_lbl").text(" more GB needed");
} else {
$('#avail_denominator').show();
$("#avail_lbl").text("GB remain");
}
avail_gb_span.text(to_gb(avail));
}
// Update each bar shown under custom selections in the settings tab
$('.total-selected-bar').each(function(b_index, bar) {
set_bar($(bar), mb_usage, quota_mb, true);
});
// If over quota, also show a warning div beneath the total bar and
// within any custom selections that are expanded
if (mb_usage > quota_mb) {
$('#total-incalculable-warning').hide();
$('#total-over-quota-warning').show();
$('#over-quota-hover').css('display', 'inline');
$('.total-selected-warning').show();
} else if (mb_usage == "?") {
$('#total-incalculable-warning').show();
$('#total-over-quota-warning').hide();
$('#over-quota-hover').hide();
$('.total-selected-warning').hide();
} else {
$('#total-incalculable-warning').hide();
$('#total-over-quota-warning').hide();
$('#over-quota-hover').hide();
$('.total-selected-warning').hide();
}
}
/* get the usage of a all selected items for a given database backup type and whether
* we're counting for a whitelist (or blacklist) */
function get_custom_db_usage(baktype, whitelist) {
if (whitelist) {
var inputs = $('#custom_items_whitelist_'.concat(baktype).concat(' input'));
} else {
var inputs = $('#custom_items_blacklist_'.concat(baktype).concat(' input'));
}
var size_mb = 0;
var num_checked = 0;
var error = false;
$.each(inputs, function(i, checkbox) {
checkbox = $(checkbox);
if (checkbox.is(':checked')) {
num_checked += 1;
var this_size = checkbox.data('size');
if (this_size == '?') {
error = true;
} else {
size_mb += Number(this_size);
}
}
});
$('#'.concat(baktype).concat('-apply-btn')).prop('disabled', num_checked == 0);
if (error) return '?';
return size_mb;
}
/* get the total size of all db items for custom backups if all were selected */
function get_custom_db_total(baktype) {
var size_mb = 0;
var error = false;
$.each($('#custom_items_whitelist_'.concat(baktype).concat(' input')), function(i, checkbox) {
var this_size = $(checkbox).data('size');
if (this_size == '?') {
error = true;
} else {
size_mb += Number(this_size);
}
});
if (error) return '?';
return size_mb;
}
/* get the state of a cpanel enable/disable switch without needing AngularJS */
function get_switch_state(id) {
return $("#".concat(id)).hasClass('btn-primary');
}
/* set the state of a cpanel enable/disable switch without needing AngularJS */
function set_switch_state(id, enabled) {
var btn = $('#'.concat(id));
var label = $("#".concat(id).concat(' span'));
if (enabled) {
btn.removeClass('btn-danger');
btn.addClass('btn-primary');
label.html(label.data('enabled-html'));
} else {
btn.removeClass('btn-primary');
btn.addClass('btn-danger');
label.html(label.data('disabled-html'));
}
}
/* When the "Restore" link is clicked in the settings tab, this takes
the user to that section of the restore tab and auto-selects that date */
function goto_restore(link) {
link = $(link);
var baktype = link.data('baktype');
var geo = link.data('geo');
if (baktype == 'homedir') {
// the change event will already init the file browser, so
// if this is the first time expanding, avoid initializing it twice
window.homedir_restore_shown_once = true;
}
var collapse = $('#restore_'.concat(baktype).concat('_collapse'));
var val = ''.concat(geo).concat(':').concat(link.data('snap'));
collapse.find('.restore-date-select').val(val).change();
// hide all other accordion items on the restore form
$.each($('#restore_tab .collapse'), function(i, elem) {
elem = $(elem);
if (collapse.attr('id') != elem.attr('id')) {
elem.collapse('hide');
}
});
collapse.collapse('show'); // show this accordion item
$('#nav-link-restore').tab('show');
}
function update_geo_dests() {
var geo_loc = $('#restore_accordion').data('geo-loc');
var cluster_loc = $('#restore_accordion').data('cluster-loc');
$('.restore-date-select').each(function (index, select) {
var select = $(select);
var baktype = select.data('baktype');
var geo = select.find(":selected").data('geo');
if (geo == 1) {
$("#geo-dest-".concat(baktype)).text(geo_loc);
} else {
$("#geo-dest-".concat(baktype)).text(cluster_loc);
}
});
}
/* flip the state of a cpanel enable/disable switch without needing AngularJS */
function toggle_switch_state(id) {
var enabled = !get_switch_state(id);
set_switch_state(id, enabled);
if (id.endsWith('_enabled')) {
var baktype = id.split('_', 1)[0];
apply_settings(baktype, '#'.concat(baktype).concat('apply-btn'));
}
set_child_usage(); // update child progress bars
show_hide_baktypes(); // show/hide any backup forms if necessary
recalculate_usage(); // adjust quotas for anything that changed
show_hide_child_cols(); // hide child account form columns if needed
update_sched(); // update scheduling column if it disabled something
if (id.startsWith('childnotify-')) {
validate_child_email();
}
if (id == 'do_child_limits') {
// submit on toggle if this is the enable button at the top of
// the child account form
check_overprovision();
apply_child_limits(false);
}
}
/* convert MB to GB and round 2 decimal points; return as a string */
function to_gb(mb) {
if (mb === '?') { return '?'; }
return (Math.round(Number(mb / 1024) * 100) / 100).toFixed(2);
}
/* Different dates may have different databases backed up.
* This populates the database select dropdown whever the date
* is changed in the restore form */
function update_restore_dbnames() {
$('.restore_db_date').each(function(index, date_select) {
var date_select = $(date_select);
var dbtype = date_select.data('baktype');
var date_option = date_select.find(":selected");
var dbname_select = $('#restore_dbname_'.concat(dbtype));
dbname_select.find('option').remove();
dbname_select.append($('', {
text: 'select',
value: ''
}));
var geo = date_option.data('geo');
$.each(date_option.data('dbsnaps'), function(dbname, snap_id) {
dbname_select.append($(' ', {
value: "".concat(geo).concat(":").concat(snap_id),
text: dbname
}));
});
});
}
/* only show custom lists under radio buttons which are selected and update
the "data backed up" column on the header */
function show_hide_custom() {
$('.apply-msg').hide(); // hide save mesages; form was just changed
$.each(['homedir', 'mysql', 'pgsql'], function(i, baktype) {
var checked = $('input[name=mode_'.concat(baktype).concat(']:checked')).val()
if (checked != undefined) {
var white_div = $('#custom_hide_whitelist_'.concat(baktype));
var black_div = $('#custom_hide_blacklist_'.concat(baktype));
if (checked == 'whitelist') {
white_div.show();
black_div.hide();
$('#mode_descr_'.concat(baktype)).text('Custom');
} else if (checked == 'blacklist') {
white_div.hide();
black_div.show();
$('#mode_descr_'.concat(baktype)).text('Custom');
} else {
white_div.hide();
black_div.hide();
if (get_switch_state(baktype.concat('_enabled'))) {
$('#mode_descr_'.concat(baktype)).text('All Data');
} else {
$('#mode_descr_'.concat(baktype)).text('Disabled');
}
}
}
});
}
/* show only backup types which are enabled in the settings tab */
function show_hide_baktypes() {
$.each(['homedir', 'mysql', 'pgsql'], function(i, baktype) {
if ($('#'.concat(baktype).concat('_enabled')).length > 0) { // the form exists
var enabled = get_switch_state(baktype.concat('_enabled'));
if (enabled) {
$('#settings_form_'.concat(baktype)).show();
$('#settings_form_alert_'.concat(baktype)).hide();
} else {
$('#settings_form_'.concat(baktype)).hide();
$('#settings_form_alert_'.concat(baktype)).show();
}
}
});
show_hide_custom();
}
/* hides columns on the child account form when limiting them is disabled */
function show_hide_child_cols() {
if ($('#do_child_limits').length > 0) { // the form exists
var enabled = get_switch_state('do_child_limits');
if (enabled) {
$('.child-limit-inputs').show();
} else {
$('.child-limit-inputs').hide();
}
}
}
/* only show scheduling options (interval or days) below the radio button that's
currently checked and update the "schedule" column on the header */
function update_sched() {
$('.apply-msg').hide(); // hide save mesages; form was just changed
$.each(['homedir', 'mysql', 'pgsql'], function(i, baktype) {
if ($('#'.concat(baktype).concat('_enabled')).length > 0) { // the form exists
if (!get_switch_state(baktype.concat('_enabled'))) {
$('#sched_descr_'.concat(baktype)).text('Disabled');
} else if ($('input[name=scheduling_'.concat(baktype).concat(']:checked')).val() == 'interval') {
// we're using interval-based scheduling
$('#sched_interval_form_'.concat(baktype)).show();
$('#sched_daytime_form_'.concat(baktype)).hide();
var interval = $('#sched_interval_'.concat(baktype)).val();
if (interval == 1) {
$('#sched_descr_'.concat(baktype)).text('Every Day');
} else {
$('#sched_descr_'.concat(baktype)).text('Every '.concat(interval).concat(' Days'));
}
} else {
// we're using day/time-based scheduling
$('#sched_interval_form_'.concat(baktype)).hide();
$('#sched_daytime_form_'.concat(baktype)).show();
var hour = $('#scheduling_hour_'.concat(baktype)).val();
var meridiem = $('#scheduling_meridiem_'.concat(baktype)).val();
var day_labels = [];
$.each($('#scheduling_days_'.concat(baktype).concat(' input')), function(ii, checkbox) {
checkbox = $(checkbox);
if (checkbox.is(':checked')) {
day_labels.push(checkbox.data('short'));
}
});
if (day_labels.length == 0) {
day_labels = '?'; // no days are selected yet
} else {
day_labels = day_labels.join(', ');
}
$('#sched_descr_'.concat(baktype)).text(
day_labels
.concat(' | ')
.concat(hour)
.concat(meridiem)
);
}
}
});
}
/* Set the "current usage" column of the child tab */
function set_child_usage() {
var quota_mb = $('#total_gb').data('quota-mb');
$.each($('.childacct-row'), function(i, row_div) {
row_div = $(row_div);
var usage = row_div.find('.childacct-usage').data('usage');
if (usage != undefined) {
row_div.find('.usage_span').text(to_gb(usage));
} else {
usage = 0;
}
var bar = row_div.find('.childacct-progressbar');
if (get_switch_state('do_child_limits')) { // limits turned on
var limit = row_div.find('.childacct-limit').val();
var limit_span = row_div.find('.limit_span');
limit_span.text('/ '.concat(limit).concat('GB'));
limit_span.show();
set_bar(bar, usage, limit * 1024, true);
} else { // limits turned off; denominator is total quota
set_bar(bar, usage, quota_mb, true);
row_div.find('.limit_span').hide();
}
});
}
/* calculate total size of child accounts */
function get_child_total() {
var total = 0;
var limits_on = get_switch_state('do_child_limits');
$.each($('.childacct-row'), function(i, row_div) {
row_div = $(row_div);
// usage in MB for this one child
var this_usage = row_div.find('.childacct-usage').data('usage');
if (this_usage != undefined) {
if (limits_on) {
var this_limit = Number(row_div.find('.childacct-limit').val()) * 1024;
if (this_limit < this_usage) {
total += this_limit;
} else {
total += this_usage;
}
} else {
total += this_usage;
}
}
});
return total;
}
/* cancel button on the bottom of a restore form
* (not the button to cancel a requested restore that's already going) */
function cancel_restore_form(cancel_link) {
var collapse = $(cancel_link).closest('.collapse');
var restore_dbname_select = collapse.find('.restore_dbname_select');
if (restore_dbname_select.length > 0) {
// this is a database restore form
restore_dbname_select.val('');
} else {
// this is the homedir restore form
$('#homedir_filebrowser :input').prop('checked', false);
window.homedir_restore_shown_once = false; // reset to as if we never saw this form
}
var alert_div = collapse.find('.restore_alert');
var msg_div = collapse.find('.restore_alert_msg');
alert_div.removeClass('alert alert-danger');
msg_div.addClass('hidden');
msg_div.removeClass('restore_alert_msg_shown');
collapse.collapse('hide');
}
/* save button on the child account tab */
function apply_child_limits(from_submit_btn) {
if (!validate_child_email()) {
if (from_submit_btn) {
show_msg(false, 'child-limit-apply-msg', 'invalid email');
}
return;
}
if (from_submit_btn) {
$('#child-limit-apply-button').prop('disabled', true);
}
var email_err = $('#child-notify-invalid-email');
var params = {};
var child_email = $('#child-limit-email').val();
if (child_email.length > 0) {
params['email'] = child_email;
}
if (get_switch_state('do_child_limits')) {
params['do_limit'] = '1';
} else {
params['do_limit'] = '0';
}
if (params['do_limit'] == '1') {
params['default_limit'] = $('#child_limit_default').val();
var limits = {};
var notifs = {};
$.each($('.childacct-row'), function(i, row_div) {
row_div = $(row_div);
var name = row_div.find('.child-name').text();
limits[name] = row_div.find('.childacct-limit').val();
if (get_switch_state(row_div.find('.cjt2-toggle-switch').data('switch-id'))) {
notifs[name] = '1';
} else {
notifs[name] = '0';
}
});
params['limits'] = limits;
params['notifs'] = notifs;
}
do_post('set_child_limits', params, function(data) {
if (from_submit_btn) {
if (data.status != 0) {
show_msg(false, 'child-limit-apply-msg', data.data);
} else {
show_msg(true, 'child-limit-apply-msg', 'applied');
}
$('#child-limit-apply-button').prop('disabled', false);
} else {
if (data.status != 0) {
show_msg(false, 'child-limit-toggle-msg', data.data);
}
}
});
}
/* save buttons on the settings tab */
function apply_settings(baktype, button) {
$('.apply-msg').hide();
button = $(button);
button.prop('disabled', true);
var params = { baktype: baktype };
if (get_switch_state(baktype.concat('_enabled'))) { // backups enabled
params['enable'] = '1';
params['mode'] = $('input[name=mode_'.concat(baktype).concat(']:checked')).val();
} else { // backups disabled
params['enable'] = '0';
params['mode'] = 'all';
}
if (baktype == 'homedir') {
if (params['mode'] == 'whitelist') {
params['custom'] = get_browser_selected('#homedir-include-browser');
} else if (params['mode'] == 'blacklist') {
params['custom'] = get_browser_selected('#homedir-exclude-browser');
} else {
params['custom'] = null;
}
} else { // database backups
if (params['mode'] == 'whitelist') {
var inputs = $('#custom_items_whitelist_'.concat(baktype).concat(' input'));
params['custom'] = [];
$.each(inputs, function(inp_index, checkbox) {
checkbox = $(checkbox);
if (checkbox.is(':checked')) { params['custom'].push(checkbox.val()); }
});
} else if (params['mode'] == 'blacklist') {
var inputs = $('#custom_items_blacklist_'.concat(baktype).concat(' input'));
params['custom'] = [];
$.each(inputs, function(inp_index, checkbox) {
checkbox = $(checkbox);
if (checkbox.is(':checked')) { params['custom'].push(checkbox.val()); }
});
} else {
var inputs = [];
params['custom'] = null;
}
}
if (params['custom'] != null && params['custom'].length == 0) {
show_msg(false, baktype.concat('-apply-msg'), 'Nothing selected to backup');
button.prop('disabled', false);
return;
}
if ($('input[name=scheduling_'.concat(baktype).concat(']:checked')).val() == 'interval') {
// using interval scheduling
params['use_interval'] = '1';
params['interval'] = $('#sched_interval_'.concat(baktype)).val();
} else {
// using day/time scheduling
params['use_interval'] = '0';
params['hour'] = $('#scheduling_hour_'.concat(baktype)).val();
params['meridiem'] = $('#scheduling_meridiem_'.concat(baktype)).val();
params['days'] = [];
$.each($('#scheduling_days_'.concat(baktype).concat(' input')), function(day_index, checkbox) {
checkbox = $(checkbox);
if (checkbox.is(':checked')) {
params['days'].push(checkbox.val());
}
});
}
do_post('set_settings', params, function(data) {
if (data.status != 0) {
show_msg(false, baktype.concat('-apply-msg'), data.data);
} else {
show_msg(true, baktype.concat('-apply-msg'), 'applied');
}
button.prop('disabled', false);
});
}
/* "Restore" button on the restore tab; redirects to either
* do_homedir_restore or do_db_restore */
function do_restore(baktype, button) {
if (baktype != 'homedir' && $('#restore_dbname_'.concat(baktype)).val().length == 0) {
// database restore with no db selected
$('#no_db_'.concat(baktype)).show();
return;
}
var email = $('#'.concat(baktype).concat('-restore-email')).val();
if (email.length > 0 && !validate_email_string(email)) {
return; // invalid email entered
}
button = $(button);
var alert_div = $('#restore_alert_'.concat(baktype));
var msg = $('#restore_alert_msg_'.concat(baktype));
if (msg.hasClass('hidden')) {
alert_div.addClass('alert alert-danger');
msg.removeClass('hidden');
msg.addClass('restore_alert_msg_shown');
$('#'.concat(baktype).concat('-restore-msg')).hide();
} else {
alert_div.removeClass('alert alert-danger');
msg.addClass('hidden');
msg.removeClass('restore_alert_msg_shown');
button.prop('disabled', true);
if (baktype == 'homedir') {
do_homedir_restore(button);
} else {
do_db_restore(baktype, button);
}
}
}
/* requests home directory restores */
function do_homedir_restore(button) {
if (all_selected('#homedir_filebrowser')) {
var paths = [$('#restore_tab').data('home-path')];
} else {
var paths = get_browser_selected('#homedir_filebrowser');
}
var params = {
// list of full paths
paths: paths,
date: $('#restore_date_homedir option:selected').data('stamp'),
geo: parseInt($('#restore_date_homedir').val().substr(0, 1)),
snap: $('#restore_date_homedir').val().substr(2),
// target path will not include the /home/user/ part
target: $('#dump_path_homedir').val(),
mode: $('[name="restore_method_homedir"]:checked').val(),
email: $('#homedir-restore-email').val()
};
do_post('homedir_restore', params, function(data) {
if (data.status != 0) {
show_msg(false, 'homedir-restore-msg', data.data);
} else {
button.closest('.collapse').collapse('hide');
update_restore_queues();
setTimeout( // delay so the collapse has time to finish
function() {
show_msg(true, 'homedir-restore-msg', 'Queued');
},
1000
);
}
button.prop('disabled', false);
});
}
/* requests database restores */
function do_db_restore(baktype, button) {
var params = {
date: $('#restore_date_'.concat(baktype)).val().substr(2),
dbname: $('#restore_dbname_'.concat(baktype).concat(' option:selected')).text(),
geo: parseInt($('#restore_dbname_'.concat(baktype)).val().substr(0, 1)),
snap: $('#restore_dbname_'.concat(baktype)).val().substr(2),
// path will not include the /home/user/ part
target: $('#dump_path_'.concat(baktype)).val(),
mode: $('[name="restore_method_'.concat(baktype).concat('"]:checked')).val(),
email: $('#'.concat(baktype).concat('-restore-email')).val()
};
do_post(baktype.concat('_restore'), params, function(data) {
if (data.status != 0) {
console.log(data);
show_msg(false, baktype.concat('-restore-msg'), data.data);
} else {
button.closest('.collapse').collapse('hide');
update_restore_queues();
setTimeout( // delay so the collapse has time to finish
function() {
show_msg(true, baktype.concat('-restore-msg'), 'Queued');
},
1000
);
}
button.prop('disabled', false);
});
}
/* disables toggles for notifications for children when their limit
* is set to 0, because that would be redundant */
function child_notif_disable() {
$.each($('.childacct-row'), function(i, row_div) {
row_div = $(row_div);
var notif_toggle = row_div.find('.cjt2-toggle-switch');
if (Number(row_div.find('.childacct-limit').val()) <= 0) {
set_switch_state(notif_toggle.data('switch-id'), false);
notif_toggle.addClass('disabled');
} else {
notif_toggle.removeClass('disabled');
}
});
}
/* called when item selection on the homedir restore widget changes */
function enable_home_restore(has_items) {
$('#restore-btn-homedir').prop('disabled', !has_items);
}
/* all cancel buttons on the settings tab */
function cancel_settings(cancel_link) {
var collapse = $(cancel_link).closest('.collapse');
// set enable/disable back to what it was on page load
var oldval_span = collapse.find('.oldval-enable');
if (oldval_span.data('oldval') == 'y') {
set_switch_state(oldval_span.data('enableid'), true);
} else {
set_switch_state(oldval_span.data('enableid'), false);
}
// set the scheduling back
collapse.find('.sched_radio[data-oldval]').prop('checked', true).trigger('change');
collapse.find('.sched_hour').val(collapse.find('.sched_hour').data('oldval'));
collapse.find('.sched_days_checkbox[data-oldval="n"]').prop('checked', false);
collapse.find('.sched_days_checkbox[data-oldval="y"]').prop('checked', true);
collapse.find('.sched_meridiem[data-oldval]').prop('checked', true).trigger('change'); // AM/PM
// set the mode and selections back
collapse.find('.custom_checkbox[data-oldval="n"]').prop('checked', false);
collapse.find('.custom_checkbox[data-oldval="y"]').prop('checked', true);
collapse.find('.custom_radio[data-oldval]').prop('checked', true).trigger('change');
// hide this form
collapse.collapse('hide');
}
/* shows a message next to a save button */
function show_msg(success, id, msg) {
$('#'.concat(id).concat(' span')).text(msg);
var div = $('#'.concat(id));
if (success) {
div.removeClass('alert-danger');
div.addClass('alert-success');
} else {
div.removeClass('alert-success');
div.addClass('alert-danger');
}
div.show();
}
function check_overprovision() {
var total = 0;
$('.childacct-limit').each(function(i, lim) {
total += Number($(lim).val()) * 1024;
});
var do_limit = get_switch_state('do_child_limits');
var quota = Number($('#total_gb').data('quota-mb'));
if (do_limit && total > quota) {
$('#overprovision-warn').show();
$('.childacct-limit').addClass('overprov');
$('#child-limit-apply-button').prop('disabled', true);
} else {
$('#overprovision-warn').hide();
$('.childacct-limit').removeClass('overprov');
$('#child-limit-apply-button').prop('disabled', false);
}
}
/* when select/deselect all is clicked in custom items */
function custom_db_selectall(div_id, checked) {
$(div_id.concat(' input')).each(function(index, item) {
$(item).prop('checked', checked);
});
}
/* rigged to keyup on email inputs */
function validate_email(input) {
input = $(input);
email = input.val();
var err = $(input.data('err'));
if (input.attr('id') == 'child-limit-email') {
// email is required if notifications are on for child accounts
validate_child_email();
} else {
// email can be empty
if (email.length == 0 || validate_email_string(email)) {
err.hide();
} else {
err.show();
}
}
}
function validate_child_email() {
var addr = $('#child-limit-email').val();
var err = $('#child-notify-invalid-email');
var notifs_on = false;
$.each($('.childacct-row'), function(i, row_div) {
row_div = $(row_div);
if (get_switch_state(row_div.find('.cjt2-toggle-switch').data('switch-id'))) {
notifs_on = true;
}
});
if (!notifs_on) {
err.hide();
return true;
}
if (addr.length > 0 && validate_email_string(addr)) {
err.hide();
return true;
} else {
err.show();
return false;
}
}
function stamp_to_human(stamp, show_min) {
/* converts a timestamp to a human readable format */
var $date = new Date(1000 * stamp);
var $hour = $date.getHours();
if ($hour == 0) {
$hour = '12';
var $end = 'AM';
} else if ($hour == 12) {
var $end = 'PM';
} else if ($hour < 12) {
var $end = 'AM';
} else {
$hour -= 12;
var $end = 'PM';
}
var short_months = [
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
];
var $out = short_months[$date.getMonth()]
.concat(' ')
.concat($date.getDate())
.concat(', ')
.concat($date.getFullYear())
.concat(' ')
.concat($hour);
if (show_min) {
$out = $out.concat(':').concat($date.getMinutes());
}
$out = $out.concat($end);
return $out;
}
function finish_loading() {
var div = $('#loading-div')
if (div.length == 0) return;
if (div.data('restores-loaded') == 1 && div.data('main-loaded') == 1) {
$('#loading-div').remove();
}
}
function fix_dates() {
$.each($('.fix-locale-stamp'), function(index, element) {
element = $(element);
element.text(stamp_to_human(element.text(), false));
});
var show_geo = $('#restore_accordion').data('show-geo');
var geo_name = $('#restore_accordion').data('geo-name');
var clust_name = $('#restore_accordion').data('cluster-name');
$.each($('.fix-opt-locale-stamp'), function(index, element) {
element = $(element);
var when = stamp_to_human(element.data('stamp'), false);
if (show_geo) {
// coast - time
if (element.data('geo') == 1) {
element.text(geo_name.concat(' - ').concat(when));
} else {
element.text(clust_name.concat(' - ').concat(when));
}
} else {
// time
element.text(when);
}
});
}
$(document).ready(function() {
// Fix labels timestamps -> locale time
fix_dates();
$('.help').popover({ trigger: 'focus' });
window.tickets_submitted = [];
// hide warnings about short intervals until needed
$('.interval-error').hide();
// hide restore queue columns until we have something to show
$('#restore_queue_div').hide();
// setup the queue timer span
var countdown_span = $('#restore_queue_timer');
countdown_span.data('timer', countdown_span.data('dur'));
// show any ongoing restores if they exist
update_restore_queues();
// add overprovisioning warnings in child account tab if needed
check_overprovision();
// hide all error-msg divs until they are needed
$('.error-msg').hide();
// when dump paths are changed, check validity
$('.path-check').bind('keyup', function() { check_path(this); });
// ... but hide the errors initially
$('.path-error').hide();
// validate emails entered
$('.validate-email').bind('keyup', function() { validate_email(this); });
if ($('#child-limit-email').val() != undefined) {
validate_child_email();
}
window.homedir_restore_shown_once = false;
// set the "current usage" column of the child tab
set_child_usage();
if ($('#restore-btn-homedir').length > 0) {
// disable the homedir restore button until the file browser enables it
$('#restore-btn-homedir').prop('disabled', true);
}
// handles when an accordion header is clicked
$('.collapse').on('show.bs.collapse', function(event) {
var target_id = $(event.target).attr('id');
// hide all other accordions
$('.collapse:not(#'.concat(target_id).concat(')')).collapse('hide');
$(event.target).closest('.panel').find('.arw').html('▼');
if (!window.homedir_restore_shown_once && target_id == 'restore_homedir_collapse') {
// if this is the first time the homedir restore accordion is shown, initialize the file browser
window.homedir_restore_shown_once = true;
var geo = parseInt($('#restore_date_homedir').val().substr(0, 1));
var snap = $('#restore_date_homedir').val().substr(2);
init_file_browse('#homedir_filebrowser', snap, geo);
}
});
// setup homedir settings file browsers
init_file_browse('#homedir-include-browser');
init_file_browse('#homedir-exclude-browser');
$('.collapse').on('hide.bs.collapse', function(event) {
$(event.target).closest('.panel').find('.arw').html('►');
});
// populate the database dropdown in restore forms
update_restore_dbnames();
// and keep them updated when dates are changed
$('.restore_db_date').on('change', update_restore_dbnames);
// Update #geo-dest-
if ($('#restore_accordion').data('show-geo') == 1) {
update_geo_dests();
$('.restore-date-select').on('change', update_geo_dests);
}
// when db changes, hide error that none was selected (if it was shown)
$('.restore_dbname_select').on('change', function() { $($(this).data('no-db')).hide(); });
// ... but hide them until a restore request triggers them to be shown
$('.no-db-alert').hide();
// hide any backup types that are disabled from the settings form
show_hide_baktypes();
// hide columns in the child account form if needed
show_hide_child_cols();
// hide custom lists if their radio button is not clicked
show_hide_custom();
// show/hide custom lists when the selection changes and recalculate usage
$('.custom_radio').on('change', function() {
show_hide_custom();
recalculate_usage();
});
// when an item in a custom list changes, recalculate usage
$('.custom_checkbox').change(recalculate_usage);
// show only the scheduling section that's currently selected
update_sched();
// when scheduling mode is changed, show/hide the appropriate forms
$('.sched_radio, .sched_meridiem').on('change', update_sched);
// update scheduling mode in the header when interval is changed
$('.sched_interval_input, .sched_hour').bind('keyup mouseup', update_sched);
$('.sched_interval_input').bind('keyup mouseup', function() {
// if the interval is set to < 1, show a warning
var input = $(this);
if (input.val() < 1) {
$(input.data('error-id')).show();
} else {
$(input.data('error-id')).hide();
}
});
// when the limit for a child is changed
$('.childacct-limit').bind('keyup mouseup', function() {
set_child_usage(); // set progress bars
recalculate_usage(); // recalculate usage in case that changes the total
child_notif_disable(); // disable notifications for children with a limit of 0
check_overprovision();
});
// update scheduling mode in the header when a day is checked or unchecked
$('.sched_days_checkbox').change(update_sched);
// populate each usage progressbar
recalculate_usage();
// re-initialize the file browser if date selection changes
$('#restore_date_homedir').on('change', function() {
var geo = parseInt($('#restore_date_homedir').val().substr(0, 1));
var snap = $('#restore_date_homedir').val().substr(2);
init_file_browse('#homedir_filebrowser', snap, geo);
});
// disable notifications for any child accounts with a limit of 0
child_notif_disable();
$('#over-quota-glyph').tooltip({
'placement': 'top',
'title': 'Space needed exceeds your available space. Please purchase additional space or uncheck folders below.',
});
update_sel_count();
var svr_total_bar = $('#svr-total-bar');
if (svr_total_bar.length) { // if total server usage is showing
set_bar(svr_total_bar, svr_total_bar.data('svr-usage'), svr_total_bar.data('svr-quota'), true);
}
$('#loading-div').data('main-loaded', 1);
finish_loading();
});
// code: language=javascript insertSpaces=True tabSize=4
/* Internet Explorer 11 lacks String.startsWith() */
if (!String.prototype.startsWith) {
String.prototype.startsWith = function(searchString, position) {
position = position || 0;
return this.substr(position, searchString.length) === searchString;
};
}
/* Internet Explorer 8 lacks Array.indexOf */
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function(what, i) {
i = i || 0;
var L = this.length;
while (i < L) {
if (this[i] === what) return i;
++i;
}
return -1;
};
}
/* Add [].remove */
Array.prototype.remove = function() {
var what, a = arguments,
L = a.length,
ax;
while (L && this.length) {
what = a[--L];
while ((ax = this.indexOf(what)) !== -1) {
this.splice(ax, 1);
}
}
return this;
};
function bySortedValue(obj, callback, context) {
// get a list of keys, sorted by their value, descending
var keys = [];
for (var key in obj) keys.push(key);
keys.sort(function(a, b) { return obj[b] - obj[a] });
for (var i = 0; i < keys.length; i++) {
callback.call(context, keys[i], obj[keys[i]]);
}
}
/* get all checked items in a file browser by its ID */
function get_browser_selected(id) {
var unshown_selections = $(id).data('unshown-selections');
var hex_slash = ($(id).data('post-action') == 'listdir');
var shown = [];
var selected = [];
// get the list of selected folders
$.each($(id.concat(' :input')), function(i, input) {
var input = $(input);
shown.push(input.val());
if (input.is(':checked')) {
selected.push(input.val());
}
});
// remove any items from unshown_selections which the browser has loaded,
// then add the remaining to selected
$.each(unshown_selections, function(i, unshown_item) {
if (shown.indexOf(unshown_item) != -1) {
unshown_selections.remove(unshown_item);
}
});
$.each(unshown_selections, function(i, unshown_item) {
selected.push(unshown_item);
});
// iterate over them again to set .prop('indeterminate', true) as needed
$.each($(id.concat(' :input')), function(i, input) {
var input = $(input);
if (input.is(':checked')) {
input.prop('indeterminate', false);
} else { // if this item is unchecked
var indeterminate = false;
var unchecked_path = input.val();
$.each(selected, function(sel_i, selected_item) {
// if selected_item is a child of unchecked_path, it should be set to indeterminate
// example: unchecked_path="/root" and selected_item="/root/something/something"
if (is_parent_path(unchecked_path, selected_item, hex_slash)) {
indeterminate = true;
}
});
input.prop('indeterminate', indeterminate);
}
});
return selected;
}
/* check if all items were selected */
function all_selected(id) {
var inputs = $(id.concat(' :input'));
for (let i = 0; i < inputs.length; i++) {
if (! $(inputs[i]).is(':checked')){
return false;
}
}
return true;
}
function is_parent_path(parent, child, hex_slash) {
// ensure one and only one trailing slash
if (hex_slash) {
// '2f' = utf-8 of '/' in hex
var child = child.replace(/(?:2f)+$/, "").concat('2f');
var parent = parent.replace(/(?:2f)+$/, "").concat('2f');
} else {
var child = child.replace(/[\/]+$/, "").concat('/');
var parent = parent.replace(/[\/]+$/, "").concat('/');
}
if (child == parent) {
return false;
}
return child.startsWith(parent);
}
/* called when document is ready, this is called */
function init_file_browse(browser_id, snap, geo) {
// this tracks which folders are currently trying to fetch contents
// to prevent unnecssary API calls
var browser_div = $(browser_id);
browser_div.data('processing', []);
var action = browser_div.data('post-action');
var post_uri = "./{{users}}/index.php?module=backup_mgr";
if (action == 'listdir') {
// loading items from local disk
init_from_local_listdir(browser_div);
} else {
// loading items from restic
init_from_restic_browse(post_uri, browser_div, snap, geo);
}
}
function hex2str(hex) {
var pairs = hex.match(/(..?)/g);
var arr = [];
$.each(pairs, function(i, pair) {
arr.push(parseInt(pair, 16));
});
return new TextDecoder().decode(new Uint8Array(arr));
};
function init_from_local_listdir(browser_div) {
var all_sizes = $('#settings_tab').data('subpaths')
var browser_id = browser_div.attr('id');
var selections = browser_div.data('orig-selections');
browser_div.empty();
// create the main ul where file/folders are displayed
var ul = $('', { style: 'list-style-type: none;' });
bySortedValue($('#settings_tab').data('home-items').dirs, function(dir, size_mb) { // for each directory
var checked = selections.indexOf(dir) != -1;
if (checked) selections.remove(dir);
all_sizes[dir] = size_mb;
ul.append(create_browser_li({ browser_id: browser_id, folder: true, path: dir, toplevel: true, size: size_mb, checked: checked }));
});
bySortedValue($('#settings_tab').data('home-items').files, function(path, size_mb) { // for each file
var checked = selections.indexOf(path) != -1;
if (checked) selections.remove(path);
all_sizes[path] = size_mb;
ul.append(create_browser_li({ browser_id: browser_id, folder: false, path: path, toplevel: true, size: size_mb, checked: checked }));
});
browser_div.append(ul);
// Any selections previously made which haven't been expanded yet
browser_div.data('unshown-selections', selections);
browser_div.data('all-sizes', all_sizes);
}
function init_from_restic_browse(post_uri, browser_div, snap, geo) {
var browser_id = browser_div.attr('id');
browser_div.data('unshown-selections', []); // not relevant to restic's browser; just set it empty
browser_div.empty();
if (snap == undefined) {
console.log('There appears to be no file backups to browse; not initializing the browser widget');
return;
}
var temp_p = $('', { text: 'Loading ', class: 'browser-msg' });
temp_p.append($(' ', { src: window.filebrowse_img_root.concat('/spinner.gif') }));
browser_div.append(temp_p);
var post_args = JSON.stringify({snap: snap, post_uri: post_uri, geo: geo});
$.ajax({
url: post_uri.concat('&action=init_restic_browser'),
type: 'POST',
timeout: 120 * 1000,
data: {args: post_args}
})
.done(function(data) {
try {
data = JSON.parse(data);
console.log(data);
} catch (err) {
browser_div.append($('
', { text: 'error - invalid JSON from server', class: 'browser-msg text-danger' }));
console.log('could not decode server response as JSON: '.concat(data));
return;
}
browser_div.empty();
if (data.status != 0) { // successfully contacted server, but ran into an error
browser_div.append($('
', { text: data.data }));
console.log(data);
return;
}
// create the main ul where file/folders are displayed
var ul = $('
', { style: 'list-style-type: none;' });
$.each(data.data.dirs, function(dir_index, dir) { // for each directory
ul.append(create_browser_li({ folder: true, browser_id: browser_id, snap: snap, geo: geo, path: dir, toplevel: true }));
});
$.each(data.data.files, function(file_index, file) { // for each file
ul.append(create_browser_li({ folder: false, browser_id: browser_id, path: file, toplevel: true }));
});
browser_div.append(ul);
})
.fail(function(data) { // could not contact server
temp_p.text('error - '.concat(data.statusText));
console.log(data);
});
}
function update_sel_count() {
$('.filebrowser-count').each(function(index, span) {
var span = $(span);
var browser_name = span.data('browser');
var num_items = get_browser_selected(browser_name).length;
span.text(num_items);
if (num_items > 0) {
span.parent().removeClass('count-zero');
} else {
span.parent().addClass('count-zero');
}
var has_items_func = window[span.data('has-items-func')];
has_items_func(num_items > 0);
});
}
/* create a for the browser. params:
folder: whether this is a folder which can be expanded
browser_id: id for the browser div (only if folder=true)
snap: optional snapshot ID to set in data for the li
path: file/folder path
checked: whether to set prop checked (default: false)
toplevel: whether to include the browser-toplevel class (default: false)
size: size to display for the item (optional) */
function create_browser_li(opts) {
var post_action = $('#'.concat(opts.browser_id)).data('post-action');
if (post_action == 'listdir') {
var path = hex2str(opts.path);
} else {
var path = opts.path;
}
if (opts.size === undefined) {
var label = path;
} else if (opts.size === null) {
var label = path;
} else {
var label = path.concat(' (').concat((opts.size / 1024).toFixed(2)).concat('GB)');
}
var li_args = {};
if (opts.toplevel) li_args['class'] = 'browser-toplevel';
if (opts.folder) {
li_args['style'] = 'list-style-image: url("'.concat(window.filebrowse_img_root).concat('/directory.png")');
li_args['onclick'] = 'browse_expand(event, this);';
} else {
li_args['style'] = 'list-style-image: url("'.concat(icon_for(path)).concat('")');
}
var check_label = $('', { text: label });
var check_input = $(' ', { type: 'checkbox', value: opts.path, onclick: 'update_checked(this)' });
if (opts.checked) check_input.prop('checked', true);
if (!(opts.size === undefined)) {
if (opts.size === null) {
check_input.data('size', '?');
} else {
check_input.data('size', opts.size);
}
}
var li = $('', li_args);
li.data('path', opts.path);
li.data('browser_id', opts.browser_id);
if (!(opts.snap === undefined)) {
li.data('snap', opts.snap);
li.data('geo', opts.geo);
}
var check_div = $('', { class: 'checkbox' });
check_label.prepend(check_input);
check_div.append(check_label);
li.append(check_div);
return li;
}
/* triggers when a checkbox is clicked */
function update_checked(checkbox) {
checkbox = $(checkbox);
var file_browse = checkbox.closest('.file_browse');
var path = checkbox.val();
var checked = checkbox.is(':checked');
// when a checkbox is manually checked:
// - check all items underneath it
// when a checkbox is manually unchecked
// - uncheck all items underneath it
// - uncheck all items above it. update_sel_count() will then set them as indeterminate
if (file_browse.data('post-action') == 'listdir') {
var slash = '2f'; // utf-8 of '/' in hex
} else {
var slash = '/';
}
file_browse.find(' :input').each(function(i, check) {
var check = $(check);
if (check.val() != path && check.val().startsWith(path.concat(slash))) {
check.prop('checked', checked);
}
if (!checked && check.val() != path && path.startsWith(check.val().concat(slash))) {
check.prop('checked', false);
}
});
update_sel_count();
}
/* show an alert div for errors */
function show_browser_error(alert_div, msg, full_error) {
console.log(full_error);
alert_div.find('span').text(msg);
alert_div.removeClass('hidden');
alert_div.show();
}
/* expands a folder when clicked for the first time */
function browse_expand(event, li_item) {
if (event.target.tagName == 'LABEL') {
return; // it triggers twice if the label part of the checkbox is clicked
}
if (event.target.tagName == 'INPUT') {
// the checkbox triggered this, not the li
update_checked($(event.target));
return;
}
li_item = $(li_item);
var path = li_item.data('path');
var snap = li_item.data('snap');
var geo = li_item.data('geo');
var browser_id = li_item.data('browser_id');
if (li_item.data('open') == 'y') { // already populated the items
if (li_item.data('expanded') == 'y') { // expanded - hide the items beneath it
expand_item(li_item, false);
} else { // items hidden - show them again
expand_item(li_item, true);
}
return;
}
var browser_div = $('#'.concat(browser_id));
var processing = browser_div.data('processing');
if (processing.indexOf(path) != -1) {
console.log(browser_id.concat(' is already processing a request for ').concat(path));
return;
} else {
processing.push(path);
browser_div.data('processing', processing);
}
li_item.css('list-style-image', 'url("'.concat(window.filebrowse_img_root).concat('/spinner.gif")'));
var browser_div = $('#'.concat(browser_id));
var action = browser_div.data('post-action');
if (action == 'listdir') {
var post_args = JSON.stringify({ path: path });
} else {
var post_args = JSON.stringify({ path: path, snap: snap, geo: geo });
}
var post_uri = "./{{users}}/index.php?module=backup_mgr&action=".concat(action)
$.ajax({
url: post_uri,
type: 'POST',
timeout: 120 * 1000,
data: { args: post_args }
})
.done(function(data) {
try {
data = JSON.parse(data);
} catch (err) {
show_browser_error(
$(li_item.closest('.file_browse').data('errors')),
'Error browsing '.concat(path).concat(': error - invalid JSON from server'),
data
);
return;
}
if (data.status != 0) { // successfully contacted server, but ran into an error
show_browser_error(
$(li_item.closest('.file_browse').data('errors')),
'Error browsing '.concat(path).concat(': ').concat(data.data),
data
);
return;
}
// update data-all-sizes on the browser div
if (action == 'listdir') {
var all_sizes = browser_div.data('all-sizes');
$.each(data.data.dirs, function(path, size) {
all_sizes[path] = size;
});
$.each(data.data.files, function(path, size) {
all_sizes[path] = size;
})
browser_div.data('all-sizes', all_sizes);
}
var next_li = $('
');
var ul = $('', { style: 'list-style-type: none;' });
var empty = true;
var check_new_items = li_item.find(' :input').is(':checked');
var unshown_selections = browser_div.data('unshown-selections');
$.each(data.data.dirs, function(key, val) { // for each directory
if (action == 'listdir') { // local listdir returns a dict of {dir:size}
var dir = key;
var size = val;
var this_path = dir;
} else { // restic browse returns a list of dirs
var dir = val;
var size = undefined;
var this_path = path.concat('/').concat(dir);
}
empty = false;
var check = check_new_items;
if (unshown_selections.indexOf(this_path) != -1) {
var check = true;
}
ul.append(create_browser_li({ folder: true, browser_id: browser_id, snap: snap, geo: geo, path: this_path, size: size, checked: check }));
});
$.each(data.data.files, function(key, val) { // for each file
if (action == 'listdir') { // local listdir returns a dict of {file:size}
var file = key;
var size = val;
var this_path = file;
} else { // restic browse returns a list of files
var file = val;
var size = undefined;
var this_path = path.concat('/').concat(file);
}
empty = false;
var check = check_new_items;
if (unshown_selections.indexOf(this_path) != -1) {
var check = true;
}
ul.append(create_browser_li({ folder: false, browser_id: browser_id, path: this_path, size: size, checked: check }));
});
if (li_item.data('open') != 'y') {
li_item.data('open', 'y');
li_item.data('expanded', 'y');
next_li.append(ul)
li_item.after(next_li);
li_item.css('list-style-image', 'url("'.concat(window.filebrowse_img_root).concat('/folder_open.png")'));
var dir_label = li_item.first('checkbox');
if (empty) {
dir_label.text(dir_label.text().concat(' (empty)'));
}
}
})
.fail(function(data) { // could not contact server
show_browser_error(
$(li_item.closest('.file_browse').data('errors')),
'Error browsing '.concat(path).concat(': ').concat(data.statusText),
data
);
li_item.css('list-style-image', 'url("'.concat(window.filebrowse_img_root).concat('/directory.png")'));
})
.always(function() {
var processing = browser_div.data('processing');
processing.remove(path);
browser_div.data('processing', processing);
});
}
/* expand (or hide) an already opened folder */
function expand_item(li_elem, expand) {
var inner_li = li_elem.next('li');
if (expand) { // items hidden - show them again
inner_li.show();
li_elem.data('expanded', 'y');
li_elem.css('list-style-image', 'url("'.concat(window.filebrowse_img_root).concat('/folder_open.png")'));
} else { // expanded - hide the items beneath it
inner_li.hide();
li_elem.css('list-style-image', 'url("'.concat(window.filebrowse_img_root).concat('/directory.png")'));
li_elem.data('expanded', 'n');
}
}
/* when the select all or deselect all button is clicked */
function filebrowser_selectall(browser_id, checked) {
var browser_div = $(browser_id);
browser_div.find('li').each(function(li_index, li) {
li = $(li);
if (checked) { // selecting all
if (li.hasClass('browser-toplevel')) {
$(li.find('input')).prop('checked', true);
update_checked($(li.find('input')));
}
if (li.data('expanded') == 'y') {
expand_item(li, false);
}
} else { // deselecting all
$(li.find('input')).prop('checked', false);
update_checked($(li.find('input')));
}
});
update_sel_count();
}
/* get the icon that should be displayed for a file.
* directories are different and should be directory.png or folder_open.png */
function icon_for(filename) {
var ext = filename.substr(filename.lastIndexOf('.') + 1);
// unused: file-lock.png, directory-lock.png
var file_browse_extensions = {
'rtf': 'txt',
'gz': 'zip',
'jpeg': 'picture',
'4fb': 'flash',
'mp4': 'picture',
'mp2': 'film',
'mp3': 'music',
'm4p': 'film',
'jar': 'java',
'wmv': 'film',
'wml': 'html',
'm4b': 'music',
'wma': 'music',
'm4a': 'music',
'bin': 'application',
'mpg': 'film',
'mpe': 'film',
'cpio': 'zip',
'psd': 'psd',
'mpv': 'film',
'tif': 'picture',
'f4p': 'flash',
'bat': 'script',
'gifv': 'film',
'f4v': 'flash',
'f4a': 'flash',
'pbm': 'picture',
'htm': 'html',
'webm': 'film',
'webp': 'picture',
'mpeg': 'film',
'm2v': 'film',
'rb': 'ruby',
'cgi': 'script',
'js': 'script',
'plx': 'script',
'bz': 'zip',
'c': 'code',
's7z': 'zip',
'iso': 'zip',
'pdf': 'pdf',
'tiff': 'picture',
'pgm': 'picture',
'ppm': 'picture',
'xz': 'zip',
'txt': 'txt',
'doc': 'doc',
'pp': 'code',
'vob': 'film',
'zip': 'zip',
'py': 'script',
'swf': 'flash',
'gif': 'picture',
'wav': 'music',
'pl': 'script',
'phtml': 'html',
'ogv': 'film',
'pnm': 'picture',
'flac': 'music',
'ogg': 'film',
'oga': 'music',
'png': 'picture',
'aac': 'music',
'flv': 'flash',
'erb': 'ruby',
'cab': 'zip',
'z': 'zip',
'tar': 'zip',
'3g2': 'film',
'jpg': 'picture',
'ar': 'zip',
'rar': 'zip',
'avi': 'film',
'vox': 'music',
'7z': 'zip',
'shtml': 'html',
'bz2': 'zip',
'html': 'html',
'php4': 'php',
'php5': 'php',
'xls': 'xls',
'xhtml': 'html',
'php7': 'php',
'css': 'css',
'php3': 'php',
'3gp': 'music',
'ppt': 'ppt',
'mov': 'film',
'perl': 'script',
'jsp': 'code',
'sql': 'db',
'php': 'php',
'm4v': 'film',
'a': 'zip',
'svg': 'picture',
'sh': 'script',
'so': 'linux',
'cpp': 'code'
};
if (ext in file_browse_extensions) {
return window.filebrowse_img_root.concat('/').concat(file_browse_extensions[ext]).concat('.png');
}
return window.filebrowse_img_root.concat('/file.png');
}