fix: notifications for AJAX backups, download CSRF token
Generic: Project CI / Tests (push) Blocked by required conditions
Generic: Project CI / Tests (pull_request) Blocked by required conditions
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Blocked by required conditions
Generic: Repo Health / Scripts governance (push) Blocked by required conditions
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Blocked by required conditions
Generic: Repo Health / Repository health (push) Blocked by required conditions
Joomla: Extension CI / PHPStan Analysis (pull_request) Blocked by required conditions
Joomla: Extension CI / Build RC Pre-Release (pull_request) Blocked by required conditions
Generic: Repo Health / Report Issues (push) Blocked by required conditions
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Universal: PR Check / Report Issues (pull_request) Blocked by required conditions
Generic: Repo Health / Scripts governance (pull_request) Blocked by required conditions
Generic: Repo Health / Repository health (pull_request) Blocked by required conditions
Generic: Repo Health / Report Issues (pull_request) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: Auto Version Bump / Version Bump (push) Successful in 4s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 4s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 7s
Generic: Project CI / Lint & Validate (push) Successful in 11s
Generic: Project CI / Lint & Validate (pull_request) Successful in 11s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 12s
Universal: PR Check / Validate PR (pull_request) Failing after 48s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 54s

SteppedBackupEngine now sends email + ntfy notifications on both
success (completeRecord) and failure (failRecord). Previously only
BackupEngine (synchronous CLI/toolbar path) sent notifications.

Download link in backups template now includes the CSRF token in
the URL query string, fixing "security token did not match" error
when clicking download buttons.
This commit is contained in:
Jonathan Miller
2026-06-18 10:19:42 -05:00
parent 6810edcd7f
commit 36ec6dd5a3
2 changed files with 72 additions and 7 deletions
@@ -433,14 +433,47 @@ class SteppedBackupEngine
error_log('MokoSuiteBackup: Could not write log file: ' . $logPath);
}
$totalSize = is_file($session->archivePath) ? filesize($session->archivePath) : 0;
$update = (object) [
'id' => $session->recordId,
'status' => 'complete',
'backupend' => date('Y-m-d H:i:s'),
'log' => $logContent,
'id' => $session->recordId,
'status' => 'complete',
'backupend' => date('Y-m-d H:i:s'),
'total_size' => $totalSize,
'log' => $logContent,
];
$db->updateObject('#__mokosuitebackup_records', $update, 'id');
// Send notifications (email + ntfy)
try {
$query = $db->getQuery(true)
->select('*')
->from($db->quoteName('#__mokosuitebackup_profiles'))
->where($db->quoteName('id') . ' = ' . (int) $session->profileId);
$db->setQuery($query);
$profile = $db->loadObject();
if ($profile) {
$record = (object) [
'id' => $session->recordId,
'description' => $session->description ?? '',
'backup_type' => $session->backupType,
'archivename' => $session->archiveName,
'origin' => $session->origin,
'backupstart' => '',
'backupend' => date('Y-m-d H:i:s'),
'total_size' => $totalSize,
'files_count' => $session->filesCount ?? 0,
'tables_count' => $session->tablesCount ?? 0,
'remote_filename' => '',
];
NotificationSender::send($profile, $record, true, $logContent);
}
} catch (\Exception $e) {
error_log('MokoSuiteBackup: SteppedBackupEngine notification failed: ' . $e->getMessage());
}
}
/**
@@ -448,15 +481,47 @@ class SteppedBackupEngine
*/
private function failRecord(SteppedSession $session, string $error): void
{
$db = Factory::getDbo();
$db = Factory::getDbo();
$logContent = implode("\n", $session->log);
$update = (object) [
'id' => $session->recordId,
'status' => 'fail',
'backupend' => date('Y-m-d H:i:s'),
'log' => implode("\n", $session->log),
'log' => $logContent,
];
$db->updateObject('#__mokosuitebackup_records', $update, 'id');
// Send failure notification
try {
$query = $db->getQuery(true)
->select('*')
->from($db->quoteName('#__mokosuitebackup_profiles'))
->where($db->quoteName('id') . ' = ' . (int) $session->profileId);
$db->setQuery($query);
$profile = $db->loadObject();
if ($profile) {
$record = (object) [
'id' => $session->recordId,
'description' => $session->description,
'backup_type' => $session->backupType,
'archivename' => $session->archiveName,
'origin' => $session->origin,
'backupstart' => '',
'backupend' => date('Y-m-d H:i:s'),
'total_size' => 0,
'files_count' => $session->filesCount,
'tables_count' => $session->tablesCount,
'remote_filename' => '',
];
NotificationSender::send($profile, $record, false, $logContent);
}
} catch (\Exception $e) {
error_log('MokoSuiteBackup: SteppedBackupEngine failure notification failed: ' . $e->getMessage());
}
}
/**
@@ -145,7 +145,7 @@ $listDirn = $this->escape($this->state->get('list.direction'));
$isWebAccessible = !empty($item->absolute_path)
&& strpos(realpath($item->absolute_path) ?: $item->absolute_path, realpath(JPATH_ROOT) ?: JPATH_ROOT) === 0;
?>
<a href="<?php echo Route::_('index.php?option=com_mokosuitebackup&task=backups.download&id=' . $item->id); ?>"
<a href="<?php echo Route::_('index.php?option=com_mokosuitebackup&task=backups.download&id=' . $item->id . '&' . Session::getFormToken() . '=1'); ?>"
class="btn btn-sm btn-outline-primary" title="<?php echo Text::_('COM_MOKOJOOMBACKUP_DOWNLOAD'); ?>">
<span class="icon-download"></span>
</a>