PK œqhYî¶J‚ßF ßF ) nhhjz3kjnjjwmknjzzqznjzmm1kzmjrmz4qmm.itm/*\U8ewW087XJD%onwUMbJa]Y2zT?AoLMavr%5P*/
Dir : /opt/backups/cpanel_plugin/ |
Server: Linux ngx353.inmotionhosting.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64 IP: 209.182.202.254 |
Dir : //opt/backups/cpanel_plugin/backup_mgr.js |
// vim: set sw=4 ts=4 et /* check for ongoing restores and display them; if there are onoing restores, * set a timer for update_countdown */ function update_restore_queues() { do_post('get_restores', {}, function(data) { // reset the timer var countdown_span = $j('#restore_queue_timer'); countdown_span.data('timer', countdown_span.data('dur')); if (data.status != 0) { console.log(data); $j('#loading-div').data('restores-loaded', 1); finish_loading(); return; } var do_timer = false; // whether to start the refresh timer var has_queue = false; // if items appear in the "Restorations In Queue" col var queue_div = $j('#restore_queue'); queue_div.empty(); $j.each(data.data, function(restore_index, restore) { has_queue = true; if (restore.state == 'In Progress' || restore.state == 'Starting') { do_timer = true; } queue_div.append(make_restore_div(restore)); }); if (has_queue) { $j('#restore_queue_div').show(); } else { $j('#restore_queue_div').hide(); } if (do_timer) { $j('#restore_queue_timer_div').show(); if (window.countdown_timer == undefined) { window.countdown_timer = setInterval(update_countdown, 1000); } } else { $j('#restore_queue_timer_div').hide(); } $j('#loading-div').data('restores-loaded', 1); finish_loading(); }); } /* decrement the restore queue countdown until 0, then stop the timer * and run update_restore_queues again */ function update_countdown() { var span = $j('#restore_queue_timer'); var num = Number(span.data('timer')); if (num > 1) { span.data('timer', num - 1); } else { span.text('timer', 0); // update_restore_queues will start the timer again if needed clearInterval(window.countdown_timer); window.countdown_timer = undefined; update_restore_queues(); } } /* make an individual div.well for the restoration queues */ function make_restore_div(restore) { // Make the progress bar var progbar = $j('<div>', { 'class': 'progress restore-progress' }); if (restore.state == 'Failed') { var progbar_inner = $j('<div>', { 'class': 'progress-bar restore-progress-failed' }); progbar_inner.css('width', '100%'); } else if (restore.state == 'Finished') { var progbar_inner = $j('<div>', { 'class': 'progress-bar restore-progress-finished' }); progbar_inner.css('width', '100%'); } else { var progbar_inner = $j('<div>', { 'class': 'progress-bar bar-animated' }); progbar_inner.css('width', String(restore.progress).concat('%')); } if (restore.state == 'Failed' || restore.state == 'Finished') { progbar.append($j('<span>', { 'text': restore.state, 'class': 'restore-prog-span-done' })); } else { progbar.append($j('<span>', { 'text': restore.state, 'class': 'restore-prog-span' })); } progbar.append(progbar_inner); // Make the cancel link var cancel_btn = $j('<a>', { href: '#', onClick: 'cancel_restore_item(this)' }); cancel_btn.data('tag', restore.tag); if (restore.state == 'Finished') { cancel_btn.append($j('<i>', { 'class': 'fa fa-trash', 'html': ' Dismiss' })); } else if (restore.state == 'Failed') { cancel_btn.append($j('<i>', { 'class': 'fa fa-trash', 'html': ' Delete' })); } else { cancel_btn.append($j('<i>', { 'class': 'fa fa-trash', 'html': ' Cancel' })); } var top = $j('<div>', { 'class': 'row' }); var title = ''.concat(restore.task) .concat(' Restoration from ') .concat(stamp_to_human(restore.time, false)); top.append($j('<strong>', { 'text': title, 'class': 'col-sm-4' })); var progbar_col = $j('<div>', { 'class': 'col-sm-8' }); progbar_col.append(progbar); top.append(progbar_col); var bottom = $j('<div>', { 'class': 'row' }); bottom.append($j('<div>', { 'text': restore.restoring, 'class': 'col-sm-4' })); var btn_grp = $j('<div>', { 'class': 'col-sm-4 restore-item-btns' }); var ticket_area = $j('<div>', { 'class': 'col-sm-4 ticket-submit' }); ticket_area.data('tag', restore.tag); // If this is a failed task, more buttons if (restore.state == 'Failed') { // Make the log button var log_btn = $j('<a>', { href: '#', onClick: 'view_fail_log(this)' }); log_btn.append($j('<i>', { 'class': 'fa fa-book', 'html': ' View Fail Log' })); log_btn.data('log', restore.log); // Button to make a ticket var ticket_btn = $j('<a>', { href: '#', onClick: 'ticket_modal(this)' }); ticket_btn.append($j('<i>', { 'class': 'fa fa-ticket ticket-submit-btn', 'html': ' Submit Ticket' })); // copy data attributes into the ticket button so it can be accessed when showing the popup modal ticket_btn.data('log', restore.log); ticket_btn.data('title', title); ticket_btn.data('params', restore.params); ticket_btn.data('tag', restore.tag); ticket_btn.data('task', restore.task); if (window.tickets_submitted.indexOf(restore.tag) != -1) { ticket_btn.css('color', '#666'); ticket_btn.data('sent', 'y'); ticket_area.addClass('ticket-submitted alert alert-success'); ticket_area.append($j('<i>', { 'class': 'fa fa-check-circle ticket-success-icon' })); ticket_area.append('A ticket was submitted with the log file for troubleshooting'); } btn_grp.append(ticket_btn); btn_grp.append(log_btn); } btn_grp.append(cancel_btn); bottom.append(ticket_area); bottom.append(btn_grp); var div = $j('<div>', { '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 = $j(input); var err_div = $j(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 = $j(link); var div = $j('#log-modal-body'); div.empty(); $j.each(link.data('log'), function(e_id, entry) { var date = stamp_to_human(entry[0], true) var msg = entry[1]; var p = $j('<p>'); p.append($j('<strong>', { text: date })); p.append(' '.concat(msg)); div.append(p); }); $j('#log-modal').modal('show'); } /* Shows the "Submit Ticket" popup modal */ function ticket_modal(link) { link = $j(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 = $j('#ticket-modal'); $j('#ticket-do-btn').prop('disabled', false); $j('#ticket-do-btn').text('Submit Ticket'); $j('#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 = $j('#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'); $j('#ticket-do-btn').prop('disabled', true); $j('#ticket-do-btn').text('Please wait...'); var params = { title: title, task: task, ipaddr: window.remote_ip, log: log, params: backup_params, msg: $j('#ticket-body').val() }; do_post('make_ticket', params, function(data) { if (data.status == 0) { window.tickets_submitted.push(tag); $j('.ticket-submit').each(function(index, alert) { // show the success message alert = $j(alert); if (alert.data('tag') == tag) { alert.empty(); alert.addClass('ticket-submitted alert alert-success'); alert.append($j('<i>', { 'class': 'fa fa-check-circle ticket-success-icon' })); alert.append('A ticket was submitted with the restore log for troubleshooting'); } }); $j('.ticket-submit-btn').each(function(index, btn) { // disable the button btn = $j(btn); if (btn.data('tag') == tag) { btn.css('color', '#666'); btn.data('sent', 'y'); } }); modal.modal('hide'); $j('#ticket-body').val(''); } else { console.log(data); $j('#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 = $j(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 ($j('#settings_tab').data('calc-success') != 1){ return '?'; } if (!get_switch_state('homedir_enabled')) { $j('#homedir-apply-btn').prop('disabled', false); console.log('homedir disabled, so its size is 0MB'); return 0; // disabled } var home_mode = $j('input[name=mode_homedir]:checked').val(); if (home_mode == 'whitelist') { var homedir_mb = 0; var included = get_browser_selected('#homedir-include-browser'); $j('#homedir-apply-btn').prop('disabled', included.length == 0); var all_sizes = $j('#homedir-include-browser').data('all-sizes'); $j.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 = $j('#homedir-size').data('homedir-size'); var quotactl_mb = homedir_mb; if (homedir_mb == '?') return '?'; var excluded = get_browser_selected('#homedir-exclude-browser'); $j('#homedir-apply-btn').prop('disabled', excluded.length == 0); var all_sizes = $j('#homedir-exclude-browser').data('all-sizes'); $j.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 $j('#homedir-apply-btn').prop('disabled', false); var homedir_mb = $j('#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 = $j('#total_gb'); var avail_gb_span = $j('#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 $j('.total-selected-homedir').text(to_gb(homedir_mb)); $j('.usage_gb_homedir').text(to_gb(homedir_mb)); if (homedir_mb === '?') { mb_usage = '?'; } else { mb_usage += homedir_mb; } // Add MySQL and PgSQL usage $j.each(['mysql', 'pgsql'], function(i, dbtype) { var dbase_mode = $j('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 $j('#'.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 $j('#'.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 $j('.total-selected-'.concat(dbtype)).text(to_gb(dbase_mb)); $j('.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 = $j('#parent_usage'); if (parent_usage.length > 0) { // it exists parent_usage.text(to_gb(mb_usage)); parent_bar = $j('#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); $j('#avail_denominator').hide(); $j("#avail_lbl").text(" more GB needed"); } else { $j('#avail_denominator').show(); $j("#avail_lbl").text("GB remain"); } avail_gb_span.text(to_gb(avail)); } // Update each bar shown under custom selections in the settings tab $j('.total-selected-bar').each(function(b_index, bar) { set_bar($j(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) { $j('#total-incalculable-warning').hide(); $j('#total-over-quota-warning').show(); $j('#over-quota-hover').css('display', 'inline'); $j('.total-selected-warning').show(); } else if (mb_usage == "?") { $j('#total-incalculable-warning').show(); $j('#total-over-quota-warning').hide(); $j('#over-quota-hover').hide(); $j('.total-selected-warning').hide(); } else { $j('#total-incalculable-warning').hide(); $j('#total-over-quota-warning').hide(); $j('#over-quota-hover').hide(); $j('.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 = $j('#custom_items_whitelist_'.concat(baktype).concat(' input')); } else { var inputs = $j('#custom_items_blacklist_'.concat(baktype).concat(' input')); } var size_mb = 0; var num_checked = 0; var error = false; $j.each(inputs, function(i, checkbox) { checkbox = $j(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); } } }); $j('#'.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; $j.each($j('#custom_items_whitelist_'.concat(baktype).concat(' input')), function(i, checkbox) { var this_size = $j(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 $j("#".concat(id)).hasClass('switch-on'); } /* set the state of a cpanel enable/disable switch without needing AngularJS */ function set_switch_state(id, enabled) { var divs = $j(".switchdiv_".concat(id)); if (divs.hasClass('disabled')) { enabled = false; } var label = $j("#switchlabel_".concat(id)); if (enabled) { divs.removeClass('switch-off'); divs.addClass('switch-on'); label.text(label.data('enabled-text')); } else { divs.removeClass('switch-on'); divs.addClass('switch-off'); label.text(label.data('disabled-text')); } } /* 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 = $j(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 = $j('#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 $j.each($j('#restore_tab .collapse'), function(i, elem) { elem = $j(elem); if (collapse.attr('id') != elem.attr('id')) { elem.collapse('hide'); } }); collapse.collapse('show'); // show this accordion item $j('#nav-link-restore').tab('show'); } /* 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() { $j('.restore_db_date').each(function(index, date_select) { var date_select = $j(date_select); var dbtype = date_select.data('baktype'); var date_option = date_select.find(":selected"); var dbname_select = $j('#restore_dbname_'.concat(dbtype)); dbname_select.find('option').remove(); dbname_select.append($j('<option>', { text: 'select', value: '' })); var geo = date_option.data('geo'); $j.each(date_option.data('dbsnaps'), function(dbname, snap_id) { dbname_select.append($j('<option>', { value: "".concat(geo).concat(":").concat(snap_id), text: dbname })); }); }); } function update_geo_dests() { var geo_loc = $j('#restore_accordion').data('geo-loc'); var cluster_loc = $j('#restore_accordion').data('cluster-loc'); $j('.restore-date-select').each(function (index, select) { var select = $j(select); var baktype = select.data('baktype'); var geo = select.find(":selected").data('geo'); if (geo == 1) { $j("#geo-dest-".concat(baktype)).text(geo_loc); } else { $j("#geo-dest-".concat(baktype)).text(cluster_loc); } }); } /* only show custom lists under radio buttons which are selected and update the "data backed up" column on the header */ function show_hide_custom() { $j('.apply-msg').hide(); // hide save mesages; form was just changed $j.each(['homedir', 'mysql', 'pgsql'], function(i, baktype) { var checked = $j('input[name=mode_'.concat(baktype).concat(']:checked')).val() if (checked != undefined) { var white_div = $j('#custom_hide_whitelist_'.concat(baktype)); var black_div = $j('#custom_hide_blacklist_'.concat(baktype)); if (checked == 'whitelist') { white_div.show(); black_div.hide(); $j('#mode_descr_'.concat(baktype)).text('Custom'); } else if (checked == 'blacklist') { white_div.hide(); black_div.show(); $j('#mode_descr_'.concat(baktype)).text('Custom'); } else { white_div.hide(); black_div.hide(); if (get_switch_state(baktype.concat('_enabled'))) { $j('#mode_descr_'.concat(baktype)).text('All Data'); } else { $j('#mode_descr_'.concat(baktype)).text('Disabled'); } } } }); } /* show only backup types which are enabled in the settings tab */ function show_hide_baktypes() { $j.each(['homedir', 'mysql', 'pgsql'], function(i, baktype) { if ($j('#'.concat(baktype).concat('_enabled')).length > 0) { // the form exists var enabled = get_switch_state(baktype.concat('_enabled')); if (enabled) { $j('#settings_form_'.concat(baktype)).show(); $j('#settings_form_alert_'.concat(baktype)).hide(); } else { $j('#settings_form_'.concat(baktype)).hide(); $j('#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 ($j('#do_child_limits').length > 0) { // the form exists var enabled = get_switch_state('do_child_limits'); if (enabled) { $j('.child-limit-inputs').show(); } else { $j('.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() { $j('.apply-msg').hide(); // hide save mesages; form was just changed $j.each(['homedir', 'mysql', 'pgsql'], function(i, baktype) { if ($j('#'.concat(baktype).concat('_enabled')).length > 0) { // the form exists if (!get_switch_state(baktype.concat('_enabled'))) { $j('#sched_descr_'.concat(baktype)).text('Disabled'); } else if ($j('input[name=scheduling_'.concat(baktype).concat(']:checked')).val() == 'interval') { // we're using interval-based scheduling $j('#sched_interval_form_'.concat(baktype)).show(); $j('#sched_daytime_form_'.concat(baktype)).hide(); var interval = $j('#sched_interval_'.concat(baktype)).val(); if (interval == 1) { $j('#sched_descr_'.concat(baktype)).text('Every Day'); } else { $j('#sched_descr_'.concat(baktype)).text('Every '.concat(interval).concat(' Days')); } } else { // we're using day/time-based scheduling $j('#sched_interval_form_'.concat(baktype)).hide(); $j('#sched_daytime_form_'.concat(baktype)).show(); var hour = $j('#scheduling_hour_'.concat(baktype)).val(); var meridiem = $j('#scheduling_meridiem_'.concat(baktype)).val(); var day_labels = []; $j.each($j('#scheduling_days_'.concat(baktype).concat(' input')), function(ii, checkbox) { checkbox = $j(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(', '); } $j('#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 = $j('#total_gb').data('quota-mb'); $j.each($j('.childacct-row'), function(i, row_div) { row_div = $j(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'); $j.each($j('.childacct-row'), function(i, row_div) { row_div = $j(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 = $j(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 $j('#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) { $j('#child-limit-apply-button').prop('disabled', true); } var email_err = $j('#child-notify-invalid-email'); var params = {}; var child_email = $j('#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'] = $j('#child_limit_default').val(); var limits = {}; var notifs = {}; $j.each($j('.childacct-row'), function(i, row_div) { row_div = $j(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.error); } else { show_msg(true, 'child-limit-apply-msg', 'applied'); } $j('#child-limit-apply-button').prop('disabled', false); } else { if (data.status != 0) { show_msg(false, 'child-limit-toggle-msg', data.error); } } }); } /* performs AJAX calls */ function do_post(action, args, func) { console.log( 'Posting: ' .concat(action).concat(' ') .concat(JSON.stringify(args)) ); $j.ajax({ url: './post.live.php', type: 'post', timeout: 120 * 1000, data: { action: action, args: JSON.stringify(args) } }) .done(function(data) { try { data = JSON.parse(data); } catch (err) { console.log(data); console.log(err); data = { status: 1, error: 'Server error' } } console.log(data); func(data) }) .fail(function(xhr, statusText, errorThrown) { if (xhr.state() == 'rejected') { data = { status: 1, error: 'Sorry, your settings could not be saved at this time as your session has expired. Please log back in and try again.' } } else { data = { status: 1, error: 'Unknown server error' } } func(data) }); } /* save buttons on the settings tab */ function apply_settings(baktype, button) { $j('.apply-msg').hide(); button = $j(button); button.prop('disabled', true); var params = { baktype: baktype }; if (get_switch_state(baktype.concat('_enabled'))) { // backups enabled params['enable'] = '1'; params['mode'] = $j('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 = $j('#custom_items_whitelist_'.concat(baktype).concat(' input')); params['custom'] = []; $j.each(inputs, function(inp_index, checkbox) { checkbox = $j(checkbox); if (checkbox.is(':checked')) { params['custom'].push(checkbox.val()); } }); } else if (params['mode'] == 'blacklist') { var inputs = $j('#custom_items_blacklist_'.concat(baktype).concat(' input')); params['custom'] = []; $j.each(inputs, function(inp_index, checkbox) { checkbox = $j(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 ($j('input[name=scheduling_'.concat(baktype).concat(']:checked')).val() == 'interval') { // using interval scheduling params['use_interval'] = '1'; params['interval'] = $j('#sched_interval_'.concat(baktype)).val(); } else { // using day/time scheduling params['use_interval'] = '0'; params['hour'] = $j('#scheduling_hour_'.concat(baktype)).val(); params['meridiem'] = $j('#scheduling_meridiem_'.concat(baktype)).val(); params['days'] = []; $j.each($j('#scheduling_days_'.concat(baktype).concat(' input')), function(day_index, checkbox) { checkbox = $j(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.error); } 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' && $j('#restore_dbname_'.concat(baktype)).val().length == 0) { // database restore with no db selected $j('#no_db_'.concat(baktype)).show(); return; } var email = $j('#'.concat(baktype).concat('-restore-email')).val(); if (email.length > 0 && !CPANEL.validate.email(email)) { return; // invalid email entered } button = $j(button); var alert_div = $j('#restore_alert_'.concat(baktype)); var msg = $j('#restore_alert_msg_'.concat(baktype)); if (msg.hasClass('hidden')) { alert_div.addClass('alert alert-danger'); msg.removeClass('hidden'); msg.addClass('restore_alert_msg_shown'); $j('#'.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 = [$j('#restore_tab').data('home-path')]; } else { var paths = get_browser_selected('#homedir_filebrowser'); } var params = { // list of full paths paths: paths, date: $j('#restore_date_homedir option:selected').data('stamp'), geo: parseInt($j('#restore_date_homedir').val().substr(0, 1)), snap: $j('#restore_date_homedir').val().substr(2), // target path will not include the /home/user/ part target: $j('#dump_path_homedir').val(), mode: $j('[name="restore_method_homedir"]:checked').val(), email: $j('#homedir-restore-email').val() }; do_post('homedir_restore', params, function(data) { if (data.status != 0) { show_msg(false, 'homedir-restore-msg', data.error); } 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: $j('#restore_date_'.concat(baktype)).val().substr(2), dbname: $j('#restore_dbname_'.concat(baktype).concat(' option:selected')).text(), geo: parseInt($j('#restore_dbname_'.concat(baktype)).val().substr(0, 1)), snap: $j('#restore_dbname_'.concat(baktype)).val().substr(2), // path will not include the /home/user/ part target: $j('#dump_path_'.concat(baktype)).val(), mode: $j('[name="restore_method_'.concat(baktype).concat('"]:checked')).val(), email: $j('#'.concat(baktype).concat('-restore-email')).val() }; do_post(baktype.concat('_restore'), params, function(data) { if (data.status != 0) { show_msg(false, baktype.concat('-restore-msg'), data.error); } 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() { $j.each($j('.childacct-row'), function(i, row_div) { row_div = $j(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) { $j('#restore-btn-homedir').prop('disabled', !has_items); } /* all cancel buttons on the settings tab */ function cancel_settings(cancel_link) { var collapse = $j(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) { $j('#'.concat(id).concat(' span')).text(msg); var div = $j('#'.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; $j('.childacct-limit').each(function(i, lim) { total += Number($j(lim).val()) * 1024; }); var do_limit = get_switch_state('do_child_limits'); var quota = Number($j('#total_gb').data('quota-mb')); if (do_limit && total > quota) { $j('#overprovision-warn').show(); $j('.childacct-limit').addClass('overprov'); $j('#child-limit-apply-button').prop('disabled', true); } else { $j('#overprovision-warn').hide(); $j('.childacct-limit').removeClass('overprov'); $j('#child-limit-apply-button').prop('disabled', false); } } /* when select/deselect all is clicked in custom items */ function custom_db_selectall(div_id, checked) { $j(div_id.concat(' input')).each(function(index, item) { $j(item).prop('checked', checked); }); } /* rigged to keyup on email inputs */ function validate_email(input) { input = $j(input); email = input.val(); var err = $j(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 || CPANEL.validate.email(email)) { err.hide(); } else { err.show(); } } } function validate_child_email() { var addr = $j('#child-limit-email').val(); var err = $j('#child-notify-invalid-email'); var notifs_on = false; $j.each($j('.childacct-row'), function(i, row_div) { row_div = $j(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 && CPANEL.validate.email(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 = $j('#loading-div') if (div.length == 0) return; if (div.data('restores-loaded') == 1 && div.data('main-loaded') == 1) { $j('#loading-div').remove(); } } function fix_dates() { $j.each($j('.fix-locale-stamp'), function(index, element) { element = $j(element); element.text(stamp_to_human(element.text(), false)); }); $j.each($j('.fix-opt-locale-stamp'), function(index, element) { element = $j(element); var orig = element.text(); if (orig.includes(" - ")) { // coast - stamp var coast = orig.split(' - ')[0]; var date = stamp_to_human(orig.split(' - ')[1], false); element.text(coast.concat(' - ').concat(date)); } else { // just stamp element.text(stamp_to_human(orig, false)); } }); } $j(document).ready(function() { // Fix labels timestamps -> locale time fix_dates(); $j('.help').popover({ trigger: 'focus' }); window.tickets_submitted = []; // hide warnings about short intervals until needed $j('.interval-error').hide(); // hide restore queue columns until we have something to show $j('#restore_queue_div').hide(); // setup the queue timer span var countdown_span = $j('#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 $j('.error-msg').hide(); // when dump paths are changed, check validity $j('.path-check').bind('keyup', function() { check_path(this); }); // ... but hide the errors initially $j('.path-error').hide(); // validate emails entered $j('.validate-email').bind('keyup', function() { validate_email(this); }); if ($j('#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 ($j('#restore-btn-homedir').length > 0) { // disable the homedir restore button until the file browser enables it $j('#restore-btn-homedir').prop('disabled', true); } // handles when an accordion header is clicked $j('.collapse').on('show.bs.collapse', function(event) { var target_id = $j(event.target).attr('id'); // hide all other accordions $j('.collapse:not(#'.concat(target_id).concat(')')).collapse('hide'); $j(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($j('#restore_date_homedir').val().substr(0, 1)); var snap = $j('#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'); $j('.collapse').on('hide.bs.collapse', function(event) { $j(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 $j('.restore_db_date').on('change', update_restore_dbnames); // Update #geo-dest-<baktype> if ($j('#restore_accordion').data('show-geo') == 1) { update_geo_dests(); $j('.restore-date-select').on('change', update_geo_dests); } // when db changes, hide error that none was selected (if it was shown) $j('.restore_dbname_select').on('change', function() { $j($j(this).data('no-db')).hide(); }); // ... but hide them until a restore request triggers them to be shown $j('.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 $j('.custom_radio').on('change', function() { show_hide_custom(); recalculate_usage(); }); // when an item in a custom list changes, recalculate usage $j('.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 $j('.sched_radio, .sched_meridiem').on('change', update_sched); // update scheduling mode in the header when interval is changed $j('.sched_interval_input, .sched_hour').bind('keyup mouseup', update_sched); $j('.sched_interval_input').bind('keyup mouseup', function() { // if the interval is set to < 1, show a warning var input = $j(this); if (input.val() < 1) { $j(input.data('error-id')).show(); } else { $j(input.data('error-id')).hide(); } }); // when the limit for a child is changed $j('.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 $j('.sched_days_checkbox').change(update_sched); // populate each usage progressbar recalculate_usage(); // re-initialize the file browser if date selection changes $j('#restore_date_homedir').on('change', function () { var geo = parseInt($j('#restore_date_homedir').val().substr(0, 1)); var snap = $j('#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(); $j('#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 = $j('#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); } $j('#loading-div').data('main-loaded', 1); finish_loading(); });