Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 64875771a7 | |||
| 605e45a967 | |||
| d7639ec3d9 | |||
| 9c37bc6303 | |||
| c01b0ab112 | |||
| 462aed0e51 | |||
| c7f0a122a4 | |||
| 5fac72b5ed | |||
| 3efadf941f | |||
| dabc556e18 | |||
| 6717f0ed68 | |||
| a6de828fec | |||
| a5e0775b0b | |||
| cba074b0aa | |||
| 455689532e | |||
| a9882b9b51 | |||
| 2d382cd62b | |||
| db9734b156 | |||
| a4c8b72733 |
@@ -5,7 +5,7 @@
|
||||
# FILE INFORMATION
|
||||
# DEFGROUP: MokoGIT.Workflow
|
||||
# INGROUP: MokoCLI.Automation
|
||||
# VERSION: 02.66.00
|
||||
# VERSION: 02.67.00
|
||||
# BRIEF: Auto-create feature branch when an issue is opened
|
||||
|
||||
name: "Universal: Issue Branch"
|
||||
|
||||
+7
-3
@@ -1,7 +1,12 @@
|
||||
# Changelog
|
||||
## [Unreleased]
|
||||
|
||||
## [02.66.00] --- 2026-07-16
|
||||
## [02.67.00] --- 2026-07-17
|
||||
|
||||
### Fixed
|
||||
- Pre-update / pre-uninstall skip flag is now **time-bounded**. It records the moment it was armed and is honoured only within a short TTL (5 min), always consumed one-shot. Previously a bare boolean: if a user ran the full-screen pre-update backup then abandoned the flow (closed the tab before the update re-fired), the flag lingered for the whole session and could silently suppress a later, unrelated pre-action backup — i.e. a real update running with **no** backup. Now a stale flag is ignored and the server backs up as normal.
|
||||
- Pre-update / pre-uninstall backup can no longer run **twice**. The one-shot "skip the synchronous server-side backup" flag is now armed **server-side** the moment the full-screen backup completes (in `AjaxController::step`, keyed by the `msb_action` it is fronting), instead of relying solely on the best-effort client `ajax.preupdateAck` POST (whose failure was silently swallowed in a `catch()`). If that ack ever fails to land, the re-fired extension update/uninstall no longer triggers a second backup behind the "update is running" overlay. The flag is armed **only** on genuine completion (`done`, no error), so a failed or cancelled backup still lets the server back up before the action — the failure mode stays "one extra backup", never "no backup".
|
||||
- Component **Options** page showed the raw `COM_MOKOSUITEBACKUP_CONFIGURATION` constant instead of a translated title. Joomla's `com_config` derives the Options-page title (and the component name) from the extension *element* (`com_mokosuitebackup`), but the language files defined those keys only under the legacy `COM_MOKOJOOMBACKUP_` stem. Added the element-derived `COM_MOKOSUITEBACKUP` and `COM_MOKOSUITEBACKUP_CONFIGURATION` keys to all four language files (en-GB/en-US, `.ini` and `.sys.ini`), matching the already-migrated `COM_MOKOSUITEBACKUP_ACTION_*` ACL keys. The 400+ explicitly-referenced `COM_MOKOJOOMBACKUP_*` keys are unaffected and left as-is. (#234)
|
||||
|
||||
## [02.66.00] --- 2026-07-16
|
||||
|
||||
@@ -20,9 +25,8 @@
|
||||
- Database view "One Problem" on MokoSuiteBackup: reconciled the `#__mokosuitebackup_profiles` schema-checker output with the update-file history. Corrected the stale `TINYINT` definition in `01.01.01.sql` to the final `VARCHAR(20)` type, fixed the `MODIFY COLUMN` parser trip-up in `01.39.00.sql`, and rewrote the retired `sftp_*` `ADD COLUMN` statements in `01.35.00.sql`/`01.36.00.sql` as bare `ADD` so Joomla's checker no longer demands columns that `02.52.25` and the postflight purge deliberately remove. Joomla's schema checker now reports no problems.
|
||||
|
||||
### Changed
|
||||
- Component now shows the "Type - Name" pretty name `Component - MokoSuiteBackup` in the Extensions manager, consistent with the other sub-extensions. Achieved safely with an `<element>com_mokosuitebackup</element>` tag in the manifest (Joomla reads `<element>` before `<name>` for the extension element), so the element stays `com_mokosuitebackup` and no duplicate/orphaned component is created.
|
||||
- Backup/restore progress modals in the backups view now use the same full-screen black, big-text, animated Atum-coloured progress-bar theme as the `runbackup` screen, so all backup progress surfaces match. New `media/css/backup-progress.css` scopes the black to the modal (the list page is unaffected until a modal opens).
|
||||
- Standalone MokoRestore wizard (generated `restore.php`) re-branded to the full-black MokoSuite theme — black background, big header, dark panels/forms, and MokoSuite accent colours — so the restore experience matches the rest of the system instead of the old light blue "Joomla-styled" look.
|
||||
|
||||
## [02.64.00] --- 2026-07-14
|
||||
|
||||
## [02.64.00] --- 2026-07-14
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ DEFGROUP: Template-Joomla
|
||||
INGROUP: Template-Joomla.Documentation
|
||||
REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Joomla
|
||||
PATH: /SECURITY.md
|
||||
VERSION: 02.66.00
|
||||
VERSION: 02.67.00
|
||||
BRIEF: Security vulnerability reporting and handling policy
|
||||
-->
|
||||
|
||||
|
||||
Submodule source/packages/MokoSuiteClient updated: c564efe357...6bb4f884d4
@@ -7,6 +7,13 @@
|
||||
COM_MOKOJOOMBACKUP="MokoSuiteBackup"
|
||||
COM_MOKOJOOMBACKUP_SHORT="Backup"
|
||||
COM_MOKOJOOMBACKUP_CONFIGURATION="MokoSuiteBackup Options"
|
||||
; Framework-derived keys: Joomla builds the component name and the Options-page
|
||||
; title from the element (com_mokosuitebackup), NOT from the legacy
|
||||
; COM_MOKOJOOMBACKUP_ stem, so they must exist under the new stem too (mirrors
|
||||
; the COM_MOKOSUITEBACKUP_ACTION_* ACL keys). Without these the Options screen
|
||||
; shows the raw COM_MOKOSUITEBACKUP_CONFIGURATION constant. See #234.
|
||||
COM_MOKOSUITEBACKUP="MokoSuiteBackup"
|
||||
COM_MOKOSUITEBACKUP_CONFIGURATION="MokoSuiteBackup Options"
|
||||
COM_MOKOJOOMBACKUP_DESCRIPTION="Full-site backup and restore for Joomla"
|
||||
|
||||
; Submenu
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
COM_MOKOJOOMBACKUP="MokoSuiteBackup"
|
||||
COM_MOKOJOOMBACKUP_SHORT="Backup"
|
||||
COM_MOKOJOOMBACKUP_DESCRIPTION="Full-site backup and restore for Joomla — database, files, and configuration."
|
||||
; Element-derived aliases (see the .ini file for the rationale). #234
|
||||
COM_MOKOSUITEBACKUP="MokoSuiteBackup"
|
||||
COM_MOKOSUITEBACKUP_CONFIGURATION="MokoSuiteBackup Options"
|
||||
COM_MOKOJOOMBACKUP_SUBMENU_DASHBOARD="Dashboard"
|
||||
COM_MOKOJOOMBACKUP_SUBMENU_BACKUPS="Backup Records"
|
||||
COM_MOKOJOOMBACKUP_SUBMENU_PROFILES="Backup Profiles"
|
||||
|
||||
@@ -7,6 +7,13 @@
|
||||
COM_MOKOJOOMBACKUP="MokoSuiteBackup"
|
||||
COM_MOKOJOOMBACKUP_SHORT="Backup"
|
||||
COM_MOKOJOOMBACKUP_DESCRIPTION="Full-site backup and restore for Joomla"
|
||||
; Framework-derived keys: Joomla builds the component name and the Options-page
|
||||
; title from the element (com_mokosuitebackup), NOT from the legacy
|
||||
; COM_MOKOJOOMBACKUP_ stem, so they must exist under the new stem too (mirrors
|
||||
; the COM_MOKOSUITEBACKUP_ACTION_* ACL keys). Without these the Options screen
|
||||
; shows the raw COM_MOKOSUITEBACKUP_CONFIGURATION constant. See #234.
|
||||
COM_MOKOSUITEBACKUP="MokoSuiteBackup"
|
||||
COM_MOKOSUITEBACKUP_CONFIGURATION="MokoSuiteBackup Options"
|
||||
COM_MOKOJOOMBACKUP_SUBMENU_DASHBOARD="Dashboard"
|
||||
COM_MOKOJOOMBACKUP_SUBMENU_BACKUPS="Backup Records"
|
||||
COM_MOKOJOOMBACKUP_SUBMENU_PROFILES="Backup Profiles"
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
|
||||
COM_MOKOJOOMBACKUP="MokoSuiteBackup"
|
||||
COM_MOKOJOOMBACKUP_SHORT="Backup"
|
||||
; Element-derived aliases (see the .ini file for the rationale). #234
|
||||
COM_MOKOSUITEBACKUP="MokoSuiteBackup"
|
||||
COM_MOKOSUITEBACKUP_CONFIGURATION="MokoSuiteBackup Options"
|
||||
COM_MOKOJOOMBACKUP_DESCRIPTION="Full-site backup and restore for Joomla — database, files, and configuration."
|
||||
COM_MOKOJOOMBACKUP_SUBMENU_DASHBOARD="Dashboard"
|
||||
COM_MOKOJOOMBACKUP_SUBMENU_BACKUPS="Backup Records"
|
||||
|
||||
@@ -7,17 +7,18 @@
|
||||
-->
|
||||
<extension type="component" method="upgrade">
|
||||
<!--
|
||||
IMPORTANT: a component's <name> drives the Joomla-derived extension
|
||||
element (com_ + sanitized name), so it MUST stay element-safe:
|
||||
"MokoSuiteBackup" -> com_mokosuitebackup. Do NOT apply the "Type - Name"
|
||||
display convention here — "Component - MokoSuiteBackup" derives
|
||||
com_component-mokosuitebackup, which registers a duplicate component and
|
||||
orphans the real one. Packages are exempt because they set the element
|
||||
via <packagename>; plugins/modules are exempt because <name> is only a
|
||||
display label there.
|
||||
The <element> tag PINS this extension's element to com_mokosuitebackup.
|
||||
Joomla's InstallerAdapter::getElement() reads <element> BEFORE falling
|
||||
back to <name> (libraries/src/Installer/InstallerAdapter.php), so the
|
||||
display <name> can safely use the "Type - Name" convention without the
|
||||
element being derived as com_component-mokosuitebackup (which would
|
||||
register a duplicate component and orphan the real one). Without the
|
||||
<element> tag, "Component - MokoSuiteBackup" would break the install.
|
||||
NB: the manifest filename must stay mokosuitebackup.xml (short element).
|
||||
-->
|
||||
<name>MokoSuiteBackup</name>
|
||||
<version>02.66.00</version>
|
||||
<element>com_mokosuitebackup</element>
|
||||
<name>Component - MokoSuiteBackup</name>
|
||||
<version>02.67.00</version>
|
||||
<creationDate>2026-06-02</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
/* 02.66.01 — no schema changes */
|
||||
@@ -0,0 +1 @@
|
||||
/* 02.66.02 — no schema changes */
|
||||
@@ -0,0 +1 @@
|
||||
/* 02.66.03 — no schema changes */
|
||||
@@ -0,0 +1 @@
|
||||
/* 02.66.04 — no schema changes */
|
||||
@@ -0,0 +1 @@
|
||||
/* 02.66.05 — no schema changes */
|
||||
@@ -0,0 +1 @@
|
||||
/* 02.66.06 — no schema changes */
|
||||
@@ -0,0 +1 @@
|
||||
/* 02.66.07 — no schema changes */
|
||||
@@ -0,0 +1 @@
|
||||
/* 02.67.00 — no schema changes */
|
||||
@@ -81,6 +81,19 @@ class AjaxController extends BaseController
|
||||
$engine = new SteppedBackupEngine();
|
||||
$result = $engine->runStep($sessionId);
|
||||
|
||||
/* Server-authoritative pre-action skip. When a backup that was launched as a
|
||||
pre-update / pre-uninstall front COMPLETES here, arm the one-shot skip flag
|
||||
on the SERVER — rather than relying solely on the client-side
|
||||
ajax.preupdateAck POST, which is best-effort and swallows its own failure
|
||||
in a catch(). This guarantees the imminent re-fired update/uninstall does
|
||||
not trigger a SECOND synchronous backup even if that ack never lands.
|
||||
Armed ONLY on genuine completion (done, no error), so a failed or cancelled
|
||||
backup never arms it — preserving "no successful pre-action backup ⇒ the
|
||||
server still backs up before the action". */
|
||||
if (!empty($result['done']) && empty($result['error'])) {
|
||||
$this->armPreactionSkip($this->input->getCmd('action', ''));
|
||||
}
|
||||
|
||||
$this->sendJson($result);
|
||||
}
|
||||
|
||||
@@ -116,16 +129,35 @@ class AjaxController extends BaseController
|
||||
action so an update ack never suppresses a later, unrelated uninstall.
|
||||
For a core Joomla update (no action) neither flag is set — a core
|
||||
update doesn't fire onExtensionBefore(Update|Uninstall). */
|
||||
$action = $this->app->getInput()->getCmd('action', '');
|
||||
$this->armPreactionSkip($this->app->getInput()->getCmd('action', ''));
|
||||
|
||||
$this->sendJson(['error' => false, 'message' => 'Pre-action backup acknowledged']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Arm the one-shot session skip flag for a specific pre-action, so the
|
||||
* imminent re-fired extension update/uninstall skips its synchronous
|
||||
* server-side backup exactly once (runPreActionBackup consumes it). Keyed by
|
||||
* action so an update never suppresses a later, unrelated uninstall. A blank
|
||||
* or unknown action (core Joomla update, manual "Backup Now") arms nothing.
|
||||
*
|
||||
* Called from two places: ajax.step on genuine completion (authoritative) and
|
||||
* ajax.preupdateAck (best-effort client ack) — either one arming the flag is
|
||||
* enough, and re-arming it is harmless.
|
||||
*
|
||||
* Stores the unix time it was armed (not a bare bool) so the plugin can honour
|
||||
* the skip only within a short TTL and never let a stale flag from an abandoned
|
||||
* backup suppress a genuine, unrelated pre-action backup later in the session.
|
||||
*/
|
||||
private function armPreactionSkip(string $action): void
|
||||
{
|
||||
$session = Factory::getSession();
|
||||
|
||||
if ($action === 'update') {
|
||||
$session->set('mokosuitebackup.skip_preaction_backup_before_update', true);
|
||||
$session->set('mokosuitebackup.skip_preaction_backup_before_update', time());
|
||||
} elseif ($action === 'uninstall') {
|
||||
$session->set('mokosuitebackup.skip_preaction_backup_before_uninstall', true);
|
||||
$session->set('mokosuitebackup.skip_preaction_backup_before_uninstall', time());
|
||||
}
|
||||
|
||||
$this->sendJson(['error' => false, 'message' => 'Pre-action backup acknowledged']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -349,7 +349,11 @@ $this->getDocument()->addStyleSheet(Uri::root(true) . '/media/com_mokosuitebacku
|
||||
|
||||
var done = false;
|
||||
while (!done && !cancelled) {
|
||||
var step = await post({ task: 'ajax.step', session_id: init.session_id });
|
||||
/* Pass the pre-action so the SERVER can arm the one-shot skip flag the
|
||||
moment this backup completes (see AjaxController::step) — the black
|
||||
"update is running" overlay then never fronts a second backup even
|
||||
if the completion ack POST below fails to land. */
|
||||
var step = await post({ task: 'ajax.step', session_id: init.session_id, action: CFG.action || '' });
|
||||
|
||||
if (!step || step.error) {
|
||||
throw new Error((step && step.message) || 'Backup step failed');
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
-->
|
||||
<extension type="module" client="administrator" method="upgrade">
|
||||
<name>Module - MokoSuiteBackup - cPanel</name>
|
||||
<version>02.66.00</version>
|
||||
<version>02.67.00</version>
|
||||
<creationDate>2026-06-23</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
-->
|
||||
<extension type="plugin" group="actionlog" method="upgrade">
|
||||
<name>Action Log - MokoSuiteBackup</name>
|
||||
<version>02.66.00</version>
|
||||
<version>02.67.00</version>
|
||||
<creationDate>2026-06-04</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
-->
|
||||
<extension type="plugin" group="console" method="upgrade">
|
||||
<name>Console - MokoSuiteBackup</name>
|
||||
<version>02.66.00</version>
|
||||
<version>02.67.00</version>
|
||||
<creationDate>2026-06-04</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
-->
|
||||
<extension type="plugin" group="content" method="upgrade">
|
||||
<name>Content - MokoSuiteBackup</name>
|
||||
<version>02.66.00</version>
|
||||
<version>02.67.00</version>
|
||||
<creationDate>2026-06-04</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<extension type="plugin" group="quickicon" method="upgrade">
|
||||
<name>Quick Icon - MokoSuiteBackup</name>
|
||||
<version>02.66.00</version>
|
||||
<version>02.67.00</version>
|
||||
<creationDate>2026-06-02</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
-->
|
||||
<extension type="plugin" group="system" method="upgrade">
|
||||
<name>System - MokoSuiteBackup</name>
|
||||
<version>02.66.00</version>
|
||||
<version>02.67.00</version>
|
||||
<creationDate>2026-06-02</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
|
||||
@@ -35,6 +35,17 @@ final class MokoSuiteBackup extends CMSPlugin implements SubscriberInterface
|
||||
/** @var array<string,bool> Per-request cache of the one-shot "client already backed up" skip flag. */
|
||||
private array $preactionSkip = [];
|
||||
|
||||
/**
|
||||
* Max age (seconds) of the client "already backed up" skip flag that this
|
||||
* plugin will honour. The flag stores the unix time it was armed (by the
|
||||
* full-screen backup's ajax.step completion / ajax.preupdateAck); the re-fired
|
||||
* update/uninstall follows within a second or two, so a small window is ample.
|
||||
* Bounding it means a backup that was run then ABANDONED (browser closed before
|
||||
* the update re-fired) cannot silently suppress a genuine, unrelated pre-action
|
||||
* backup minutes or hours later in the same session.
|
||||
*/
|
||||
private const PREACTION_SKIP_TTL = 300;
|
||||
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return [
|
||||
@@ -648,12 +659,16 @@ JS;
|
||||
$skipKey = 'mokosuitebackup.skip_preaction_' . $paramName;
|
||||
|
||||
if (!array_key_exists($paramName, $this->preactionSkip)) {
|
||||
$this->preactionSkip[$paramName] = (bool) $session->get($skipKey, false);
|
||||
$session->set($skipKey, false);
|
||||
/* The flag stores the unix time it was armed. Consume it one-shot (reset
|
||||
to 0) and honour the skip ONLY if it was armed within the TTL — a
|
||||
stale flag from an abandoned backup must not suppress a real one. */
|
||||
$armedAt = (int) $session->get($skipKey, 0);
|
||||
$session->set($skipKey, 0);
|
||||
$this->preactionSkip[$paramName] = ($armedAt > 0 && (time() - $armedAt) <= self::PREACTION_SKIP_TTL);
|
||||
}
|
||||
|
||||
if ($this->preactionSkip[$paramName]) {
|
||||
// Client already backed up; skip this whole re-fired (possibly batch) request.
|
||||
// Client already backed up (recently); skip this re-fired (possibly batch) request.
|
||||
$this->preactionRan[$paramName] = true;
|
||||
|
||||
return;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
-->
|
||||
<extension type="plugin" group="task" method="upgrade">
|
||||
<name>Task - MokoSuiteBackup</name>
|
||||
<version>02.66.00</version>
|
||||
<version>02.67.00</version>
|
||||
<creationDate>2026-06-02</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
-->
|
||||
<extension type="plugin" group="webservices" method="upgrade">
|
||||
<name>Web Services - MokoSuiteBackup</name>
|
||||
<version>02.66.00</version>
|
||||
<version>02.67.00</version>
|
||||
<creationDate>2026-06-02</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<extension type="package" method="upgrade">
|
||||
<name>Package - MokoSuiteBackup</name>
|
||||
<packagename>mokosuitebackup</packagename>
|
||||
<version>02.66.00</version>
|
||||
<version>02.67.00</version>
|
||||
<creationDate>2026-06-02</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
|
||||
Reference in New Issue
Block a user