From 2af264171212d41b857bb0cc80e73d8bd8f55701 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sun, 5 Jul 2026 18:31:06 -0500 Subject: [PATCH 1/2] fix(installer): self-heal admin menu; fix alias collision; short-constant label MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fallout of the duplicate-component element bug: - Preflight now runs removeOrphanedComponent() BEFORE the component install recreates its menu, so the orphan's "Backup" menu (alias "backup") no longer collides ("The alias backup is already being used by the Backup menu item"). - ensureSubmenuItems() recreates the top-level "Backup" menu when it is missing (via new createTopMenu()) instead of bailing out — so a failed install that deleted the parent menu no longer leaves Backup gone from the admin menu (which also broke the cPanel module and MokoSuiteClient component detection). - The top-level menu label now uses the short constant COM_MOKOJOOMBACKUP_SHORT (manifest + enforced/normalized in the script). Claude-Session: https://claude.ai/code/session_01WbGBN9VyRK61zczYWcCQ2i --- CHANGELOG.md | 1 + .../com_mokosuitebackup/mokosuitebackup.xml | 2 +- source/script.php | 113 +++++++++++++++--- 3 files changed, 98 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26def769..c95165fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## [Unreleased] ### Fixed +- Admin menu / duplicate-component fallout: (a) the orphaned `com_component-mokosuitebackup` is now removed in **preflight** too, so its "Backup" menu no longer collides on install ("The alias backup is already being used"); (b) `ensureSubmenuItems()` **recreates the top-level "Backup" menu** if it was deleted, instead of giving up — so Backup no longer disappears from the admin menu (and the cPanel module / MokoSuiteClient can find it again); (c) the component menu label now uses the short constant `COM_MOKOJOOMBACKUP_SHORT`. (#213 fallout) - Installer no longer aborts on MySQL 8 with "This command is not supported in the prepared statement protocol yet" (error 1295). The legacy remote-column purge migration (`02.56.01.sql`) used `PREPARE`/`EXECUTE`/`DEALLOCATE`, which Joomla's installer rejects; the drop now runs in the package installer script via an INFORMATION_SCHEMA-gated plain `ALTER` (portable across MariaDB and MySQL 8). (#213 update path) ## [02.57.00] --- 2026-07-05 diff --git a/source/packages/com_mokosuitebackup/mokosuitebackup.xml b/source/packages/com_mokosuitebackup/mokosuitebackup.xml index 6fb65dbe..04e1fc5a 100644 --- a/source/packages/com_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/com_mokosuitebackup/mokosuitebackup.xml @@ -47,7 +47,7 @@ - Backup + COM_MOKOJOOMBACKUP_SHORT backupDownloadKey(); } + /* Remove any orphaned mis-registered component BEFORE the component install + recreates its admin menu. The orphan (element com_component-mokosuitebackup) + owns a "Backup" menu with alias "backup"; if it survives, the real + component's menu creation collides ("The alias backup is already being used") + and the whole install aborts. */ + $this->removeOrphanedComponent(); + return true; } @@ -622,23 +629,7 @@ class Pkg_MokoSuiteBackupInstallerScript try { $db = Factory::getDbo(); - /* Find the parent menu item for our component */ - $query = $db->getQuery(true) - ->select([$db->quoteName('id'), $db->quoteName('menutype')]) - ->from($db->quoteName('#__menu')) - ->where($db->quoteName('client_id') . ' = 1') - ->where($db->quoteName('level') . ' = 1') - ->where($db->quoteName('link') . ' LIKE ' . $db->quote('index.php?option=com_mokosuitebackup%')) - ->setLimit(1); - $db->setQuery($query); - $parent = $db->loadObject(); - - if (!$parent) { - error_log('MokoSuiteBackup: ensureSubmenuItems() — parent menu item not found'); - return; - } - - /* Get the component extension_id */ + /* Component extension_id first — needed to (re)create the parent menu. */ $query = $db->getQuery(true) ->select($db->quoteName('extension_id')) ->from($db->quoteName('#__extensions')) @@ -653,6 +644,41 @@ class Pkg_MokoSuiteBackupInstallerScript return; } + /* Find the top-level "Backup" parent menu item for our component */ + $query = $db->getQuery(true) + ->select([$db->quoteName('id'), $db->quoteName('menutype')]) + ->from($db->quoteName('#__menu')) + ->where($db->quoteName('client_id') . ' = 1') + ->where($db->quoteName('level') . ' = 1') + ->where($db->quoteName('link') . ' LIKE ' . $db->quote('index.php?option=com_mokosuitebackup%')) + ->setLimit(1); + $db->setQuery($query); + $parent = $db->loadObject(); + + /* Self-heal: if the top-level menu was deleted (e.g. by a failed install + after the duplicate-component mess), recreate it — otherwise the whole + Backup menu stays gone and dependents (cPanel module, MokoSuiteClient) + can't locate the component. */ + if (!$parent) { + $parent = $this->createTopMenu($componentId); + + if (!$parent) { + error_log('MokoSuiteBackup: ensureSubmenuItems() — parent menu missing and could not be created'); + return; + } + } + + /* Keep the top-level menu label on the short constant and owned by the + real component. */ + $db->setQuery( + $db->getQuery(true) + ->update($db->quoteName('#__menu')) + ->set($db->quoteName('title') . ' = ' . $db->quote('COM_MOKOJOOMBACKUP_SHORT')) + ->set($db->quoteName('component_id') . ' = ' . (int) $componentId) + ->where($db->quoteName('id') . ' = ' . (int) $parent->id) + ); + $db->execute(); + foreach ($submenus as $submenu) { /* Check if this submenu item already exists */ $query = $db->getQuery(true) @@ -718,6 +744,59 @@ class Pkg_MokoSuiteBackupInstallerScript } } + /** + * Create the top-level "Backup" admin menu item for the component when it is + * missing (deleted by a failed install / the duplicate-component fallout). + * Label uses the short constant. Returns a lightweight {id, menutype} object, + * or null on failure. + * + * @param int $componentId Extension id of com_mokosuitebackup + * + * @return object|null + */ + private function createTopMenu(int $componentId): ?object + { + try { + $table = Factory::getApplication() + ->bootComponent('com_menus') + ->getMVCFactory() + ->createTable('Menu', 'Administrator'); + + $table->menutype = 'main'; + $table->title = 'COM_MOKOJOOMBACKUP_SHORT'; + $table->alias = 'backup'; + $table->link = 'index.php?option=com_mokosuitebackup'; + $table->type = 'component'; + $table->published = 1; + $table->parent_id = 1; + $table->level = 1; + $table->component_id = $componentId; + $table->client_id = 1; + $table->img = 'class:archive'; + $table->params = '{}'; + $table->language = '*'; + $table->access = 1; + + $table->setLocation(1, 'last-child'); + + if (!$table->check() || !$table->store()) { + error_log('MokoSuiteBackup: createTopMenu() failed: ' . $table->getError()); + + return null; + } + + $obj = new \stdClass(); + $obj->id = (int) $table->id; + $obj->menutype = 'main'; + + return $obj; + } catch (\Throwable $e) { + error_log('MokoSuiteBackup: createTopMenu() exception: ' . $e->getMessage()); + + return null; + } + } + private function fixPackageClientId(): void { try { From 1c420b2277c31521fa757524a7ce29f578b4d36e Mon Sep 17 00:00:00 2001 From: "mokogitea-actions[bot]" Date: Sun, 5 Jul 2026 23:31:24 +0000 Subject: [PATCH 2/2] chore(version): pre-release bump to 02.57.05-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.57.05.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.57.05.sql diff --git a/.mokogitea/workflows/issue-branch.yml b/.mokogitea/workflows/issue-branch.yml index 97cb4f09..41b45a86 100644 --- a/.mokogitea/workflows/issue-branch.yml +++ b/.mokogitea/workflows/issue-branch.yml @@ -5,7 +5,7 @@ # FILE INFORMATION # DEFGROUP: MokoGitea.Workflow # INGROUP: mokocli.Automation -# VERSION: 02.57.04 +# VERSION: 02.57.05 # BRIEF: Auto-create feature branch when an issue is opened name: "Universal: Issue Branch" diff --git a/SECURITY.md b/SECURITY.md index 8d010a9e..53020c69 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.57.04 +VERSION: 02.57.05 BRIEF: Security vulnerability reporting and handling policy --> diff --git a/source/packages/com_mokosuitebackup/mokosuitebackup.xml b/source/packages/com_mokosuitebackup/mokosuitebackup.xml index 04e1fc5a..3b32d925 100644 --- a/source/packages/com_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/com_mokosuitebackup/mokosuitebackup.xml @@ -17,7 +17,7 @@ display label there. --> MokoSuiteBackup - 02.57.04 + 02.57.05 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/com_mokosuitebackup/sql/updates/mysql/02.57.05.sql b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.57.05.sql new file mode 100644 index 00000000..a21e1bd2 --- /dev/null +++ b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.57.05.sql @@ -0,0 +1 @@ +/* 02.57.05 — 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 d4b81573..3c11ba40 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 @@ --> Module - MokoSuiteBackup - cPanel - 02.57.04 + 02.57.05 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 7a6418bc..c2059c79 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.57.04 + 02.57.05 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 359bb07a..d2d09d64 100644 --- a/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Console - MokoSuiteBackup - 02.57.04 + 02.57.05 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 bcacee04..2e1d2b3d 100644 --- a/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Content - MokoSuiteBackup - 02.57.04 + 02.57.05 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 4f17d8f3..9f1d3957 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.57.04 + 02.57.05 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 a8b7f693..00882897 100644 --- a/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> System - MokoSuiteBackup - 02.57.04 + 02.57.05 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 f2c281ce..575fec88 100644 --- a/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Task - MokoSuiteBackup - 02.57.04 + 02.57.05 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 e9863d3b..f2ca7f99 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.57.04 + 02.57.05 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/pkg_mokosuitebackup.xml b/source/pkg_mokosuitebackup.xml index dfa5e0e0..19b7388d 100644 --- a/source/pkg_mokosuitebackup.xml +++ b/source/pkg_mokosuitebackup.xml @@ -8,7 +8,7 @@ Package - MokoSuiteBackup mokosuitebackup - 02.57.04 + 02.57.05 2026-06-02 Moko Consulting hello@mokoconsulting.tech