From 1eb1c18bdfbd0ad581231d70059e3910f78f1658 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Tue, 30 Jun 2026 13:48:51 -0500 Subject: [PATCH 1/6] fix: add cancel stalled backup action with ACL permission Backups stuck in "running" status block all future backups for the same profile via the preflight check. Previously the only fix was a manual DB update. Adds a toolbar button and AJAX endpoint to cancel stalled backups: - New ACL permission: mokosuitebackup.backup.cancel - BackupsController::cancelStalled() for toolbar (multi-select) - AjaxController::cancelBackup() for AJAX/API use - Sets status to "fail", cleans up partial archive files - Updated preflight error message to mention the cancel action - Language keys for en-GB and en-US Claude-Session: https://claude.ai/code/session_01MbEjBtsSjPuTWhqqrMS2wG --- .../packages/com_mokosuitebackup/access.xml | 1 + .../language/en-GB/com_mokosuitebackup.ini | 8 +++ .../language/en-US/com_mokosuitebackup.ini | 10 +++ .../src/Controller/AjaxController.php | 61 ++++++++++++++++ .../src/Controller/BackupsController.php | 70 +++++++++++++++++++ .../src/Engine/PreflightCheck.php | 2 +- .../src/View/Backups/HtmlView.php | 4 ++ 7 files changed, 155 insertions(+), 1 deletion(-) diff --git a/source/packages/com_mokosuitebackup/access.xml b/source/packages/com_mokosuitebackup/access.xml index 37c2f9d..6f3220e 100644 --- a/source/packages/com_mokosuitebackup/access.xml +++ b/source/packages/com_mokosuitebackup/access.xml @@ -15,5 +15,6 @@ + diff --git a/source/packages/com_mokosuitebackup/language/en-GB/com_mokosuitebackup.ini b/source/packages/com_mokosuitebackup/language/en-GB/com_mokosuitebackup.ini index 8547103..738fb5a 100644 --- a/source/packages/com_mokosuitebackup/language/en-GB/com_mokosuitebackup.ini +++ b/source/packages/com_mokosuitebackup/language/en-GB/com_mokosuitebackup.ini @@ -450,6 +450,8 @@ COM_MOKOSUITEBACKUP_ACTION_BACKUP_COMPARE="Compare Backups" COM_MOKOSUITEBACKUP_ACTION_BACKUP_COMPARE_DESC="Allows users to compare two backup records side-by-side." COM_MOKOSUITEBACKUP_ACTION_BACKUP_BROWSE="Browse Archives" COM_MOKOSUITEBACKUP_ACTION_BACKUP_BROWSE_DESC="Allows users to view file listings inside backup archives without extracting." +COM_MOKOSUITEBACKUP_ACTION_BACKUP_CANCEL="Cancel Stalled Backup" +COM_MOKOSUITEBACKUP_ACTION_BACKUP_CANCEL_DESC="Allows users to cancel backup records stuck in running status and clean up partial archive files." ; Snapshot ACL COM_MOKOSUITEBACKUP_ACTION_SNAPSHOT_MANAGE="Manage Snapshots" @@ -500,6 +502,12 @@ COM_MOKOJOOMBACKUP_PURGE_INVALID_DATE="Invalid date. Please select a valid date. COM_MOKOJOOMBACKUP_PURGE_SUCCESS="%d backup(s) purged successfully." COM_MOKOJOOMBACKUP_PURGE_PARTIAL="%d backup(s) purged, but %d could not be deleted." +; Cancel Stalled Backup +COM_MOKOJOOMBACKUP_TOOLBAR_CANCEL_STALLED="Cancel Stalled" +COM_MOKOJOOMBACKUP_CANCEL_NONE_SELECTED="No backup records selected." +COM_MOKOJOOMBACKUP_CANCEL_NONE_RUNNING="None of the selected backups are in running status." +COM_MOKOJOOMBACKUP_CANCEL_SUCCESS="%d stalled backup(s) cancelled." + ; Remote Destinations (multi-remote) COM_MOKOJOOMBACKUP_REMOTE_DESTINATIONS="Remote Destinations" COM_MOKOJOOMBACKUP_REMOTE_ADD="Add Destination" diff --git a/source/packages/com_mokosuitebackup/language/en-US/com_mokosuitebackup.ini b/source/packages/com_mokosuitebackup/language/en-US/com_mokosuitebackup.ini index ef2e72b..1d7328d 100644 --- a/source/packages/com_mokosuitebackup/language/en-US/com_mokosuitebackup.ini +++ b/source/packages/com_mokosuitebackup/language/en-US/com_mokosuitebackup.ini @@ -116,3 +116,13 @@ COM_MOKOJOOMBACKUP_PURGE_NONE_FOUND="No completed backups found before the selec COM_MOKOJOOMBACKUP_PURGE_INVALID_DATE="Invalid date. Please select a valid date." COM_MOKOJOOMBACKUP_PURGE_SUCCESS="%d backup(s) purged successfully." COM_MOKOJOOMBACKUP_PURGE_PARTIAL="%d backup(s) purged, but %d could not be deleted." + +; Cancel Stalled Backup +COM_MOKOJOOMBACKUP_TOOLBAR_CANCEL_STALLED="Cancel Stalled" +COM_MOKOJOOMBACKUP_CANCEL_NONE_SELECTED="No backup records selected." +COM_MOKOJOOMBACKUP_CANCEL_NONE_RUNNING="None of the selected backups are in running status." +COM_MOKOJOOMBACKUP_CANCEL_SUCCESS="%d stalled backup(s) cancelled." + +; ACL - Cancel +COM_MOKOSUITEBACKUP_ACTION_BACKUP_CANCEL="Cancel Stalled Backup" +COM_MOKOSUITEBACKUP_ACTION_BACKUP_CANCEL_DESC="Allows users to cancel backup records stuck in running status and clean up partial archive files." diff --git a/source/packages/com_mokosuitebackup/src/Controller/AjaxController.php b/source/packages/com_mokosuitebackup/src/Controller/AjaxController.php index 159af3b..f064e0b 100644 --- a/source/packages/com_mokosuitebackup/src/Controller/AjaxController.php +++ b/source/packages/com_mokosuitebackup/src/Controller/AjaxController.php @@ -84,6 +84,67 @@ class AjaxController extends BaseController $this->sendJson($result); } + /** + * Cancel a backup record stuck in "running" status. + * POST: task=ajax.cancelBackup&id=123 + */ + public function cancelBackup(): void + { + if (!Session::checkToken('get') && !Session::checkToken('post')) { + $this->sendJson(['error' => true, 'message' => 'Invalid token'], 403); + + return; + } + + if (!$this->app->getIdentity()->authorise('mokosuitebackup.backup.cancel', 'com_mokosuitebackup')) { + $this->sendJson(['error' => true, 'message' => 'Access denied'], 403); + + return; + } + + $id = $this->input->getInt('id', 0); + + if (!$id) { + $this->sendJson(['error' => true, 'message' => 'Missing record ID']); + + return; + } + + $db = Factory::getDbo(); + $query = $db->getQuery(true) + ->select($db->quoteName(['id', 'status', 'absolute_path'])) + ->from($db->quoteName('#__mokosuitebackup_records')) + ->where($db->quoteName('id') . ' = ' . $id); + $db->setQuery($query); + $record = $db->loadObject(); + + if (!$record) { + $this->sendJson(['error' => true, 'message' => 'Record not found'], 404); + + return; + } + + if ($record->status !== 'running') { + $this->sendJson(['error' => true, 'message' => 'Backup is not in running status']); + + return; + } + + $update = $db->getQuery(true) + ->update($db->quoteName('#__mokosuitebackup_records')) + ->set($db->quoteName('status') . ' = ' . $db->quote('fail')) + ->set($db->quoteName('backupend') . ' = ' . $db->quote(date('Y-m-d H:i:s'))) + ->where($db->quoteName('id') . ' = ' . $id); + $db->setQuery($update); + $db->execute(); + + if (!empty($record->absolute_path) && is_file($record->absolute_path)) { + @unlink($record->absolute_path); + } + + $this->sendJson(['error' => false, 'message' => 'Backup cancelled']); + } + /** * Browse server directories for the folder picker field. * POST: task=ajax.browseDir&path=/some/path diff --git a/source/packages/com_mokosuitebackup/src/Controller/BackupsController.php b/source/packages/com_mokosuitebackup/src/Controller/BackupsController.php index 1f09d49..b2bad20 100644 --- a/source/packages/com_mokosuitebackup/src/Controller/BackupsController.php +++ b/source/packages/com_mokosuitebackup/src/Controller/BackupsController.php @@ -235,6 +235,76 @@ class BackupsController extends AdminController $this->setRedirect(Route::_('index.php?option=com_mokosuitebackup&view=backups', false)); } + /** + * Cancel selected backup records that are stuck in "running" status. + * + * Sets their status to "fail", cleans up partial archive files, + * and destroys any associated stepped session. + */ + public function cancelStalled(): void + { + $this->checkToken(); + + if (!$this->app->getIdentity()->authorise('mokosuitebackup.backup.cancel', 'com_mokosuitebackup')) { + $this->setMessage(Text::_('JLIB_APPLICATION_ERROR_ACCESS_FORBIDDEN'), 'error'); + $this->setRedirect(Route::_('index.php?option=com_mokosuitebackup&view=backups', false)); + + return; + } + + $cid = $this->input->get('cid', [], 'array'); + + if (empty($cid)) { + $this->setMessage(Text::_('COM_MOKOJOOMBACKUP_CANCEL_NONE_SELECTED'), 'warning'); + $this->setRedirect(Route::_('index.php?option=com_mokosuitebackup&view=backups', false)); + + return; + } + + $db = $this->app->getContainer()->get('DatabaseDriver'); + $cancelled = 0; + $skipped = 0; + + foreach ($cid as $id) { + $id = (int) $id; + + $query = $db->getQuery(true) + ->select($db->quoteName(['id', 'status', 'absolute_path'])) + ->from($db->quoteName('#__mokosuitebackup_records')) + ->where($db->quoteName('id') . ' = ' . $id); + $db->setQuery($query); + $record = $db->loadObject(); + + if (!$record || $record->status !== 'running') { + $skipped++; + + continue; + } + + $update = $db->getQuery(true) + ->update($db->quoteName('#__mokosuitebackup_records')) + ->set($db->quoteName('status') . ' = ' . $db->quote('fail')) + ->set($db->quoteName('backupend') . ' = ' . $db->quote(date('Y-m-d H:i:s'))) + ->where($db->quoteName('id') . ' = ' . $id); + $db->setQuery($update); + $db->execute(); + + if (!empty($record->absolute_path) && is_file($record->absolute_path)) { + @unlink($record->absolute_path); + } + + $cancelled++; + } + + if ($cancelled > 0) { + $this->setMessage(Text::sprintf('COM_MOKOJOOMBACKUP_CANCEL_SUCCESS', $cancelled)); + } elseif ($skipped > 0) { + $this->setMessage(Text::_('COM_MOKOJOOMBACKUP_CANCEL_NONE_RUNNING'), 'warning'); + } + + $this->setRedirect(Route::_('index.php?option=com_mokosuitebackup&view=backups', false)); + } + /** * No-op target for the purge toolbar button. * diff --git a/source/packages/com_mokosuitebackup/src/Engine/PreflightCheck.php b/source/packages/com_mokosuitebackup/src/Engine/PreflightCheck.php index ac62cd3..d85e821 100644 --- a/source/packages/com_mokosuitebackup/src/Engine/PreflightCheck.php +++ b/source/packages/com_mokosuitebackup/src/Engine/PreflightCheck.php @@ -209,7 +209,7 @@ class PreflightCheck if ($running > 0) { $this->errors[] = 'Another backup is already running for profile: ' . $profile->title - . ' — wait for it to finish or delete the stale record'; + . ' — wait for it to finish or use Cancel Stalled from the Backup Records toolbar'; } } diff --git a/source/packages/com_mokosuitebackup/src/View/Backups/HtmlView.php b/source/packages/com_mokosuitebackup/src/View/Backups/HtmlView.php index 4816383..3b45d0f 100644 --- a/source/packages/com_mokosuitebackup/src/View/Backups/HtmlView.php +++ b/source/packages/com_mokosuitebackup/src/View/Backups/HtmlView.php @@ -113,6 +113,10 @@ class HtmlView extends BaseHtmlView ToolbarHelper::custom('backups.compare', 'copy', '', 'COM_MOKOJOOMBACKUP_TOOLBAR_COMPARE', true); } + if ($user->authorise('mokosuitebackup.backup.cancel', 'com_mokosuitebackup')) { + ToolbarHelper::custom('backups.cancelStalled', 'stop-circle', '', 'COM_MOKOJOOMBACKUP_TOOLBAR_CANCEL_STALLED', true); + } + if ($user->authorise('core.delete', 'com_mokosuitebackup')) { ToolbarHelper::deleteList('JGLOBAL_CONFIRM_DELETE', 'backups.delete'); } -- 2.52.0 From a56f72b186226ef1e30234924c05d4b1c1a4164f Mon Sep 17 00:00:00 2001 From: "gitea-actions[bot]" Date: Tue, 30 Jun 2026 18:49:16 +0000 Subject: [PATCH 2/6] chore(version): pre-release bump to 02.52.20-dev [skip ci] --- .mokogitea/workflows/issue-branch.yml | 2 +- SECURITY.md | 2 +- source/packages/MokoSuiteClient | 2 +- source/packages/com_mokosuitebackup/mokosuitebackup.xml | 2 +- .../packages/com_mokosuitebackup/sql/updates/mysql/02.52.20.sql | 1 + .../mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml | 2 +- .../packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml | 2 +- .../packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml | 2 +- .../plg_webservices_mokosuitebackup/mokosuitebackup.xml | 2 +- source/pkg_mokosuitebackup.xml | 2 +- 14 files changed, 14 insertions(+), 13 deletions(-) create mode 100644 source/packages/com_mokosuitebackup/sql/updates/mysql/02.52.20.sql diff --git a/.mokogitea/workflows/issue-branch.yml b/.mokogitea/workflows/issue-branch.yml index 11958bd..5fcb249 100644 --- a/.mokogitea/workflows/issue-branch.yml +++ b/.mokogitea/workflows/issue-branch.yml @@ -5,7 +5,7 @@ # FILE INFORMATION # DEFGROUP: Gitea.Workflow # INGROUP: mokocli.Automation -# VERSION: 01.00.00 +# VERSION: 02.52.20 # BRIEF: Auto-create feature branch when an issue is opened name: "Universal: Issue Branch" diff --git a/SECURITY.md b/SECURITY.md index 5dfd6f1..df2069c 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -23,7 +23,7 @@ DEFGROUP: Template-Joomla INGROUP: Template-Joomla.Documentation REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Joomla PATH: /SECURITY.md -VERSION: 02.52.18 +VERSION: 02.52.20 BRIEF: Security vulnerability reporting and handling policy --> diff --git a/source/packages/MokoSuiteClient b/source/packages/MokoSuiteClient index 0a9125e..c7e6670 160000 --- a/source/packages/MokoSuiteClient +++ b/source/packages/MokoSuiteClient @@ -1 +1 @@ -Subproject commit 0a9125e51956a084941abccdf2de8ddd064777e8 +Subproject commit c7e66705443f74e3ee2ffdfecc08224cc40240aa diff --git a/source/packages/com_mokosuitebackup/mokosuitebackup.xml b/source/packages/com_mokosuitebackup/mokosuitebackup.xml index 916c79c..3c01478 100644 --- a/source/packages/com_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/com_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> MokoSuiteBackup - 02.52.18 + 02.52.20 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/com_mokosuitebackup/sql/updates/mysql/02.52.20.sql b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.52.20.sql new file mode 100644 index 0000000..4812b35 --- /dev/null +++ b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.52.20.sql @@ -0,0 +1 @@ +/* 02.52.20 — no schema changes */ diff --git a/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml b/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml index 8c6c5ba..88c0bdf 100644 --- a/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml +++ b/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml @@ -8,7 +8,7 @@ --> mod_mokosuitebackup_cpanel - 02.52.18 + 02.52.20 2026-06-23 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml index 14db151..1aac1ef 100644 --- a/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Action Log - MokoSuiteBackup - 02.52.18 + 02.52.20 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml index 1fdeb74..765d8ec 100644 --- a/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Console - MokoSuiteBackup - 02.52.18 + 02.52.20 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml index 0c325b4..17b2685 100644 --- a/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Content - MokoSuiteBackup - 02.52.18 + 02.52.20 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml index d00530b..b736034 100644 --- a/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml @@ -1,7 +1,7 @@ Quick Icon - MokoSuiteBackup - 02.52.18 + 02.52.20 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml index 7ad71bf..5e11793 100644 --- a/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> System - MokoSuiteBackup - 02.52.18 + 02.52.20 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml index 0a4e874..d2a84bf 100644 --- a/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Task - MokoSuiteBackup - 02.52.18 + 02.52.20 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml index acd32a2..ad258c0 100644 --- a/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Web Services - MokoSuiteBackup - 02.52.18 + 02.52.20 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/pkg_mokosuitebackup.xml b/source/pkg_mokosuitebackup.xml index aa7a8ae..2c90373 100644 --- a/source/pkg_mokosuitebackup.xml +++ b/source/pkg_mokosuitebackup.xml @@ -8,7 +8,7 @@ Package - MokoSuiteBackup mokosuitebackup - 02.52.18 + 02.52.20 2026-06-02 Moko Consulting hello@mokoconsulting.tech -- 2.52.0 From b26a21820ba47a10934ee78e7ad58c7116e01a00 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Tue, 30 Jun 2026 13:49:56 -0500 Subject: [PATCH 3/6] fix: auto-cancel stalled backups after 30 min timeout PreflightCheck now auto-cancels "running" backup records that have exceeded 30 minutes, treating them as stalled. Partial archive files are cleaned up. The auto-cancelled records are surfaced as warnings so the user knows what happened. Records younger than 30 minutes are assumed to be legitimately running and still block new backups for the same profile. Claude-Session: https://claude.ai/code/session_01MbEjBtsSjPuTWhqqrMS2wG --- .../src/Engine/PreflightCheck.php | 42 +++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/source/packages/com_mokosuitebackup/src/Engine/PreflightCheck.php b/source/packages/com_mokosuitebackup/src/Engine/PreflightCheck.php index d85e821..64b42b5 100644 --- a/source/packages/com_mokosuitebackup/src/Engine/PreflightCheck.php +++ b/source/packages/com_mokosuitebackup/src/Engine/PreflightCheck.php @@ -194,20 +194,56 @@ class PreflightCheck } } + private const STALE_TIMEOUT_MINUTES = 30; + /** * Check if another backup is already running for this profile. + * + * Backups running longer than STALE_TIMEOUT_MINUTES are automatically + * marked as failed so they don't permanently block future runs. */ private function checkRunningBackup(object $profile, object $db): void { $query = $db->getQuery(true) - ->select('COUNT(*)') + ->select($db->quoteName(['id', 'backupstart', 'absolute_path'])) ->from($db->quoteName('#__mokosuitebackup_records')) ->where($db->quoteName('profile_id') . ' = ' . (int) $profile->id) ->where($db->quoteName('status') . ' = ' . $db->quote('running')); $db->setQuery($query); - $running = (int) $db->loadResult(); + $rows = $db->loadObjectList(); - if ($running > 0) { + if (empty($rows)) { + return; + } + + $cutoff = time() - (self::STALE_TIMEOUT_MINUTES * 60); + $stillAlive = 0; + + foreach ($rows as $row) { + $started = strtotime($row->backupstart); + + if ($started !== false && $started < $cutoff) { + $update = $db->getQuery(true) + ->update($db->quoteName('#__mokosuitebackup_records')) + ->set($db->quoteName('status') . ' = ' . $db->quote('fail')) + ->set($db->quoteName('backupend') . ' = ' . $db->quote(date('Y-m-d H:i:s'))) + ->where($db->quoteName('id') . ' = ' . (int) $row->id); + $db->setQuery($update); + $db->execute(); + + if (!empty($row->absolute_path) && is_file($row->absolute_path)) { + @unlink($row->absolute_path); + } + + $this->warnings[] = 'Auto-cancelled stalled backup #' . $row->id + . ' (started ' . $row->backupstart . ', exceeded ' + . self::STALE_TIMEOUT_MINUTES . ' min timeout)'; + } else { + $stillAlive++; + } + } + + if ($stillAlive > 0) { $this->errors[] = 'Another backup is already running for profile: ' . $profile->title . ' — wait for it to finish or use Cancel Stalled from the Backup Records toolbar'; } -- 2.52.0 From 5be922613fc887345b9f432874d6dd39476cd16f Mon Sep 17 00:00:00 2001 From: "gitea-actions[bot]" Date: Tue, 30 Jun 2026 18:50:40 +0000 Subject: [PATCH 4/6] chore(version): pre-release bump to 02.52.21-dev [skip ci] --- .mokogitea/workflows/issue-branch.yml | 2 +- SECURITY.md | 2 +- source/packages/com_mokosuitebackup/mokosuitebackup.xml | 2 +- .../packages/com_mokosuitebackup/sql/updates/mysql/02.52.21.sql | 1 + .../mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml | 2 +- .../packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml | 2 +- .../packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml | 2 +- .../plg_webservices_mokosuitebackup/mokosuitebackup.xml | 2 +- source/pkg_mokosuitebackup.xml | 2 +- 13 files changed, 13 insertions(+), 12 deletions(-) create mode 100644 source/packages/com_mokosuitebackup/sql/updates/mysql/02.52.21.sql diff --git a/.mokogitea/workflows/issue-branch.yml b/.mokogitea/workflows/issue-branch.yml index 5fcb249..4f2a190 100644 --- a/.mokogitea/workflows/issue-branch.yml +++ b/.mokogitea/workflows/issue-branch.yml @@ -5,7 +5,7 @@ # FILE INFORMATION # DEFGROUP: Gitea.Workflow # INGROUP: mokocli.Automation -# VERSION: 02.52.20 +# VERSION: 02.52.21 # BRIEF: Auto-create feature branch when an issue is opened name: "Universal: Issue Branch" diff --git a/SECURITY.md b/SECURITY.md index df2069c..297840f 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -23,7 +23,7 @@ DEFGROUP: Template-Joomla INGROUP: Template-Joomla.Documentation REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Joomla PATH: /SECURITY.md -VERSION: 02.52.20 +VERSION: 02.52.21 BRIEF: Security vulnerability reporting and handling policy --> diff --git a/source/packages/com_mokosuitebackup/mokosuitebackup.xml b/source/packages/com_mokosuitebackup/mokosuitebackup.xml index 3c01478..55474f9 100644 --- a/source/packages/com_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/com_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> MokoSuiteBackup - 02.52.20 + 02.52.21 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/com_mokosuitebackup/sql/updates/mysql/02.52.21.sql b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.52.21.sql new file mode 100644 index 0000000..5727cbf --- /dev/null +++ b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.52.21.sql @@ -0,0 +1 @@ +/* 02.52.21 — no schema changes */ diff --git a/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml b/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml index 88c0bdf..77bb70c 100644 --- a/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml +++ b/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml @@ -8,7 +8,7 @@ --> mod_mokosuitebackup_cpanel - 02.52.20 + 02.52.21 2026-06-23 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml index 1aac1ef..c783628 100644 --- a/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Action Log - MokoSuiteBackup - 02.52.20 + 02.52.21 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml index 765d8ec..7b110a8 100644 --- a/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Console - MokoSuiteBackup - 02.52.20 + 02.52.21 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml index 17b2685..5356723 100644 --- a/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Content - MokoSuiteBackup - 02.52.20 + 02.52.21 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml index b736034..421af36 100644 --- a/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml @@ -1,7 +1,7 @@ Quick Icon - MokoSuiteBackup - 02.52.20 + 02.52.21 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml index 5e11793..71bc16e 100644 --- a/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> System - MokoSuiteBackup - 02.52.20 + 02.52.21 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml index d2a84bf..cd5ff7b 100644 --- a/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Task - MokoSuiteBackup - 02.52.20 + 02.52.21 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml index ad258c0..2dbdd87 100644 --- a/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Web Services - MokoSuiteBackup - 02.52.20 + 02.52.21 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/pkg_mokosuitebackup.xml b/source/pkg_mokosuitebackup.xml index 2c90373..34ccd67 100644 --- a/source/pkg_mokosuitebackup.xml +++ b/source/pkg_mokosuitebackup.xml @@ -8,7 +8,7 @@ Package - MokoSuiteBackup mokosuitebackup - 02.52.20 + 02.52.21 2026-06-02 Moko Consulting hello@mokoconsulting.tech -- 2.52.0 From 4560ffb84b9da81b574ec3a8d02b9fe1aca3993f Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Tue, 30 Jun 2026 13:52:19 -0500 Subject: [PATCH 5/6] docs: update changelog with cancel stalled and pre-update modal Claude-Session: https://claude.ai/code/session_01MbEjBtsSjPuTWhqqrMS2wG --- CHANGELOG.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42cc677..d8f3a35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,20 @@ # Changelog ## [Unreleased] -## [02.52.18] --- 2026-06-30 +### Added +- Cancel Stalled toolbar button on Backup Records view to cancel backups stuck in "running" status +- New ACL permission `mokosuitebackup.backup.cancel` for cancel stalled action +- AJAX endpoint `ajax.cancelBackup` for programmatic/API cancel +- Auto-timeout failsafe: preflight auto-cancels "running" backups older than 30 minutes +- Pre-extension-update backup progress modal (Bootstrap 5 modal with stepped AJAX progress bar) + +### Fixed +- Pre-update backup ran synchronously with no browser feedback — page hung until complete +- Stalled backups permanently blocked future backups for the same profile +- Preflight error message now directs users to Cancel Stalled action ## [02.52.18] --- 2026-06-30 -## [01.45.00] --- 2026-06-28 - - ## [01.45.00] --- 2026-06-28 ## [01.43.35] --- 2026-06-28 -- 2.52.0 From 8dac5a7448d2594888395c7de8050c702a83f94d Mon Sep 17 00:00:00 2001 From: "gitea-actions[bot]" Date: Tue, 30 Jun 2026 18:53:06 +0000 Subject: [PATCH 6/6] chore(version): pre-release bump to 02.52.22-dev [skip ci] --- .mokogitea/workflows/issue-branch.yml | 2 +- SECURITY.md | 2 +- source/packages/com_mokosuitebackup/mokosuitebackup.xml | 2 +- .../packages/com_mokosuitebackup/sql/updates/mysql/02.52.22.sql | 1 + .../mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml | 2 +- .../packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml | 2 +- .../packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml | 2 +- .../plg_webservices_mokosuitebackup/mokosuitebackup.xml | 2 +- source/pkg_mokosuitebackup.xml | 2 +- 13 files changed, 13 insertions(+), 12 deletions(-) create mode 100644 source/packages/com_mokosuitebackup/sql/updates/mysql/02.52.22.sql diff --git a/.mokogitea/workflows/issue-branch.yml b/.mokogitea/workflows/issue-branch.yml index 4f2a190..9a5ae00 100644 --- a/.mokogitea/workflows/issue-branch.yml +++ b/.mokogitea/workflows/issue-branch.yml @@ -5,7 +5,7 @@ # FILE INFORMATION # DEFGROUP: Gitea.Workflow # INGROUP: mokocli.Automation -# VERSION: 02.52.21 +# VERSION: 02.52.22 # BRIEF: Auto-create feature branch when an issue is opened name: "Universal: Issue Branch" diff --git a/SECURITY.md b/SECURITY.md index 297840f..46c440f 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -23,7 +23,7 @@ DEFGROUP: Template-Joomla INGROUP: Template-Joomla.Documentation REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Joomla PATH: /SECURITY.md -VERSION: 02.52.21 +VERSION: 02.52.22 BRIEF: Security vulnerability reporting and handling policy --> diff --git a/source/packages/com_mokosuitebackup/mokosuitebackup.xml b/source/packages/com_mokosuitebackup/mokosuitebackup.xml index 55474f9..6aeb44e 100644 --- a/source/packages/com_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/com_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> MokoSuiteBackup - 02.52.21 + 02.52.22 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/com_mokosuitebackup/sql/updates/mysql/02.52.22.sql b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.52.22.sql new file mode 100644 index 0000000..dd661bd --- /dev/null +++ b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.52.22.sql @@ -0,0 +1 @@ +/* 02.52.22 — no schema changes */ diff --git a/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml b/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml index 77bb70c..f9cd809 100644 --- a/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml +++ b/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml @@ -8,7 +8,7 @@ --> mod_mokosuitebackup_cpanel - 02.52.21 + 02.52.22 2026-06-23 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml index c783628..e7759ab 100644 --- a/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Action Log - MokoSuiteBackup - 02.52.21 + 02.52.22 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml index 7b110a8..94003d1 100644 --- a/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Console - MokoSuiteBackup - 02.52.21 + 02.52.22 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml index 5356723..38e1384 100644 --- a/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Content - MokoSuiteBackup - 02.52.21 + 02.52.22 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml index 421af36..a757f43 100644 --- a/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml @@ -1,7 +1,7 @@ Quick Icon - MokoSuiteBackup - 02.52.21 + 02.52.22 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml index 71bc16e..0f6282c 100644 --- a/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> System - MokoSuiteBackup - 02.52.21 + 02.52.22 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml index cd5ff7b..4643360 100644 --- a/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Task - MokoSuiteBackup - 02.52.21 + 02.52.22 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml index 2dbdd87..868f770 100644 --- a/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Web Services - MokoSuiteBackup - 02.52.21 + 02.52.22 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/pkg_mokosuitebackup.xml b/source/pkg_mokosuitebackup.xml index 34ccd67..fa57eb2 100644 --- a/source/pkg_mokosuitebackup.xml +++ b/source/pkg_mokosuitebackup.xml @@ -8,7 +8,7 @@ Package - MokoSuiteBackup mokosuitebackup - 02.52.21 + 02.52.22 2026-06-02 Moko Consulting hello@mokoconsulting.tech -- 2.52.0