Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cc85b69e41 | |||
| 129be7ef9d | |||
| 14392de078 | |||
| 8bdadb68c2 | |||
| bcc4054ced | |||
| 0cba7f81e8 | |||
| 2688ea352b | |||
| 39d94a31d6 | |||
| 1029e40908 | |||
| ec3094385f | |||
| 4a2bb1b19d | |||
| 3c5ad43e97 | |||
| f92e5227dc | |||
| 9db54ac60c | |||
| 0c7c3552ed | |||
| 351321161a | |||
| d2cc234fce | |||
| 2389df8670 | |||
| 55f29498b0 | |||
| a5397c0f16 | |||
| c0792a6ba0 | |||
| 7a3f0f914e | |||
| cc7f18ae45 | |||
| 4cf8f8243d | |||
| efb28fa386 | |||
| 68043c9a37 | |||
| e5558fad26 | |||
| 60c5c00333 | |||
| f9169fd9f7 | |||
| d69db6fac3 |
@@ -3,7 +3,7 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# FILE INFORMATION
|
||||
# DEFGROUP: Gitea.Workflow
|
||||
# DEFGROUP: MokoGitea.Workflow
|
||||
# INGROUP: mokocli.Release
|
||||
# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Generic
|
||||
# PATH: /.mokogitea/workflows/auto-bump.yml
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# FILE INFORMATION
|
||||
# DEFGROUP: Gitea.Workflow
|
||||
# DEFGROUP: MokoGitea.Workflow
|
||||
# INGROUP: mokocli.Release
|
||||
# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Generic
|
||||
# PATH: /.mokogitea/workflows/auto-release.yml
|
||||
@@ -142,8 +142,8 @@ jobs:
|
||||
run: |
|
||||
git fetch origin rc
|
||||
git checkout rc
|
||||
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
|
||||
git config --local user.name "gitea-actions[bot]"
|
||||
git config --local user.email "mokogitea-actions[bot]@mokoconsulting.tech"
|
||||
git config --local user.name "mokogitea-actions[bot]"
|
||||
git remote set-url origin "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
|
||||
|
||||
- name: Publish RC release
|
||||
@@ -214,8 +214,8 @@ jobs:
|
||||
|
||||
- name: Configure git for bot pushes
|
||||
run: |
|
||||
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
|
||||
git config --local user.name "gitea-actions[bot]"
|
||||
git config --local user.email "mokogitea-actions[bot]@mokoconsulting.tech"
|
||||
git config --local user.name "mokogitea-actions[bot]"
|
||||
git remote set-url origin "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
|
||||
|
||||
- name: Check for merge conflict markers
|
||||
@@ -380,10 +380,13 @@ jobs:
|
||||
import sys
|
||||
version, date = sys.argv[1], sys.argv[2]
|
||||
content = open('CHANGELOG.md').read()
|
||||
old = '## [Unreleased]'
|
||||
new = f'## [Unreleased]\n\n## [{version}] --- {date}'
|
||||
content = content.replace(old, new, 1)
|
||||
open('CHANGELOG.md', 'w').write(content)
|
||||
marker = f'## [{version}]'
|
||||
# Idempotent: only promote when this version header isn't already present,
|
||||
# otherwise re-runs (or same-version builds) create empty duplicate headers.
|
||||
if marker not in content:
|
||||
new = f'## [Unreleased]\n\n{marker} --- {date}'
|
||||
content = content.replace('## [Unreleased]', new, 1)
|
||||
open('CHANGELOG.md', 'w').write(content)
|
||||
" "$VERSION" "$DATE"
|
||||
git add CHANGELOG.md
|
||||
git commit -m "chore: promote changelog [Unreleased] → [${VERSION}]" || true
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# FILE INFORMATION
|
||||
# DEFGROUP: Gitea.Workflow
|
||||
# DEFGROUP: MokoGitea.Workflow
|
||||
# INGROUP: MokoStandards.Universal
|
||||
# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Generic
|
||||
# PATH: /.mokogitea/workflows/branch-cleanup.yml
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# FILE INFORMATION
|
||||
# DEFGROUP: Gitea.Workflow
|
||||
# DEFGROUP: MokoGitea.Workflow
|
||||
# INGROUP: MokoStandards.Cascade
|
||||
# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Generic
|
||||
# PATH: /.mokogitea/workflows/cascade-dev.yml
|
||||
@@ -71,7 +71,7 @@ jobs:
|
||||
echo "Reusing open cascade PR #${PR}"
|
||||
fi
|
||||
|
||||
# 3. wait for Gitea to compute mergeability (conflict detection)
|
||||
# 3. wait for MokoGitea to compute mergeability (conflict detection)
|
||||
MERGEABLE=""
|
||||
for _ in 1 2 3 4 5 6; do
|
||||
MERGEABLE=$(curl -sf -H "$AUTH" "${API}/pulls/${PR}" | jqnum mergeable)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# FILE INFORMATION
|
||||
# DEFGROUP: Gitea.Workflow
|
||||
# DEFGROUP: MokoGitea.Workflow
|
||||
# INGROUP: MokoStandards.CI
|
||||
# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Generic
|
||||
# PATH: /.mokogitea/workflows/ci-generic.yml
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# FILE INFORMATION
|
||||
# DEFGROUP: Gitea.Workflow
|
||||
# DEFGROUP: MokoGitea.Workflow
|
||||
# INGROUP: mokocli.Universal
|
||||
# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Generic
|
||||
# PATH: /.mokogitea/workflows/ci-issue-reporter.yml
|
||||
# VERSION: 01.00.00
|
||||
# BRIEF: Reusable workflow — creates/updates a Gitea issue when a CI gate fails.
|
||||
# BRIEF: Reusable workflow — creates/updates a MokoGitea issue when a CI gate fails.
|
||||
# Clones MokoCLI and runs cli/ci_issue_reporter.sh.
|
||||
|
||||
name: "Universal: CI Issue Reporter"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# FILE INFORMATION
|
||||
# DEFGROUP: Gitea.Workflow
|
||||
# DEFGROUP: MokoGitea.Workflow
|
||||
# INGROUP: MokoStandards.Maintenance
|
||||
# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards
|
||||
# PATH: /.mokogitea/workflows/cleanup.yml
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# FILE INFORMATION
|
||||
# DEFGROUP: Gitea.Workflow
|
||||
# DEFGROUP: MokoGitea.Workflow
|
||||
# INGROUP: MokoStandards.Security
|
||||
# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards-API
|
||||
# PATH: /.mokogitea/workflows/gitleaks.yml
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# FILE INFORMATION
|
||||
# DEFGROUP: Gitea.Workflow
|
||||
# DEFGROUP: MokoGitea.Workflow
|
||||
# INGROUP: mokocli.Automation
|
||||
# VERSION: 02.56.07
|
||||
# VERSION: 02.56.14
|
||||
# BRIEF: Auto-create feature branch when an issue is opened
|
||||
|
||||
name: "Universal: Issue Branch"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# FILE INFORMATION
|
||||
# DEFGROUP: Gitea.Workflow
|
||||
# DEFGROUP: MokoGitea.Workflow
|
||||
# INGROUP: MokoStandards.Notifications
|
||||
# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards
|
||||
# PATH: /.mokogitea/workflows/notify.yml
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# FILE INFORMATION
|
||||
# DEFGROUP: Gitea.Workflow
|
||||
# DEFGROUP: MokoGitea.Workflow
|
||||
# INGROUP: mokocli.CI
|
||||
# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Generic
|
||||
# PATH: /.mokogitea/workflows/pr-check.yml
|
||||
@@ -350,7 +350,7 @@ jobs:
|
||||
joomla)
|
||||
MANIFEST=$(find . -maxdepth 3 -name "*.xml" ! -path "./.git/*" -exec grep -l '<extension' {} \; 2>/dev/null | head -1)
|
||||
if [ -z "$MANIFEST" ]; then
|
||||
echo "::warning::No Joomla manifest found (WaaS site)"
|
||||
echo "::warning::No Joomla manifest found (MokoSuite site)"
|
||||
exit 0
|
||||
fi
|
||||
echo "Manifest: ${MANIFEST}"
|
||||
@@ -363,7 +363,7 @@ jobs:
|
||||
# Block legacy raw/branch update server URLs on MokoGitea
|
||||
RAW_URLS=$(grep -n 'raw/branch' "$MANIFEST" | grep -i 'mokoconsulting\|mokogitea\|git\.mokoconsulting\.tech' || true)
|
||||
if [ -n "$RAW_URLS" ]; then
|
||||
echo "::error::Manifest contains legacy raw/branch update server URL on MokoGitea. Use the Gitea Pages URL instead (e.g. /{REPO}/updates.xml not /{REPO}/raw/branch/main/updates.xml)"
|
||||
echo "::error::Manifest contains legacy raw/branch update server URL on MokoGitea. Use the MokoGitea Pages URL instead (e.g. /{REPO}/updates.xml not /{REPO}/raw/branch/main/updates.xml)"
|
||||
echo "$RAW_URLS"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# FILE INFORMATION
|
||||
# DEFGROUP: Gitea.Workflow
|
||||
# DEFGROUP: MokoGitea.Workflow
|
||||
# INGROUP: mokocli.Release
|
||||
# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Generic
|
||||
# PATH: /.mokogitea/workflows/pre-release.yml
|
||||
@@ -156,8 +156,8 @@ jobs:
|
||||
fi
|
||||
|
||||
# Commit version bump
|
||||
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
|
||||
git config --local user.name "gitea-actions[bot]"
|
||||
git config --local user.email "mokogitea-actions[bot]@mokoconsulting.tech"
|
||||
git config --local user.name "mokogitea-actions[bot]"
|
||||
git remote set-url origin "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
|
||||
git add -A
|
||||
git diff --cached --quiet || {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# FILE INFORMATION
|
||||
# DEFGROUP: Gitea.Workflow
|
||||
# DEFGROUP: MokoGitea.Workflow
|
||||
# INGROUP: mokocli.Universal
|
||||
# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Generic
|
||||
# PATH: /.mokogitea/workflows/rc-revert.yml
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# FILE INFORMATION
|
||||
# DEFGROUP: Gitea.Workflow
|
||||
# DEFGROUP: MokoGitea.Workflow
|
||||
# INGROUP: mokocli.Validation
|
||||
# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Generic
|
||||
# PATH: /.mokogitea/workflows/repo-health.yml
|
||||
@@ -88,7 +88,7 @@ jobs:
|
||||
|
||||
# Hardcoded authorized users — always allowed
|
||||
case "$ACTOR" in
|
||||
jmiller|gitea-actions[bot])
|
||||
jmiller|mokogitea-actions[bot])
|
||||
ALLOWED=true
|
||||
PERMISSION=admin
|
||||
METHOD="hardcoded allowlist"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# FILE INFORMATION
|
||||
# DEFGROUP: Gitea.Workflow.Template
|
||||
# DEFGROUP: MokoGitea.Workflow.Template
|
||||
# INGROUP: MokoStandards.CI
|
||||
# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Joomla
|
||||
# PATH: /.mokogitea/workflows/version-set.yml
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# FILE INFORMATION
|
||||
# DEFGROUP: Gitea.Workflow
|
||||
# DEFGROUP: MokoGitea.Workflow
|
||||
# INGROUP: mokocli.Universal
|
||||
# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Generic
|
||||
# PATH: /.mokogitea/workflows/workflow-sync-trigger.yml
|
||||
|
||||
+23
-8
@@ -1,15 +1,30 @@
|
||||
# Changelog
|
||||
## [Unreleased]
|
||||
|
||||
## [02.56.07] --- 2026-07-05
|
||||
### Fixed
|
||||
- Release automation: the changelog-promote step is now idempotent — it only inserts a `## [version]` header when that version isn't already present, preventing the empty, duplicated version headers that repeated/same-version builds were producing. (workflow)
|
||||
|
||||
## [02.56.11] --- 2026-07-05
|
||||
|
||||
### Fixed
|
||||
- Package `postflight` now removes the orphaned `com_component-mokosuitebackup` registration (stray extension record, admin menu items, schema rows, and `administrator/` folder) left behind by the old "Type - Name" component `<name>` — self-healing on update so affected sites reconcile to the real `com_mokosuitebackup`. (#213 follow-up)
|
||||
|
||||
## [02.56.08] --- 2026-07-05
|
||||
|
||||
### Fixed
|
||||
- Component manifest `<name>` reverted to the element-safe `MokoSuiteBackup`. The "Type - Name" convention derived element `com_component-mokosuitebackup`, registering a duplicate component and leaving the real `com_mokosuitebackup` orphaned on the old version. (#213)
|
||||
|
||||
## [02.56.07] --- 2026-07-05
|
||||
|
||||
## [02.56.05] --- 2026-07-05
|
||||
### Security
|
||||
- Mask the FTP password in `AjaxController::maskSecrets()`/`mergeExistingSecrets()` — stored FTP remotes no longer leak their password via `listRemotes`. (#169)
|
||||
- Stop the API single-item view (`Backups/JsonapiView`) leaking the server `absolute_path`. (#187)
|
||||
- SFTP uploader uses `StrictHostKeyChecking=accept-new` instead of `no`. (#182)
|
||||
|
||||
## [02.56.05] --- 2026-07-05
|
||||
|
||||
## [02.56.00] --- 2026-07-04
|
||||
|
||||
|
||||
## [02.56.00] --- 2026-07-04
|
||||
### Fixed
|
||||
- `DatabaseDumper` writes a real newline after `DROP TABLE` (was a literal `\n`). (#179)
|
||||
- Profile-picker forms order by `id` instead of the dropped `ordering` column. (#180)
|
||||
- `uninstall.mysql.sql` now drops the snapshots table. (#181)
|
||||
- CLI snapshot delete uses the `data_file` column (was non-existent `file_path`). (#184)
|
||||
- Remove the duplicate pre-update backup (content plugin no longer subscribes to `onExtensionBeforeUpdate`). (#186)
|
||||
- `DatabaseImporter` collects non-fatal statement errors (`getErrors()`/`hasErrors()`). (#188)
|
||||
|
||||
+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.56.07
|
||||
VERSION: 02.56.14
|
||||
BRIEF: Security vulnerability reporting and handling policy
|
||||
-->
|
||||
|
||||
|
||||
@@ -6,8 +6,18 @@
|
||||
* @license GNU General Public License version 3 or later; see LICENSE
|
||||
-->
|
||||
<extension type="component" method="upgrade">
|
||||
<name>Component - MokoSuiteBackup</name>
|
||||
<version>02.56.07</version>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<name>MokoSuiteBackup</name>
|
||||
<version>02.56.14</version>
|
||||
<creationDate>2026-06-02</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
/* 02.56.08 — no schema changes */
|
||||
@@ -0,0 +1 @@
|
||||
/* 02.56.11 — no schema changes */
|
||||
@@ -0,0 +1 @@
|
||||
/* 02.56.14 — no schema changes */
|
||||
@@ -8,7 +8,7 @@
|
||||
-->
|
||||
<extension type="module" client="administrator" method="upgrade">
|
||||
<name>Module - MokoSuiteBackup - cPanel</name>
|
||||
<version>02.56.07</version>
|
||||
<version>02.56.14</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.56.07</version>
|
||||
<version>02.56.14</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.56.07</version>
|
||||
<version>02.56.14</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.56.07</version>
|
||||
<version>02.56.14</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.56.07</version>
|
||||
<version>02.56.14</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.56.07</version>
|
||||
<version>02.56.14</version>
|
||||
<creationDate>2026-06-02</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
-->
|
||||
<extension type="plugin" group="task" method="upgrade">
|
||||
<name>Task - MokoSuiteBackup</name>
|
||||
<version>02.56.07</version>
|
||||
<version>02.56.14</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.56.07</version>
|
||||
<version>02.56.14</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.56.07</version>
|
||||
<version>02.56.14</version>
|
||||
<creationDate>2026-06-02</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
|
||||
@@ -172,6 +172,11 @@ class Pkg_MokoSuiteBackupInstallerScript
|
||||
/* Migrate profiles with old default backup_dir values to [DEFAULT_DIR] placeholder */
|
||||
$this->migrateDefaultBackupDir();
|
||||
|
||||
/* Remove the orphaned mis-registered component (element
|
||||
com_component-mokosuitebackup) left behind when the component <name>
|
||||
briefly used the "Type - Name" convention. Self-healing on every update. */
|
||||
$this->removeOrphanedComponent();
|
||||
|
||||
/* Install completion notice (install and update) */
|
||||
$this->installSuccessful();
|
||||
|
||||
@@ -192,6 +197,107 @@ class Pkg_MokoSuiteBackupInstallerScript
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the orphaned component registration created when the component
|
||||
* <name> briefly used the "Type - Name" display convention. Joomla derives a
|
||||
* component's element from its <name>, so "Component - MokoSuiteBackup"
|
||||
* produced element com_component-mokosuitebackup — its own extension record,
|
||||
* admin menu items, schema rows and administrator/ folder — orphaning the real
|
||||
* com_mokosuitebackup on the old version. This reconciles affected sites on
|
||||
* update. Idempotent and non-fatal: does nothing when no orphan exists.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function removeOrphanedComponent(): void
|
||||
{
|
||||
try {
|
||||
$db = Factory::getDbo();
|
||||
|
||||
$query = $db->getQuery(true)
|
||||
->select($db->quoteName(['extension_id', 'element']))
|
||||
->from($db->quoteName('#__extensions'))
|
||||
->where($db->quoteName('type') . ' = ' . $db->quote('component'))
|
||||
->where($db->quoteName('client_id') . ' = 1')
|
||||
->where($db->quoteName('element') . ' LIKE ' . $db->quote('%component%mokosuitebackup%'))
|
||||
->where($db->quoteName('element') . ' <> ' . $db->quote('com_mokosuitebackup'));
|
||||
$db->setQuery($query);
|
||||
$orphans = $db->loadObjectList();
|
||||
|
||||
if (empty($orphans)) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($orphans as $orphan) {
|
||||
$id = (int) $orphan->extension_id;
|
||||
|
||||
/* Admin menu items owned by the orphan component */
|
||||
$db->setQuery(
|
||||
$db->getQuery(true)
|
||||
->delete($db->quoteName('#__menu'))
|
||||
->where($db->quoteName('component_id') . ' = ' . $id)
|
||||
)->execute();
|
||||
|
||||
/* Schema-version rows */
|
||||
$db->setQuery(
|
||||
$db->getQuery(true)
|
||||
->delete($db->quoteName('#__schemas'))
|
||||
->where($db->quoteName('extension_id') . ' = ' . $id)
|
||||
)->execute();
|
||||
|
||||
/* Update-site mapping (leave #__update_sites; harmless if orphaned) */
|
||||
$db->setQuery(
|
||||
$db->getQuery(true)
|
||||
->delete($db->quoteName('#__update_sites_extensions'))
|
||||
->where($db->quoteName('extension_id') . ' = ' . $id)
|
||||
)->execute();
|
||||
|
||||
/* The bogus extension record itself */
|
||||
$db->setQuery(
|
||||
$db->getQuery(true)
|
||||
->delete($db->quoteName('#__extensions'))
|
||||
->where($db->quoteName('extension_id') . ' = ' . $id)
|
||||
)->execute();
|
||||
|
||||
/* The stray admin component folder on disk */
|
||||
$this->deleteFolderRecursive(JPATH_ADMINISTRATOR . '/components/' . $orphan->element);
|
||||
|
||||
Factory::getApplication()->enqueueMessage(
|
||||
'MokoSuiteBackup: removed orphaned component registration "'
|
||||
. htmlspecialchars($orphan->element, ENT_QUOTES, 'UTF-8') . '".',
|
||||
'info'
|
||||
);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
/* Never block the install/update over best-effort cleanup */
|
||||
Log::add('MokoSuiteBackup orphan-component cleanup failed: ' . $e->getMessage(), Log::WARNING, 'jerror');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively delete a directory (version-independent, no Folder dependency).
|
||||
*
|
||||
* @param string $dir Absolute path
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function deleteFolderRecursive(string $dir): void
|
||||
{
|
||||
if ($dir === '' || !is_dir($dir)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$items = new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS),
|
||||
\RecursiveIteratorIterator::CHILD_FIRST
|
||||
);
|
||||
|
||||
foreach ($items as $item) {
|
||||
$item->isDir() ? @rmdir($item->getPathname()) : @unlink($item->getPathname());
|
||||
}
|
||||
|
||||
@rmdir($dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a cryptographically random webcron secret word on fresh install.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user