/** * @package akeebabackup * @copyright Copyright (c)2006-2022 Nicholas K. Dionysopoulos / Akeeba Ltd * @license GNU General Public License version 3, or later */ "use strict"; if (typeof (akeebabackup) == "undefined") { var akeebabackup = {}; } if (typeof akeebabackup.Backup == "undefined") { akeebabackup.Backup = { tag: "", backupid: null, currentDomain: null, returnUrl: "", timeoutTimer: null, resumeTimer: null, resume: { retry: 0, showWarnings: 0 } }; } /** * Start the timer which launches the next backup step. This allows us to prevent deep nesting of AJAX calls which could * lead to performance issues on long backups. * * @param waitTime How much time to wait before starting a backup step, in msec (default: 10) */ akeebabackup.Backup.timer = function (waitTime) { if (waitTime <= 0) { waitTime = 10; } setTimeout(akeebabackup.Backup.timerTick, waitTime); }; /** * This is used by the timer() method to run the next backup step */ akeebabackup.Backup.timerTick = function () { try { console.log("Timer tick"); } catch (e) { } // Reset the timer akeebabackup.Backup.resetTimeoutBar(); var maxExecutionTime = Joomla.getOptions("akeebabackup.Backup.maxExecutionTime", 14); var runtimeBias = Joomla.getOptions("akeebabackup.Backup.runtimeBias", 75); akeebabackup.Backup.startTimeoutBar(maxExecutionTime, runtimeBias); // Run the step akeebabackup.System.doAjax({ ajax: "step", tag: akeebabackup.Backup.tag, backupid: akeebabackup.Backup.backupid }, akeebabackup.Backup.onStep, akeebabackup.Backup.onError, false); }; /** * Starts the timer for the last response timer * * @param max_allowance Maximum time allowance in seconds * @param bias Runtime bias in % */ akeebabackup.Backup.startTimeoutBar = function (max_allowance, bias) { var lastResponseSeconds = 0; akeebabackup.Backup.timeoutTimer = setInterval(function () { lastResponseSeconds++; var responseTimer = document.querySelector("#response-timer div.text"); if (responseTimer) { responseTimer.textContent = Joomla.Text._( "COM_AKEEBABACKUP_BACKUP_TEXT_LASTRESPONSE").replace( "%s", lastResponseSeconds.toFixed(0) ); } }, 1000); }; /** * Resets the last response timer bar */ akeebabackup.Backup.resetTimeoutBar = function () { try { clearInterval(akeebabackup.Backup.timeoutTimer); } catch (e) { } var responseTimer = document.querySelector("#response-timer div.text"); if (responseTimer) { responseTimer.textContent = Joomla.Text._("COM_AKEEBABACKUP_BACKUP_TEXT_LASTRESPONSE").replace("%s", "0"); } }; /** * Starts the timer for the last response timer */ akeebabackup.Backup.startRetryTimeoutBar = function () { var remainingSeconds = Joomla.getOptions("akeebabackup.Backup.resume.timeout", 10); akeebabackup.Backup.resumeTimer = setInterval(function () { remainingSeconds--; document.getElementById( "akeebabackup-retry-timeout").textContent = remainingSeconds.toFixed(0); if (remainingSeconds === 0) { clearInterval(akeebabackup.Backup.resumeTimer); akeebabackup.Backup.resumeBackup(); } }, 1000); }; /** * Resets the last response timer bar */ akeebabackup.Backup.resetRetryTimeoutBar = function () { clearInterval(akeebabackup.Backup.resumeTimer); var timeout = Joomla.getOptions("akeebabackup.Backup.resume.timeout", 10); document.getElementById("akeebabackup-retry-timeout").textContent = timeout.toFixed(0); }; /** * Renders the list of the backup steps * * @param active_step Which is the active step? */ akeebabackup.Backup.renderBackupSteps = function (active_step) { var normal_class = "bg-success text-white"; if (active_step == "") { normal_class = "bg-light"; } document.getElementById("backup-steps").innerHTML = ""; var backupDomains = Joomla.getOptions("akeebabackup.Backup.domains", {}); for (var counter = 0; counter < backupDomains.length; counter++) { var element = backupDomains[counter]; var step = document.createElement("div"); step.className = "mt-1 mb-1 p-1 border rounded"; step.innerHTML = element[1]; document.getElementById("backup-steps").appendChild(step); if (element[0] == active_step) { normal_class = "bg-light"; this_class = "bg-primary text-white"; } else { var this_class = normal_class; } step.className += " " + this_class; } }; /** * Start the backup */ akeebabackup.Backup.start = function () { try { console.log("Starting backup"); console.log(data); } catch (e) { } // Check for AVG Link Scanner if (window.AVGRUN) { try { console.warn("AVG Antivirus with Link Checker detected. The backup WILL fail!"); } catch (e) { } var r = confirm(Joomla.Text._("COM_AKEEBABACKUP_BACKUP_TEXT_AVGWARNING")); if (!r) { return false; } } // Hide the backup setup document.getElementById("backup-setup").style.display = "none"; // Show the backup progress document.getElementById("backup-progress-pane").style.display = "block"; // Let's check if we have a password even if we didn't set it in the profile (maybe a password manager filled it?) var hasAngieKey = Joomla.getOptions("akeebabackup.Backup.hasAngieKey", false); if (hasAngieKey) { document.getElementById("angie-password-warning").style.display = "block"; } // Show desktop notification var rightNow = new Date(); akeebabackup.System.notification.notify(Joomla.Text._( "COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPSTARTED") + " " + rightNow.toLocaleString()); // Initialize steps akeebabackup.Backup.renderBackupSteps(""); // Start the response timer var maxExecutionTime = Joomla.getOptions("akeebabackup.Backup.maxExecutionTime", 14); var runtimeBias = Joomla.getOptions("akeebabackup.Backup.runtimeBias", 75); akeebabackup.Backup.startTimeoutBar(maxExecutionTime, runtimeBias); // Perform Ajax request var ajax_request = { // Data to send to AJAX "ajax": "start", description: document.getElementById("backup-description").value, comment: document.getElementById("comment").value }; akeebabackup.System.doAjax(ajax_request, akeebabackup.Backup.onStep, akeebabackup.Backup.onError, false); return false; }; /** * Backup step callback handler * * @param data Backup data received */ akeebabackup.Backup.onStep = function (data) { try { console.log("Running backup step"); console.log(data); } catch (e) { } // Update visual step progress from active domain data akeebabackup.Backup.renderBackupSteps(data.Domain); akeebabackup.Backup.currentDomain = data.Domain; // Update percentage display var percentageText = data.Progress + "%"; var elProgress = document.querySelector("#backup-percentage div.progress-bar"); elProgress.style.width = data.Progress + "%"; elProgress.setAttribute('aria-valuenow', percentageText); elProgress.innerHTML = percentageText; // Update step/substep display document.getElementById("backup-step").textContent = data.Step; document.getElementById("backup-substep").textContent = data.Substep; // Do we have warnings? data.Warnings = data.Warnings || []; if (data.Warnings.length > 0) { var barClass = document.getElementById("backup-percentage").className; if (barClass.indexOf("bg-warning") == -1) { document.getElementById("backup-percentage").className += " bg-warning"; } for (var i = 0; i < data.Warnings.length; i++) { var warning = data.Warnings[i]; akeebabackup.System.notification.notify( Joomla.Text._("COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPWARNING"), warning); var newDiv = document.createElement("div"); newDiv.className = 'mt-2 border-bottom pt-1 pb-1'; newDiv.textContent = warning; document.getElementById("warnings-list").appendChild(newDiv); } document.getElementById("backup-warnings-panel").style.display = "block"; } // Do we have errors? var error_message = data.Error; if (error_message != "") { try { console.error("Got an error message"); console.log(error_message); } catch (e) { } // Uh-oh! An error has occurred. akeebabackup.Backup.onError(error_message); return; } // No errors. Good! Are we finished yet? if (data["HasRun"] == 1) { try { console.log("Backup complete"); console.log(error_message); } catch (e) { } // Yes. Show backup completion page. akeebabackup.Backup.onDone(); return; } // No. Set the backup tag if (akeebabackup.Backup.tag == '') { akeebabackup.Backup.tag = "backend"; } // Set the backup id akeebabackup.Backup.backupid = data.backupid; // Reset the retries akeebabackup.Backup.resume.retry = 0; // How much time do I have to wait? var waitTime = 10; if (data.hasOwnProperty("sleepTime")) { waitTime = data.sleepTime; } // ...and send an AJAX command try { console.log("Starting tick timer with waitTime = " + waitTime + " msec"); } catch (e) { } akeebabackup.Backup.timer(waitTime); }; /** * Resume a backup attempt after an AJAX error has occurred. */ akeebabackup.Backup.resumeBackup = function () { // Make sure the timer is stopped akeebabackup.Backup.resetRetryTimeoutBar(); // Hide error and retry panels document.getElementById("error-panel").style.display = "none"; document.getElementById("retry-panel").style.display = "none"; // Show progress and warnings document.getElementById("backup-progress-pane").style.display = "block"; // Only display warnings if the saved state of warnings is true if (akeebabackup.Backup.resume.showWarnings) { document.getElementById("backup-warnings-panel").style.display = "block"; } var rightNow = new Date(); akeebabackup.System.notification.notify(Joomla.Text._( "COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPRESUME") + " " + rightNow.toLocaleString()); // Restart the backup akeebabackup.Backup.timer(); return false; }; /** * Cancel the automatic resumption of a backup attempt after an AJAX error has occurred */ akeebabackup.Backup.cancelResume = function () { // Make sure the timer is stopped akeebabackup.Backup.resetRetryTimeoutBar(); // Kill the backup var errorMessage = document.getElementById("backup-error-message-retry").innerHTML; akeebabackup.Backup.endWithError(errorMessage); return false; }; /** * AJAX error callback * * @param message The error message received */ akeebabackup.Backup.onError = function (message) { // If resume is not enabled, die. if (!Joomla.getOptions("akeebabackup.Backup.resume.enabled", true)) { akeebabackup.Backup.endWithError(message); return; } // If we are past the max retries, die. if (akeebabackup.Backup.resume.retry >= Joomla.getOptions("akeebabackup.Backup.resume.maxRetries", 3)) { akeebabackup.Backup.endWithError(message); return; } // Make sure the timer is stopped akeebabackup.Backup.resume.retry++; akeebabackup.Backup.resetRetryTimeoutBar(); var resumeNotificationMessage = Joomla.Text._("COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPHALT_DESC"); var timeout = Joomla.getOptions( "akeebabackup.Backup.resume.timeout", 10); var resumeNotificationMessageReplaced = resumeNotificationMessage.replace( "%d", timeout.toFixed(0)); akeebabackup.System.notification.notify( Joomla.Text._("COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPHALT"), resumeNotificationMessageReplaced); // Save display state of warnings panel akeebabackup.Backup.resume.showWarnings = (document.getElementById("backup-warnings-panel").style.display !== "none"); // Hide progress and warnings document.getElementById("backup-progress-pane").style.display = "none"; document.getElementById("backup-warnings-panel").style.display = "none"; document.getElementById("error-panel").style.display = "none"; // Setup and show the retry pane document.getElementById("backup-error-message-retry").textContent = message; document.getElementById("retry-panel").style.display = "block"; // Start the countdown akeebabackup.Backup.startRetryTimeoutBar(); }; /** * Terminate the backup with an error * * @param message The error message received */ akeebabackup.Backup.endWithError = function (message) { // Make sure the timer is stopped akeebabackup.Backup.resetTimeoutBar(); var alice_autorun = false; // Hide progress and warnings document.getElementById("backup-progress-pane").style.display = "none"; document.getElementById("backup-warnings-panel").style.display = "none"; document.getElementById("retry-panel").style.display = "none"; // Set up the view log URL var logURL = Joomla.getOptions("akeebabackup.Backup.URLs.LogURL", ""); var viewLogUrl = logURL + "&tag=" + akeebabackup.Backup.tag; var aliceUrl = Joomla.getOptions( "akeebabackup.Backup.URLs.AliceURL", "") + "&log=" + akeebabackup.Backup.tag; if (akeebabackup.Backup.backupid) { viewLogUrl = viewLogUrl + "." + encodeURIComponent(akeebabackup.Backup.backupid); aliceUrl = aliceUrl + "." + encodeURIComponent(akeebabackup.Backup.backupid); } if (akeebabackup.Backup.currentDomain == "finale") { alice_autorun = true; aliceUrl += "&autorun=1"; } document.getElementById("ab-viewlog-error").setAttribute("href", viewLogUrl); document.getElementById("ab-alice-error").setAttribute("href", aliceUrl); akeebabackup.System.notification.notify(Joomla.Text._("COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPFAILED"), message); // Try to send a push notification for failed backups akeebabackup.System.doAjax({ "ajax": "pushFail", "tag": akeebabackup.Backup.tag, "backupid": akeebabackup.Backup.backupid, "errorMessage": message }, function (msg) { }); // Setup and show error pane document.getElementById("backup-error-message").textContent = message; document.getElementById("error-panel").style.display = "block"; // Do we have to automatically analyze the log? if (alice_autorun) { setTimeout(function () { window.location = aliceUrl; }, 500); } }; /** * Backup finished callback handler */ akeebabackup.Backup.onDone = function () { var rightNow = new Date(); akeebabackup.System.notification.notify(Joomla.Text._( "COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPFINISHED") + " " + rightNow.toLocaleString()); // Make sure the timer is stopped akeebabackup.Backup.resetTimeoutBar(); // Hide progress document.getElementById("backup-progress-pane").style.display = "none"; // Show finished pane document.getElementById("backup-complete").style.display = "block"; document.getElementById("backup-warnings-panel").style.width = "100%"; // Show correct log URL var logURL = Joomla.getOptions("akeebabackup.Backup.URLs.LogURL", ""); var viewLogUrl = logURL + "&tag=" + akeebabackup.Backup.tag; // If the backup completes in a single pageload the backup tag and backupid are not returned. So I need to cheat. if (!akeebabackup.Backup.tag) { viewLogUrl = logURL + "&latest=1"; } else if (akeebabackup.Backup.backupid) { viewLogUrl = viewLogUrl + "." + encodeURIComponent(akeebabackup.Backup.backupid); } try { document.getElementById("ab-viewlog-success").setAttribute("href", viewLogUrl); } catch (e) { } // Proceed to the return URL if it is set var returnUrl = Joomla.getOptions("akeebabackup.Backup.returnUrl", akeebabackup.Backup.returnUrl); if (returnUrl != "") { window.location = returnUrl; } }; akeebabackup.Backup.restoreDefaultOptions = function () { document.getElementById("backup-description").value = Joomla.getOptions("akeebabackup.Backup.defaultDescription", ""); document.getElementById("comment").value = "ThisIsADummyStringToWorkAroundChrome"; document.getElementById("comment").value = ""; }; akeebabackup.Backup.flipProfile = function () { // Save the description and comments document.getElementById("flipDescription").value = document.getElementById("backup-description").value; document.getElementById("flipComment").value = document.getElementById("comment").value; // The timeout is necessary. The choice event is fired before the hidden SELECT element is updated. There is no // event after that change takes place. Therefore we need to wait a little bit for the change to take effect. setTimeout(function () { document.forms.flipForm.submit(); }, 500); }; akeebabackup.System.documentReady(function () { // Browser notifications: ask for permission if the feature is enabled akeebabackup.System.notification.askPermission(); // Register event handlers akeebabackup.System.addEventListener("comAkeebaControlPanelProfileSwitch", "choice", akeebabackup.Backup.flipProfile); akeebabackup.System.addEventListener("comAkeebaBackupCancelResume", "click", akeebabackup.Backup.cancelResume); akeebabackup.System.addEventListener("comAkeebaBackupResumeBackup", "click", akeebabackup.Backup.resumeBackup); if (Joomla.getOptions("akeebabackup.Backup.autostart")) { // Auto-start the backup: run backup now, skip registering events for the backup start / reset buttons akeebabackup.Backup.start(); } else { // Bind start button's click event akeebabackup.System.addEventListener("backup-start", "click", akeebabackup.Backup.start); akeebabackup.System.addEventListener("backup-default", "click", akeebabackup.Backup.restoreDefaultOptions); } });