Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2fd61431a5 | |||
| d2546db9de | |||
| 476d79cca7 | |||
| a7b2716d20 | |||
| 59dffdb38f | |||
| d26f938c26 | |||
| 9b90738e54 | |||
| b7dc38dcbc | |||
| ef6d3f4dc9 | |||
| c6826ebc45 | |||
| 6a2788786e | |||
| 78e507e034 | |||
| c842998d1a | |||
| cc1c84f662 | |||
| 2b66d4a9d1 | |||
| 7eb56e07a9 |
+16
-16
@@ -1,4 +1,4 @@
|
|||||||
# MokoSuiteBackup
|
# MokoJoomBackup
|
||||||
|
|
||||||
Full-site backup and restore for Joomla — database, files, and configuration. Replaces Akeeba Backup Pro.
|
Full-site backup and restore for Joomla — database, files, and configuration. Replaces Akeeba Backup Pro.
|
||||||
|
|
||||||
@@ -6,10 +6,10 @@ Full-site backup and restore for Joomla — database, files, and configuration.
|
|||||||
|
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
|---|---|
|
|---|---|
|
||||||
| **Package** | `pkg_mokosuitebackup` |
|
| **Package** | `pkg_mokojoombackup` |
|
||||||
| **Language** | PHP 8.1+ |
|
| **Language** | PHP 8.1+ |
|
||||||
| **Branch** | develop on `dev`, merge to `main` (protected) |
|
| **Branch** | develop on `dev`, merge to `main` (protected) |
|
||||||
| **Wiki** | [MokoSuiteBackup Wiki](https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteBackup/wiki) |
|
| **Wiki** | [MokoJoomBackup Wiki](https://git.mokoconsulting.tech/MokoConsulting/MokoJoomBackup/wiki) |
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
@@ -26,32 +26,32 @@ composer install # Install PHP dependencies
|
|||||||
|
|
||||||
Joomla **package** with four sub-extensions:
|
Joomla **package** with four sub-extensions:
|
||||||
|
|
||||||
### com_mokosuitebackup (Component)
|
### com_mokojoombackup (Component)
|
||||||
- Admin backend for managing backup profiles and records
|
- Admin backend for managing backup profiles and records
|
||||||
- Backup engine: `Engine/BackupEngine`, `Engine/DatabaseDumper`, `Engine/FileScanner`, `Engine/Archiver`
|
- Backup engine: `Engine/BackupEngine`, `Engine/DatabaseDumper`, `Engine/FileScanner`, `Engine/Archiver`
|
||||||
- Joomla 4/5 MVC: Controllers, Models, Views, Tables
|
- Joomla 4/5 MVC: Controllers, Models, Views, Tables
|
||||||
- Namespace: `Joomla\Component\MokoSuiteBackup\Administrator`
|
- Namespace: `Joomla\Component\MokoJoomBackup\Administrator`
|
||||||
- DB tables: `#__mokosuitebackup_profiles`, `#__mokosuitebackup_records`
|
- DB tables: `#__mokojoombackup_profiles`, `#__mokojoombackup_records`
|
||||||
- CLI: `cli/mokosuitebackup.php` for cron-based backups
|
- CLI: `cli/mokojoombackup.php` for cron-based backups
|
||||||
|
|
||||||
### plg_system_mokosuitebackup (System Plugin)
|
### plg_system_mokojoombackup (System Plugin)
|
||||||
- Cleanup of expired backup archives (age + count limits)
|
- Cleanup of expired backup archives (age + count limits)
|
||||||
- Namespace: `Joomla\Plugin\System\MokoSuiteBackup`
|
- Namespace: `Joomla\Plugin\System\MokoJoomBackup`
|
||||||
|
|
||||||
### plg_task_mokosuitebackup (Task Plugin)
|
### plg_task_mokojoombackup (Task Plugin)
|
||||||
- Integrates with Joomla's Scheduled Tasks (com_scheduler)
|
- Integrates with Joomla's Scheduled Tasks (com_scheduler)
|
||||||
- Registers "Run Backup Profile" task type
|
- Registers "Run Backup Profile" task type
|
||||||
- Namespace: `Joomla\Plugin\Task\MokoSuiteBackup`
|
- Namespace: `Joomla\Plugin\Task\MokoJoomBackup`
|
||||||
|
|
||||||
### plg_webservices_mokosuitebackup (WebServices Plugin)
|
### plg_webservices_mokojoombackup (WebServices Plugin)
|
||||||
- REST API for remote backup management (wire-compatible with mcp_mokosuitebackup)
|
- REST API for remote backup management (wire-compatible with mcp_mokojoombackup)
|
||||||
- Endpoints: backup, backups, profiles, download, delete
|
- Endpoints: backup, backups, profiles, download, delete
|
||||||
- Namespace: `Joomla\Plugin\WebServices\MokoSuiteBackup`
|
- Namespace: `Joomla\Plugin\WebServices\MokoJoomBackup`
|
||||||
|
|
||||||
### Database Schema
|
### Database Schema
|
||||||
|
|
||||||
- `#__mokosuitebackup_profiles` — backup profiles (name, description, config JSON, filters JSON)
|
- `#__mokojoombackup_profiles` — backup profiles (name, description, config JSON, filters JSON)
|
||||||
- `#__mokosuitebackup_records` — backup records (profile_id, status, origin, archive path, sizes, timestamps)
|
- `#__mokojoombackup_records` — backup records (profile_id, status, origin, archive path, sizes, timestamps)
|
||||||
|
|
||||||
## Rules
|
## Rules
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<mokoplatform xmlns="https://standards.mokoconsulting.tech/mokoplatform/1.0" schema-version="1.0">
|
<mokoplatform xmlns="https://standards.mokoconsulting.tech/mokoplatform/1.0" schema-version="1.0">
|
||||||
<identity>
|
<identity>
|
||||||
<name>MokoSuiteBackup</name>
|
<name>MokoJoomBackup</name>
|
||||||
<display-name>Package - MokoSuiteBackup</display-name>
|
<display-name>Package - MokoJoomBackup</display-name>
|
||||||
<org>MokoConsulting</org>
|
<org>MokoConsulting</org>
|
||||||
<description>Full-site backup and restore for Joomla — database, files, and configuration</description>
|
<description>Full-site backup and restore for Joomla — database, files, and configuration</description>
|
||||||
<version>01.08.17-dev</version>
|
<version>01.08.00-dev</version>
|
||||||
<license spdx="GPL-3.0-or-later">GNU General Public License v3</license>
|
<license spdx="GPL-3.0-or-later">GNU General Public License v3</license>
|
||||||
</identity>
|
</identity>
|
||||||
<governance>
|
<governance>
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
#
|
#
|
||||||
# FILE INFORMATION
|
# FILE INFORMATION
|
||||||
# DEFGROUP: Gitea.Workflow
|
# DEFGROUP: Gitea.Workflow
|
||||||
# INGROUP: mokoplatform.Release
|
# INGROUP: moko-platform.Release
|
||||||
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform
|
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
|
||||||
# PATH: /.mokogitea/workflows/auto-bump.yml
|
# PATH: /.mokogitea/workflows/auto-bump.yml
|
||||||
# VERSION: 09.23.00
|
# VERSION: 09.02.00
|
||||||
# BRIEF: Auto patch-bump version on every push to dev (skips merge commits)
|
# BRIEF: Auto patch-bump version on every push to dev (skips merge commits)
|
||||||
|
|
||||||
name: "Universal: Auto Version Bump"
|
name: "Universal: Auto Version Bump"
|
||||||
@@ -43,19 +43,19 @@ jobs:
|
|||||||
token: ${{ secrets.MOKOGITEA_TOKEN }}
|
token: ${{ secrets.MOKOGITEA_TOKEN }}
|
||||||
fetch-depth: 1
|
fetch-depth: 1
|
||||||
|
|
||||||
- name: Setup mokoplatform tools
|
- name: Setup moko-platform tools
|
||||||
run: |
|
run: |
|
||||||
if ! command -v composer &> /dev/null; then
|
if ! command -v composer &> /dev/null; then
|
||||||
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer >/dev/null 2>&1
|
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer >/dev/null 2>&1
|
||||||
fi
|
fi
|
||||||
if [ -d "/opt/mokoplatform/cli" ]; then
|
if [ -d "/opt/moko-platform/cli" ]; then
|
||||||
echo "MOKO_CLI=/opt/mokoplatform/cli" >> "$GITHUB_ENV"
|
echo "MOKO_CLI=/opt/moko-platform/cli" >> "$GITHUB_ENV"
|
||||||
else
|
else
|
||||||
git clone --depth 1 --branch main --quiet \
|
git clone --depth 1 --branch main --quiet \
|
||||||
"https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/MokoConsulting/mokoplatform.git" \
|
"https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/MokoConsulting/moko-platform.git" \
|
||||||
/tmp/mokoplatform-api
|
/tmp/moko-platform-api
|
||||||
cd /tmp/mokoplatform-api && composer install --no-dev --no-interaction --quiet
|
cd /tmp/moko-platform-api && composer install --no-dev --no-interaction --quiet
|
||||||
echo "MOKO_CLI=/tmp/mokoplatform-api/cli" >> "$GITHUB_ENV"
|
echo "MOKO_CLI=/tmp/moko-platform-api/cli" >> "$GITHUB_ENV"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Bump version
|
- name: Bump version
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
#
|
#
|
||||||
# FILE INFORMATION
|
# FILE INFORMATION
|
||||||
# DEFGROUP: Gitea.Workflow
|
# DEFGROUP: Gitea.Workflow
|
||||||
# INGROUP: mokoplatform.Release
|
# INGROUP: moko-platform.Release
|
||||||
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/mokoplatform
|
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/moko-platform
|
||||||
# PATH: /templates/workflows/universal/auto-release.yml.template
|
# PATH: /templates/workflows/universal/auto-release.yml.template
|
||||||
# VERSION: 05.00.00
|
# VERSION: 05.00.00
|
||||||
# BRIEF: Universal build & release � detects platform from manifest.xml
|
# BRIEF: Universal build & release � detects platform from manifest.xml
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
# | Reads manifest.xml (joomla|dolibarr|generic) to branch logic. |
|
# | Reads manifest.xml (joomla|dolibarr|generic) to branch logic. |
|
||||||
# | |
|
# | |
|
||||||
# | Platform-specific: |
|
# | Platform-specific: |
|
||||||
# | joomla: XML manifest, updates.xml, type-prefixed packages |
|
# | joomla: XML manifest, type-prefixed packages |
|
||||||
# | dolibarr: mod*.class.php, update.txt, dev version reset |
|
# | dolibarr: mod*.class.php, update.txt, dev version reset |
|
||||||
# | generic: README-only, no update stream |
|
# | generic: README-only, no update stream |
|
||||||
# | |
|
# | |
|
||||||
@@ -66,25 +66,30 @@ jobs:
|
|||||||
token: ${{ secrets.MOKOGITEA_TOKEN }}
|
token: ${{ secrets.MOKOGITEA_TOKEN }}
|
||||||
fetch-depth: 1
|
fetch-depth: 1
|
||||||
|
|
||||||
- name: Setup mokoplatform tools
|
- name: Setup moko-platform tools
|
||||||
env:
|
env:
|
||||||
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
|
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
|
||||||
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
|
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
|
||||||
run: |
|
run: |
|
||||||
if ! command -v composer &> /dev/null; then
|
if [ -f /opt/moko-platform/cli/version_bump.php ] && [ -f /opt/moko-platform/vendor/autoload.php ]; then
|
||||||
|
echo Using pre-installed /opt/moko-platform
|
||||||
|
echo MOKO_CLI=/opt/moko-platform/cli >> $GITHUB_ENV
|
||||||
|
else
|
||||||
|
echo Falling back to fresh clone
|
||||||
|
if ! command -v composer > /dev/null 2>&1; then
|
||||||
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer > /dev/null 2>&1
|
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer > /dev/null 2>&1
|
||||||
fi
|
fi
|
||||||
# Always fetch latest CLI tools — never use stale cache from previous runs
|
rm -rf /tmp/moko-platform-api
|
||||||
rm -rf /tmp/mokoplatform-api
|
CLONE_URL=https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git
|
||||||
git clone --depth 1 --branch main --quiet \
|
git clone --depth 1 --branch main --quiet $CLONE_URL /tmp/moko-platform-api
|
||||||
"https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/mokoplatform.git" \
|
cd /tmp/moko-platform-api
|
||||||
/tmp/mokoplatform-api
|
|
||||||
cd /tmp/mokoplatform-api
|
|
||||||
composer install --no-dev --no-interaction --quiet
|
composer install --no-dev --no-interaction --quiet
|
||||||
|
echo MOKO_CLI=/tmp/moko-platform-api/cli >> $GITHUB_ENV
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Rename branch to rc
|
- name: Rename branch to rc
|
||||||
run: |
|
run: |
|
||||||
php /tmp/mokoplatform-api/cli/branch_rename.php \
|
php ${MOKO_CLI}/branch_rename.php \
|
||||||
--from "${{ github.event.pull_request.head.ref || 'dev' }}" --to rc \
|
--from "${{ github.event.pull_request.head.ref || 'dev' }}" --to rc \
|
||||||
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
|
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
|
||||||
--api-base "${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" \
|
--api-base "${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" \
|
||||||
@@ -100,16 +105,15 @@ jobs:
|
|||||||
|
|
||||||
- name: Publish RC release
|
- name: Publish RC release
|
||||||
run: |
|
run: |
|
||||||
php /tmp/mokoplatform-api/cli/release_publish.php \
|
php ${MOKO_CLI}/release_publish.php \
|
||||||
--path . --stability rc --bump minor --branch rc \
|
--path . --stability rc --bump minor --branch rc \
|
||||||
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
|
--token "${{ secrets.MOKOGITEA_TOKEN }}"
|
||||||
--skip-update-stream
|
|
||||||
|
|
||||||
- name: Summary
|
- name: Summary
|
||||||
if: always()
|
if: always()
|
||||||
run: |
|
run: |
|
||||||
echo "## Promoted to Release Candidate" >> $GITHUB_STEP_SUMMARY
|
echo "## Promoted to Release Candidate" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "Branch renamed to rc, minor bump, RC release built (updates.xml managed by Gitea Pages)" >> $GITHUB_STEP_SUMMARY
|
echo "Branch renamed to rc, minor bump, RC release built" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
# ── Merged PR → Build & Release (or promote RC to stable) ────────────────────
|
# ── Merged PR → Build & Release (or promote RC to stable) ────────────────────
|
||||||
release:
|
release:
|
||||||
@@ -145,31 +149,83 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
echo "No conflict markers found"
|
echo "No conflict markers found"
|
||||||
|
|
||||||
- name: Setup mokoplatform tools
|
- name: Setup moko-platform tools
|
||||||
env:
|
env:
|
||||||
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
|
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
|
||||||
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
|
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
|
||||||
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_MIRROR_TOKEN }}"}}'
|
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_MIRROR_TOKEN }}"}}'
|
||||||
run: |
|
run: |
|
||||||
# Ensure PHP + Composer are available
|
if [ -f /opt/moko-platform/cli/version_bump.php ] && [ -f /opt/moko-platform/vendor/autoload.php ]; then
|
||||||
if ! command -v composer &> /dev/null; then
|
echo Using pre-installed /opt/moko-platform
|
||||||
|
echo MOKO_CLI=/opt/moko-platform/cli >> $GITHUB_ENV
|
||||||
|
else
|
||||||
|
echo Falling back to fresh clone
|
||||||
|
if ! command -v composer > /dev/null 2>&1; then
|
||||||
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer > /dev/null 2>&1
|
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer > /dev/null 2>&1
|
||||||
fi
|
fi
|
||||||
# Always fetch latest CLI tools — never use stale cache from previous runs
|
rm -rf /tmp/moko-platform-api
|
||||||
rm -rf /tmp/mokoplatform-api
|
CLONE_URL=https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git
|
||||||
git clone --depth 1 --branch main --quiet \
|
git clone --depth 1 --branch main --quiet $CLONE_URL /tmp/moko-platform-api
|
||||||
"https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/mokoplatform.git" \
|
cd /tmp/moko-platform-api
|
||||||
/tmp/mokoplatform-api
|
|
||||||
cd /tmp/mokoplatform-api
|
|
||||||
composer install --no-dev --no-interaction --quiet
|
composer install --no-dev --no-interaction --quiet
|
||||||
|
echo MOKO_CLI=/tmp/moko-platform-api/cli >> $GITHUB_ENV
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: "Determine version bump level"
|
||||||
|
id: bump
|
||||||
|
run: |
|
||||||
|
# Fix/patch branches: version was already bumped by pre-release, just strip suffix
|
||||||
|
# Feature/dev branches: bump minor for the new stable release
|
||||||
|
HEAD_REF="${{ github.event.pull_request.head.ref || 'dev' }}"
|
||||||
|
case "$HEAD_REF" in
|
||||||
|
fix/*|patch/*|hotfix/*|bugfix/*) BUMP="none" ;;
|
||||||
|
*) BUMP="minor" ;;
|
||||||
|
esac
|
||||||
|
echo "level=${BUMP}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "Bump level: ${BUMP} (from branch: ${HEAD_REF})"
|
||||||
|
|
||||||
- name: "Publish stable release"
|
- name: "Publish stable release"
|
||||||
run: |
|
run: |
|
||||||
php /tmp/mokoplatform-api/cli/release_publish.php \
|
BUMP_FLAG=""
|
||||||
--path . --stability stable --bump minor --branch main \
|
if [ "${{ steps.bump.outputs.level }}" != "none" ]; then
|
||||||
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
|
BUMP_FLAG="--bump ${{ steps.bump.outputs.level }}"
|
||||||
--skip-update-stream
|
fi
|
||||||
|
php ${MOKO_CLI}/release_publish.php \
|
||||||
|
--path . --stability stable ${BUMP_FLAG} --branch main \
|
||||||
|
--token "${{ secrets.MOKOGITEA_TOKEN }}"
|
||||||
|
|
||||||
|
- name: Update release notes from CHANGELOG.md
|
||||||
|
run: |
|
||||||
|
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
||||||
|
|
||||||
|
# Extract [Unreleased] section from changelog
|
||||||
|
if [ -f "CHANGELOG.md" ]; then
|
||||||
|
NOTES=$(awk '/^## \[Unreleased\]/{found=1; next} /^## \[/{if(found) exit} found{print}' CHANGELOG.md)
|
||||||
|
[ -z "$NOTES" ] && NOTES="Stable release"
|
||||||
|
else
|
||||||
|
NOTES="Stable release"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Update release body via API
|
||||||
|
RELEASE_ID=$(curl -sf -H "Authorization: token ${{ secrets.MOKOGITEA_TOKEN }}" \
|
||||||
|
"${API_BASE}/releases/tags/stable" | python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
|
||||||
|
|
||||||
|
if [ -n "$RELEASE_ID" ]; then
|
||||||
|
python3 -c "
|
||||||
|
import json, urllib.request
|
||||||
|
body = open('/dev/stdin').read()
|
||||||
|
payload = json.dumps({'body': body}).encode()
|
||||||
|
req = urllib.request.Request(
|
||||||
|
'${API_BASE}/releases/${RELEASE_ID}',
|
||||||
|
data=payload, method='PATCH',
|
||||||
|
headers={
|
||||||
|
'Authorization': 'token ${{ secrets.MOKOGITEA_TOKEN }}',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
})
|
||||||
|
urllib.request.urlopen(req)
|
||||||
|
" <<< "$NOTES"
|
||||||
|
echo "Release notes updated from CHANGELOG.md"
|
||||||
|
fi
|
||||||
|
|
||||||
# -- STEP 9: Mirror to GitHub (stable only) --------------------------------
|
# -- STEP 9: Mirror to GitHub (stable only) --------------------------------
|
||||||
- name: "Step 9: Mirror release to GitHub"
|
- name: "Step 9: Mirror release to GitHub"
|
||||||
@@ -182,7 +238,7 @@ jobs:
|
|||||||
RELEASE_TAG="${{ steps.version.outputs.release_tag }}"
|
RELEASE_TAG="${{ steps.version.outputs.release_tag }}"
|
||||||
GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}"
|
GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}"
|
||||||
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
||||||
php /tmp/mokoplatform-api/cli/release_mirror.php \
|
php ${MOKO_CLI}/release_mirror.php \
|
||||||
--version "$VERSION" --tag "$RELEASE_TAG" \
|
--version "$VERSION" --tag "$RELEASE_TAG" \
|
||||||
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
|
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
|
||||||
--gh-token "${{ secrets.GH_MIRROR_TOKEN }}" --gh-repo "$GH_REPO" \
|
--gh-token "${{ secrets.GH_MIRROR_TOKEN }}" --gh-repo "$GH_REPO" \
|
||||||
@@ -256,7 +312,7 @@ jobs:
|
|||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
run: |
|
run: |
|
||||||
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
||||||
php /tmp/mokoplatform-api/cli/version_reset_dev.php \
|
php ${MOKO_CLI}/version_reset_dev.php \
|
||||||
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "${API_BASE}" \
|
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "${API_BASE}" \
|
||||||
--branch dev --path . 2>&1 || true
|
--branch dev --path . 2>&1 || true
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
#
|
#
|
||||||
# FILE INFORMATION
|
# FILE INFORMATION
|
||||||
# DEFGROUP: Gitea.Workflow
|
# DEFGROUP: Gitea.Workflow
|
||||||
# INGROUP: MokoPlatform.Universal
|
# INGROUP: MokoStandards.Universal
|
||||||
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform
|
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
|
||||||
# PATH: /.mokogitea/workflows/branch-cleanup.yml
|
# PATH: /.mokogitea/workflows/branch-cleanup.yml
|
||||||
# VERSION: 09.23.00
|
# VERSION: 01.00.00
|
||||||
# BRIEF: Delete feature branches after PR merge
|
# BRIEF: Delete feature branches after PR merge
|
||||||
|
|
||||||
name: "Branch Cleanup"
|
name: "Branch Cleanup"
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# DISABLED — auto-release Step 11 recreates dev from main after every release.
|
||||||
|
# Cascade-dev is redundant and causes version conflicts when both main and dev
|
||||||
|
# have different version numbers in templateDetails.xml / manifest.xml.
|
||||||
|
name: "Cascade Main → Dev (DISABLED)"
|
||||||
|
on: workflow_dispatch
|
||||||
|
jobs:
|
||||||
|
noop:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- run: echo "Cascade disabled — auto-release handles dev recreation"
|
||||||
@@ -0,0 +1,204 @@
|
|||||||
|
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
#
|
||||||
|
# FILE INFORMATION
|
||||||
|
# DEFGROUP: Gitea.Workflow
|
||||||
|
# INGROUP: MokoStandards.CI
|
||||||
|
# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Generic
|
||||||
|
# PATH: /.gitea/workflows/ci-generic.yml
|
||||||
|
# VERSION: 01.00.00
|
||||||
|
# BRIEF: CI pipeline — lint, validate, and test for generic projects (PHP + Node.js)
|
||||||
|
|
||||||
|
name: "Generic: Project CI"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- dev
|
||||||
|
- dev/**
|
||||||
|
- rc/**
|
||||||
|
- version/**
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- dev
|
||||||
|
- dev/**
|
||||||
|
- rc/**
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
env:
|
||||||
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# ── Lint & Validate ───────────────────────────────────────────────────
|
||||||
|
lint:
|
||||||
|
name: Lint & Validate
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Detect toolchain
|
||||||
|
id: detect
|
||||||
|
run: |
|
||||||
|
HAS_PHP=false
|
||||||
|
HAS_NODE=false
|
||||||
|
[ -f "composer.json" ] && HAS_PHP=true
|
||||||
|
[ -f "package.json" ] && HAS_NODE=true
|
||||||
|
echo "has_php=$HAS_PHP" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "has_node=$HAS_NODE" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "Toolchain: PHP=$HAS_PHP Node=$HAS_NODE"
|
||||||
|
|
||||||
|
- name: Setup PHP
|
||||||
|
if: steps.detect.outputs.has_php == 'true'
|
||||||
|
run: |
|
||||||
|
if ! command -v php &> /dev/null; then
|
||||||
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get install -y -qq php-cli php-mbstring php-xml >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
php -v
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
if: steps.detect.outputs.has_node == 'true'
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
|
- name: Install PHP dependencies
|
||||||
|
if: steps.detect.outputs.has_php == 'true'
|
||||||
|
run: |
|
||||||
|
if [ -f "composer.json" ]; then
|
||||||
|
composer install --no-interaction --prefer-dist --quiet 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Install Node.js dependencies
|
||||||
|
if: steps.detect.outputs.has_node == 'true'
|
||||||
|
run: |
|
||||||
|
if [ -f "package.json" ]; then
|
||||||
|
npm ci --quiet 2>/dev/null || npm install --quiet 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: PHP syntax check
|
||||||
|
if: steps.detect.outputs.has_php == 'true'
|
||||||
|
run: |
|
||||||
|
ERRORS=0
|
||||||
|
while IFS= read -r -d '' file; do
|
||||||
|
if ! php -l "$file" 2>&1 | grep -q "No syntax errors"; then
|
||||||
|
echo "::error file=${file}::PHP syntax error"
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
fi
|
||||||
|
done < <(find . -name "*.php" -not -path "./.git/*" -not -path "./vendor/*" -not -path "./node_modules/*" -print0)
|
||||||
|
|
||||||
|
echo "## PHP Lint" >> $GITHUB_STEP_SUMMARY
|
||||||
|
if [ "$ERRORS" -eq 0 ]; then
|
||||||
|
echo "All PHP files passed syntax check." >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
echo "${ERRORS} file(s) with syntax errors." >> $GITHUB_STEP_SUMMARY
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: TypeScript/JavaScript lint
|
||||||
|
if: steps.detect.outputs.has_node == 'true'
|
||||||
|
run: |
|
||||||
|
if [ -f "node_modules/.bin/eslint" ]; then
|
||||||
|
npx eslint src/ --quiet 2>&1 || { echo "::error::ESLint errors found"; exit 1; }
|
||||||
|
echo "## ESLint" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "All files passed ESLint." >> $GITHUB_STEP_SUMMARY
|
||||||
|
elif [ -f ".eslintrc.json" ] || [ -f ".eslintrc.js" ] || [ -f "eslint.config.js" ]; then
|
||||||
|
echo "::warning::ESLint config found but eslint not installed"
|
||||||
|
else
|
||||||
|
echo "No ESLint configured — skipping"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: TypeScript compile check
|
||||||
|
if: steps.detect.outputs.has_node == 'true'
|
||||||
|
run: |
|
||||||
|
if [ -f "tsconfig.json" ] && [ -f "node_modules/.bin/tsc" ]; then
|
||||||
|
npx tsc --noEmit 2>&1 || { echo "::error::TypeScript compilation errors"; exit 1; }
|
||||||
|
echo "## TypeScript" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "TypeScript compilation passed." >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: PHPStan static analysis
|
||||||
|
if: steps.detect.outputs.has_php == 'true'
|
||||||
|
run: |
|
||||||
|
if [ -f "phpstan.neon" ] && [ -f "vendor/bin/phpstan" ]; then
|
||||||
|
vendor/bin/phpstan analyse --no-progress 2>&1 || { echo "::warning::PHPStan found issues"; }
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Tests ─────────────────────────────────────────────────────────────
|
||||||
|
test:
|
||||||
|
name: Tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: lint
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Detect toolchain
|
||||||
|
id: detect
|
||||||
|
run: |
|
||||||
|
HAS_PHP=false
|
||||||
|
HAS_NODE=false
|
||||||
|
[ -f "composer.json" ] && HAS_PHP=true
|
||||||
|
[ -f "package.json" ] && HAS_NODE=true
|
||||||
|
echo "has_php=$HAS_PHP" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "has_node=$HAS_NODE" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Setup PHP
|
||||||
|
if: steps.detect.outputs.has_php == 'true'
|
||||||
|
run: |
|
||||||
|
if ! command -v php &> /dev/null; then
|
||||||
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get install -y -qq php-cli php-mbstring php-xml >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
if: steps.detect.outputs.has_node == 'true'
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
[ -f "composer.json" ] && composer install --no-interaction --prefer-dist --quiet 2>/dev/null || true
|
||||||
|
[ -f "package.json" ] && { npm ci --quiet 2>/dev/null || npm install --quiet 2>/dev/null || true; }
|
||||||
|
|
||||||
|
- name: Run PHP tests
|
||||||
|
if: steps.detect.outputs.has_php == 'true'
|
||||||
|
run: |
|
||||||
|
if [ -f "vendor/bin/phpunit" ]; then
|
||||||
|
vendor/bin/phpunit --testdox 2>&1
|
||||||
|
echo "## PHPUnit" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "Tests passed." >> $GITHUB_STEP_SUMMARY
|
||||||
|
elif [ -f "phpunit.xml" ] || [ -f "phpunit.xml.dist" ]; then
|
||||||
|
echo "::warning::PHPUnit config found but phpunit not installed"
|
||||||
|
else
|
||||||
|
echo "No PHPUnit configured — skipping"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Run Node.js tests
|
||||||
|
if: steps.detect.outputs.has_node == 'true'
|
||||||
|
run: |
|
||||||
|
if jq -e '.scripts.test' package.json > /dev/null 2>&1; then
|
||||||
|
npm test 2>&1
|
||||||
|
echo "## Node.js Tests" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "Tests passed." >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
echo "No test script in package.json — skipping"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Build check
|
||||||
|
run: |
|
||||||
|
if [ -f "Makefile" ]; then
|
||||||
|
make build 2>&1 || echo "::warning::Build failed or not configured"
|
||||||
|
elif [ -f "package.json" ] && jq -e '.scripts.build' package.json > /dev/null 2>&1; then
|
||||||
|
npm run build 2>&1 || echo "::warning::Build failed"
|
||||||
|
fi
|
||||||
@@ -35,25 +35,32 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup PHP
|
- name: Setup PHP
|
||||||
run: |
|
run: |
|
||||||
|
if ! command -v php &> /dev/null; then
|
||||||
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer >/dev/null 2>&1
|
||||||
|
fi
|
||||||
php -v && composer --version
|
php -v && composer --version
|
||||||
|
|
||||||
- name: Clone MokoStandards
|
- name: Setup moko-platform tools
|
||||||
env:
|
env:
|
||||||
GA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN || secrets.MOKOGITEA_TOKEN || github.token }}
|
MOKO_CLONE_TOKEN: ${{ secrets.GA_TOKEN || github.token }}
|
||||||
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN || secrets.MOKOGITEA_TOKEN || github.token }}
|
MOKO_CLONE_HOST: ${{ secrets.GA_TOKEN && 'git.mokoconsulting.tech/MokoConsulting' || 'github.com/mokoconsulting-tech' }}
|
||||||
MOKO_CLONE_HOST: ${{ secrets.MOKOGITEA_TOKEN && 'git.mokoconsulting.tech/MokoConsulting' || 'github.com/mokoconsulting-tech' }}
|
|
||||||
run: |
|
run: |
|
||||||
|
if [ -d "/tmp/moko-platform" ] || [ -d "/opt/moko-platform" ]; then
|
||||||
|
echo "moko-platform already available on runner — skipping clone"
|
||||||
|
else
|
||||||
git clone --depth 1 --branch main --quiet \
|
git clone --depth 1 --branch main --quiet \
|
||||||
"https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/MokoStandards-API.git" \
|
"https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git" \
|
||||||
/tmp/mokostandards-api
|
/tmp/moko-platform 2>/dev/null || echo "moko-platform clone skipped — continuing without it"
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
env:
|
env:
|
||||||
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_MIRROR_TOKEN || github.token }}"}}'
|
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_TOKEN || secrets.GA_TOKEN || github.token }}"}}'
|
||||||
run: |
|
run: |
|
||||||
if [ -f "composer.json" ]; then
|
if [ -f "composer.json" ]; then
|
||||||
composer install \
|
composer install \
|
||||||
@@ -67,7 +74,7 @@ jobs:
|
|||||||
- name: PHP syntax check
|
- name: PHP syntax check
|
||||||
run: |
|
run: |
|
||||||
ERRORS=0
|
ERRORS=0
|
||||||
for DIR in source/ src/ htdocs/; do
|
for DIR in src/ htdocs/; do
|
||||||
if [ -d "$DIR" ]; then
|
if [ -d "$DIR" ]; then
|
||||||
FOUND=1
|
FOUND=1
|
||||||
while IFS= read -r -d '' FILE; do
|
while IFS= read -r -d '' FILE; do
|
||||||
@@ -124,13 +131,8 @@ jobs:
|
|||||||
echo "Manifest is well-formed XML." >> $GITHUB_STEP_SUMMARY
|
echo "Manifest is well-formed XML." >> $GITHUB_STEP_SUMMARY
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check required tags
|
# Check required tags: name, version, author
|
||||||
REQUIRED_TAGS="name version author"
|
for TAG in name version author; do
|
||||||
# namespace is only required for non-package extensions
|
|
||||||
if ! grep -q 'type="package"' "$MANIFEST" 2>/dev/null; then
|
|
||||||
REQUIRED_TAGS="$REQUIRED_TAGS namespace"
|
|
||||||
fi
|
|
||||||
for TAG in $REQUIRED_TAGS; do
|
|
||||||
if ! grep -q "<${TAG}>" "$MANIFEST" 2>/dev/null; then
|
if ! grep -q "<${TAG}>" "$MANIFEST" 2>/dev/null; then
|
||||||
echo "Missing required tag: \`<${TAG}>\`" >> $GITHUB_STEP_SUMMARY
|
echo "Missing required tag: \`<${TAG}>\`" >> $GITHUB_STEP_SUMMARY
|
||||||
ERRORS=$((ERRORS + 1))
|
ERRORS=$((ERRORS + 1))
|
||||||
@@ -138,6 +140,19 @@ jobs:
|
|||||||
echo "Found required tag: \`<${TAG}>\`" >> $GITHUB_STEP_SUMMARY
|
echo "Found required tag: \`<${TAG}>\`" >> $GITHUB_STEP_SUMMARY
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Namespace is required for components/plugins but not packages
|
||||||
|
EXT_TYPE=$(grep -oP '<extension[^>]*\btype="\K[^"]+' "$MANIFEST" | head -1)
|
||||||
|
if [ "$EXT_TYPE" != "package" ]; then
|
||||||
|
if ! grep -q "<namespace" "$MANIFEST" 2>/dev/null; then
|
||||||
|
echo "Missing required tag: \`<namespace>\` (required for Joomla 5+ ${EXT_TYPE} extensions)" >> $GITHUB_STEP_SUMMARY
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
else
|
||||||
|
echo "Found required tag: \`<namespace>\`" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Package extension — \`<namespace>\` not required." >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "${ERRORS}" -gt 0 ]; then
|
if [ "${ERRORS}" -gt 0 ]; then
|
||||||
@@ -202,44 +217,13 @@ jobs:
|
|||||||
echo "**Language file check passed.**" >> $GITHUB_STEP_SUMMARY
|
echo "**Language file check passed.**" >> $GITHUB_STEP_SUMMARY
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Check en-GB and en-US language directories exist
|
|
||||||
run: |
|
|
||||||
echo "### Language Directory Check" >> $GITHUB_STEP_SUMMARY
|
|
||||||
ERRORS=0
|
|
||||||
|
|
||||||
for DIR in source/ src/ htdocs/; do
|
|
||||||
[ -d "$DIR" ] || continue
|
|
||||||
# Find all language directories
|
|
||||||
while IFS= read -r -d '' LANG_DIR; do
|
|
||||||
HAS_GB=false
|
|
||||||
HAS_US=false
|
|
||||||
[ -d "${LANG_DIR}/en-GB" ] && HAS_GB=true
|
|
||||||
[ -d "${LANG_DIR}/en-US" ] && HAS_US=true
|
|
||||||
if [ "$HAS_GB" = false ]; then
|
|
||||||
echo "Missing \`en-GB\` in: \`${LANG_DIR}\`" >> $GITHUB_STEP_SUMMARY
|
|
||||||
ERRORS=$((ERRORS + 1))
|
|
||||||
fi
|
|
||||||
if [ "$HAS_US" = false ]; then
|
|
||||||
echo "Missing \`en-US\` in: \`${LANG_DIR}\`" >> $GITHUB_STEP_SUMMARY
|
|
||||||
ERRORS=$((ERRORS + 1))
|
|
||||||
fi
|
|
||||||
done < <(find "$DIR" -type d -name "language" -print0)
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ "${ERRORS}" -gt 0 ]; then
|
|
||||||
echo "**${ERRORS} missing language director(ies).**" >> $GITHUB_STEP_SUMMARY
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
echo "All language directories have en-GB and en-US." >> $GITHUB_STEP_SUMMARY
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Check index.html files in directories
|
- name: Check index.html files in directories
|
||||||
run: |
|
run: |
|
||||||
echo "### Index.html Check" >> $GITHUB_STEP_SUMMARY
|
echo "### Index.html Check" >> $GITHUB_STEP_SUMMARY
|
||||||
MISSING=0
|
MISSING=0
|
||||||
CHECKED=0
|
CHECKED=0
|
||||||
|
|
||||||
for DIR in source/ src/ htdocs/; do
|
for DIR in src/ htdocs/; do
|
||||||
if [ -d "$DIR" ]; then
|
if [ -d "$DIR" ]; then
|
||||||
while IFS= read -r -d '' SUBDIR; do
|
while IFS= read -r -d '' SUBDIR; do
|
||||||
CHECKED=$((CHECKED + 1))
|
CHECKED=$((CHECKED + 1))
|
||||||
@@ -252,7 +236,7 @@ jobs:
|
|||||||
done
|
done
|
||||||
|
|
||||||
if [ "${CHECKED}" -eq 0 ]; then
|
if [ "${CHECKED}" -eq 0 ]; then
|
||||||
echo "No source/, src/, or htdocs/ directories found — skipping." >> $GITHUB_STEP_SUMMARY
|
echo "No src/ or htdocs/ directories found — skipping." >> $GITHUB_STEP_SUMMARY
|
||||||
elif [ "${MISSING}" -gt 0 ]; then
|
elif [ "${MISSING}" -gt 0 ]; then
|
||||||
echo "" >> $GITHUB_STEP_SUMMARY
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "**${MISSING} director(ies) missing index.html out of ${CHECKED} checked.**" >> $GITHUB_STEP_SUMMARY
|
echo "**${MISSING} director(ies) missing index.html out of ${CHECKED} checked.**" >> $GITHUB_STEP_SUMMARY
|
||||||
@@ -268,7 +252,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Validate release readiness
|
- name: Validate release readiness
|
||||||
run: |
|
run: |
|
||||||
@@ -276,8 +260,8 @@ jobs:
|
|||||||
echo "" >> $GITHUB_STEP_SUMMARY
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
ERRORS=0
|
ERRORS=0
|
||||||
|
|
||||||
# Extract version from README.md (supports both FILE INFORMATION block and HTML comment format)
|
# Extract version from README.md
|
||||||
README_VERSION=$(sed -n 's/.*VERSION:\s*\([0-9]\{2\}\.[0-9]\{2\}\.[0-9]\{2\}\).*/\1/p' README.md | head -1)
|
README_VERSION=$(grep -oP '^\s*VERSION:\s*\K[0-9]{2}\.[0-9]{2}\.[0-9]{2}' README.md | head -1)
|
||||||
if [ -z "$README_VERSION" ]; then
|
if [ -z "$README_VERSION" ]; then
|
||||||
echo "No VERSION found in README.md FILE INFORMATION block." >> $GITHUB_STEP_SUMMARY
|
echo "No VERSION found in README.md FILE INFORMATION block." >> $GITHUB_STEP_SUMMARY
|
||||||
ERRORS=$((ERRORS + 1))
|
ERRORS=$((ERRORS + 1))
|
||||||
@@ -301,7 +285,7 @@ jobs:
|
|||||||
echo "Manifest: \`${MANIFEST}\`" >> $GITHUB_STEP_SUMMARY
|
echo "Manifest: \`${MANIFEST}\`" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
# Check <version> matches README VERSION
|
# Check <version> matches README VERSION
|
||||||
MANIFEST_VERSION=$(sed -n 's/.*<version>\([^<]*\)<\/version>.*/\1/p' "$MANIFEST" | head -1)
|
MANIFEST_VERSION=$(grep -oP '<version>\K[^<]+' "$MANIFEST" | head -1)
|
||||||
if [ -z "$MANIFEST_VERSION" ]; then
|
if [ -z "$MANIFEST_VERSION" ]; then
|
||||||
echo "No \`<version>\` tag in manifest." >> $GITHUB_STEP_SUMMARY
|
echo "No \`<version>\` tag in manifest." >> $GITHUB_STEP_SUMMARY
|
||||||
ERRORS=$((ERRORS + 1))
|
ERRORS=$((ERRORS + 1))
|
||||||
@@ -374,15 +358,19 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup PHP ${{ matrix.php }}
|
- name: Setup PHP ${{ matrix.php }}
|
||||||
run: |
|
run: |
|
||||||
|
if ! command -v php &> /dev/null; then
|
||||||
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer >/dev/null 2>&1
|
||||||
|
fi
|
||||||
php -v && composer --version
|
php -v && composer --version
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
env:
|
env:
|
||||||
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_MIRROR_TOKEN || github.token }}"}}'
|
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_TOKEN || secrets.GA_TOKEN || github.token }}"}}'
|
||||||
run: |
|
run: |
|
||||||
if [ -f "composer.json" ]; then
|
if [ -f "composer.json" ]; then
|
||||||
composer install \
|
composer install \
|
||||||
@@ -420,14 +408,19 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup PHP
|
- name: Setup PHP
|
||||||
run: php -v && composer --version
|
run: |
|
||||||
|
if ! command -v php &> /dev/null; then
|
||||||
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
php -v && composer --version
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
env:
|
env:
|
||||||
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_MIRROR_TOKEN || github.token }}"}}'
|
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_TOKEN || secrets.GA_TOKEN || github.token }}"}}'
|
||||||
run: |
|
run: |
|
||||||
if [ -f "composer.json" ]; then
|
if [ -f "composer.json" ]; then
|
||||||
composer install --no-interaction --prefer-dist --optimize-autoloader
|
composer install --no-interaction --prefer-dist --optimize-autoloader
|
||||||
@@ -450,7 +443,7 @@ jobs:
|
|||||||
|
|
||||||
# Determine source directory
|
# Determine source directory
|
||||||
SRC_DIR=""
|
SRC_DIR=""
|
||||||
for DIR in source/ src/ htdocs/ lib/; do
|
for DIR in src/ htdocs/ lib/; do
|
||||||
if [ -d "$DIR" ]; then
|
if [ -d "$DIR" ]; then
|
||||||
SRC_DIR="$DIR"
|
SRC_DIR="$DIR"
|
||||||
break
|
break
|
||||||
@@ -458,7 +451,7 @@ jobs:
|
|||||||
done
|
done
|
||||||
|
|
||||||
if [ -z "$SRC_DIR" ]; then
|
if [ -z "$SRC_DIR" ]; then
|
||||||
echo "No source directory found (source/, src/, htdocs/, lib/) — skipping." >> $GITHUB_STEP_SUMMARY
|
echo "No source directory found (src/, htdocs/, lib/) — skipping." >> $GITHUB_STEP_SUMMARY
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -484,3 +477,24 @@ jobs:
|
|||||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||||
fi
|
fi
|
||||||
exit $EXIT
|
exit $EXIT
|
||||||
|
|
||||||
|
pre-release:
|
||||||
|
name: Build RC Pre-Release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [lint-and-validate, test]
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Trigger pre-release build
|
||||||
|
env:
|
||||||
|
GA_TOKEN: ${{ secrets.GA_TOKEN }}
|
||||||
|
REPO: ${{ github.repository }}
|
||||||
|
BRANCH: ${{ github.head_ref }}
|
||||||
|
run: |
|
||||||
|
curl -s -X POST \
|
||||||
|
"${GITEA_URL:-https://git.mokoconsulting.tech}/api/v1/repos/${REPO}/actions/workflows/pre-release.yml/dispatches" \
|
||||||
|
-H "Authorization: token ${GA_TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"ref\":\"${BRANCH}\",\"inputs\":{\"stability\":\"release-candidate\"}}"
|
||||||
|
echo "### Pre-Release" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "Triggered RC build on branch \`${BRANCH}\`" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
#
|
#
|
||||||
# FILE INFORMATION
|
# FILE INFORMATION
|
||||||
# DEFGROUP: Gitea.Workflow
|
# DEFGROUP: Gitea.Workflow
|
||||||
# INGROUP: mokoplatform.Maintenance
|
# INGROUP: MokoStandards.Maintenance
|
||||||
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform
|
# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards
|
||||||
# PATH: /.gitea/workflows/cleanup.yml
|
# PATH: /.gitea/workflows/cleanup.yml
|
||||||
# VERSION: 09.23.00
|
# VERSION: 01.00.00
|
||||||
# BRIEF: Scheduled cleanup — delete merged branches and old workflow runs
|
# BRIEF: Scheduled cleanup — delete merged branches and old workflow runs
|
||||||
|
|
||||||
name: "Universal: Repository Cleanup"
|
name: "Universal: Repository Cleanup"
|
||||||
@@ -33,17 +33,17 @@ jobs:
|
|||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
token: ${{ secrets.MOKOGITEA_TOKEN }}
|
token: ${{ secrets.GA_TOKEN }}
|
||||||
|
|
||||||
- name: Delete merged branches
|
- name: Delete merged branches
|
||||||
env:
|
env:
|
||||||
GA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
|
GA_TOKEN: ${{ secrets.GA_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
echo "=== Merged Branch Cleanup ==="
|
echo "=== Merged Branch Cleanup ==="
|
||||||
API="${GITEA_URL}/api/v1/repos/${{ github.repository }}"
|
API="${GITEA_URL}/api/v1/repos/${{ github.repository }}"
|
||||||
|
|
||||||
# List branches via API
|
# List branches via API
|
||||||
BRANCHES=$(curl -sS -H "Authorization: token ${GITEA_TOKEN}" \
|
BRANCHES=$(curl -sS -H "Authorization: token ${GA_TOKEN}" \
|
||||||
"${API}/branches?limit=50" | jq -r '.[].name')
|
"${API}/branches?limit=50" | jq -r '.[].name')
|
||||||
|
|
||||||
DELETED=0
|
DELETED=0
|
||||||
@@ -56,7 +56,7 @@ jobs:
|
|||||||
# Check if branch is merged into main
|
# Check if branch is merged into main
|
||||||
if git merge-base --is-ancestor "origin/${BRANCH}" origin/main 2>/dev/null; then
|
if git merge-base --is-ancestor "origin/${BRANCH}" origin/main 2>/dev/null; then
|
||||||
echo " Deleting merged branch: ${BRANCH}"
|
echo " Deleting merged branch: ${BRANCH}"
|
||||||
curl -sS -X DELETE -H "Authorization: token ${GITEA_TOKEN}" \
|
curl -sS -X DELETE -H "Authorization: token ${GA_TOKEN}" \
|
||||||
"${API}/branches/${BRANCH}" 2>/dev/null || true
|
"${API}/branches/${BRANCH}" 2>/dev/null || true
|
||||||
DELETED=$((DELETED + 1))
|
DELETED=$((DELETED + 1))
|
||||||
fi
|
fi
|
||||||
@@ -66,20 +66,20 @@ jobs:
|
|||||||
|
|
||||||
- name: Clean old workflow runs
|
- name: Clean old workflow runs
|
||||||
env:
|
env:
|
||||||
GA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
|
GA_TOKEN: ${{ secrets.GA_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
echo "=== Workflow Run Cleanup ==="
|
echo "=== Workflow Run Cleanup ==="
|
||||||
API="${GITEA_URL}/api/v1/repos/${{ github.repository }}"
|
API="${GITEA_URL}/api/v1/repos/${{ github.repository }}"
|
||||||
CUTOFF=$(date -d "30 days ago" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -v-30d +%Y-%m-%dT%H:%M:%SZ)
|
CUTOFF=$(date -d "30 days ago" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -v-30d +%Y-%m-%dT%H:%M:%SZ)
|
||||||
|
|
||||||
# Get old completed runs
|
# Get old completed runs
|
||||||
RUNS=$(curl -sS -H "Authorization: token ${GITEA_TOKEN}" \
|
RUNS=$(curl -sS -H "Authorization: token ${GA_TOKEN}" \
|
||||||
"${API}/actions/runs?status=completed&limit=50" | \
|
"${API}/actions/runs?status=completed&limit=50" | \
|
||||||
jq -r ".workflow_runs[] | select(.created_at < \"${CUTOFF}\") | .id" 2>/dev/null)
|
jq -r ".workflow_runs[] | select(.created_at < \"${CUTOFF}\") | .id" 2>/dev/null)
|
||||||
|
|
||||||
DELETED=0
|
DELETED=0
|
||||||
for RUN_ID in $RUNS; do
|
for RUN_ID in $RUNS; do
|
||||||
curl -sS -X DELETE -H "Authorization: token ${GITEA_TOKEN}" \
|
curl -sS -X DELETE -H "Authorization: token ${GA_TOKEN}" \
|
||||||
"${API}/actions/runs/${RUN_ID}" 2>/dev/null || true
|
"${API}/actions/runs/${RUN_ID}" 2>/dev/null || true
|
||||||
DELETED=$((DELETED + 1))
|
DELETED=$((DELETED + 1))
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
#
|
||||||
|
# FILE INFORMATION
|
||||||
|
# DEFGROUP: Gitea.Workflow
|
||||||
|
# INGROUP: MokoStandards.Deploy
|
||||||
|
# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards-API
|
||||||
|
# PATH: /templates/workflows/joomla/deploy-manual.yml.template
|
||||||
|
# VERSION: 04.07.00
|
||||||
|
# BRIEF: Manual SFTP deploy to dev server for Joomla repos
|
||||||
|
|
||||||
|
name: "Universal: Deploy to Dev (Manual)"
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
clear_remote:
|
||||||
|
description: 'Delete all remote files before uploading'
|
||||||
|
required: false
|
||||||
|
default: 'false'
|
||||||
|
type: boolean
|
||||||
|
|
||||||
|
env:
|
||||||
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
name: SFTP Deploy to Dev
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||||
|
|
||||||
|
- name: Setup PHP
|
||||||
|
run: |
|
||||||
|
php -v && composer --version
|
||||||
|
|
||||||
|
- name: Setup MokoStandards tools
|
||||||
|
env:
|
||||||
|
GA_TOKEN: ${{ secrets.GA_TOKEN || secrets.GA_TOKEN || github.token }}
|
||||||
|
MOKO_CLONE_TOKEN: ${{ secrets.GA_TOKEN || secrets.GA_TOKEN || github.token }}
|
||||||
|
MOKO_CLONE_HOST: ${{ secrets.GA_TOKEN && 'git.mokoconsulting.tech/MokoConsulting' || 'github.com/mokoconsulting-tech' }}
|
||||||
|
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GA_TOKEN || github.token }}"}}'
|
||||||
|
run: |
|
||||||
|
git clone --depth 1 --branch main --quiet \
|
||||||
|
"https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/MokoStandards-API.git" \
|
||||||
|
/tmp/mokostandards-api 2>/dev/null || true
|
||||||
|
if [ -d "/tmp/mokostandards-api" ] && [ -f "/tmp/mokostandards-api/composer.json" ]; then
|
||||||
|
cd /tmp/mokostandards-api && composer install --no-dev --no-interaction --quiet 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Check FTP configuration
|
||||||
|
id: check
|
||||||
|
env:
|
||||||
|
HOST: ${{ vars.DEV_FTP_HOST }}
|
||||||
|
PATH_VAR: ${{ vars.DEV_FTP_PATH }}
|
||||||
|
PORT: ${{ vars.DEV_FTP_PORT }}
|
||||||
|
run: |
|
||||||
|
if [ -z "$HOST" ] || [ -z "$PATH_VAR" ]; then
|
||||||
|
echo "DEV_FTP_HOST or DEV_FTP_PATH not configured -- cannot deploy"
|
||||||
|
echo "skip=true" >> "$GITHUB_OUTPUT"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "skip=false" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "host=$HOST" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
REMOTE="${PATH_VAR%/}"
|
||||||
|
echo "remote=$REMOTE" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
[ -z "$PORT" ] && PORT="22"
|
||||||
|
echo "port=$PORT" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Deploy via SFTP
|
||||||
|
if: steps.check.outputs.skip != 'true'
|
||||||
|
env:
|
||||||
|
SFTP_KEY: ${{ secrets.DEV_FTP_KEY }}
|
||||||
|
SFTP_PASS: ${{ secrets.DEV_FTP_PASSWORD }}
|
||||||
|
SFTP_USER: ${{ vars.DEV_FTP_USERNAME }}
|
||||||
|
run: |
|
||||||
|
SOURCE_DIR="src"
|
||||||
|
[ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs"
|
||||||
|
[ ! -d "$SOURCE_DIR" ] && { echo "No src/ or htdocs/ -- nothing to deploy"; exit 0; }
|
||||||
|
|
||||||
|
printf '{"host":"%s","port":%s,"username":"%s","remotePath":"%s"' \
|
||||||
|
"${{ steps.check.outputs.host }}" "${{ steps.check.outputs.port }}" "$SFTP_USER" "${{ steps.check.outputs.remote }}" \
|
||||||
|
> /tmp/sftp-config.json
|
||||||
|
|
||||||
|
if [ -n "$SFTP_KEY" ]; then
|
||||||
|
echo "$SFTP_KEY" > /tmp/deploy_key
|
||||||
|
chmod 600 /tmp/deploy_key
|
||||||
|
printf ',"privateKeyPath":"/tmp/deploy_key"}' >> /tmp/sftp-config.json
|
||||||
|
else
|
||||||
|
printf ',"password":"%s"}' "$SFTP_PASS" >> /tmp/sftp-config.json
|
||||||
|
fi
|
||||||
|
|
||||||
|
DEPLOY_ARGS=(--path . --src-dir "$SOURCE_DIR" --config /tmp/sftp-config.json)
|
||||||
|
[ "${{ inputs.clear_remote }}" = "true" ] && DEPLOY_ARGS+=(--clear-remote)
|
||||||
|
|
||||||
|
PLATFORM=$(php /tmp/mokostandards-api/cli/platform_detect.php --path . 2>/dev/null || true)
|
||||||
|
if [ "$PLATFORM" = "waas-component" ] && [ -f "/tmp/mokostandards-api/deploy/deploy-joomla.php" ]; then
|
||||||
|
php /tmp/mokostandards-api/deploy/deploy-joomla.php "${DEPLOY_ARGS[@]}"
|
||||||
|
else
|
||||||
|
php /tmp/mokostandards-api/deploy/deploy-sftp.php "${DEPLOY_ARGS[@]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f /tmp/deploy_key /tmp/sftp-config.json
|
||||||
|
|
||||||
|
- name: Summary
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
if [ "${{ steps.check.outputs.skip }}" = "true" ]; then
|
||||||
|
echo "### Deploy Skipped -- FTP not configured" >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
echo "### Manual Dev Deploy Complete" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "|-------|-------|" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Host | \`${{ steps.check.outputs.host }}\` |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Remote | \`${{ steps.check.outputs.remote }}\` |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Clear | ${{ inputs.clear_remote }} |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
@@ -4,10 +4,10 @@
|
|||||||
#
|
#
|
||||||
# FILE INFORMATION
|
# FILE INFORMATION
|
||||||
# DEFGROUP: Gitea.Workflow
|
# DEFGROUP: Gitea.Workflow
|
||||||
# INGROUP: mokoplatform.Security
|
# INGROUP: MokoStandards.Security
|
||||||
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/mokoplatform
|
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||||
# PATH: /templates/workflows/gitleaks.yml.template
|
# PATH: /templates/workflows/gitleaks.yml.template
|
||||||
# VERSION: 09.23.00
|
# VERSION: 01.00.00
|
||||||
# BRIEF: Secret scanning — detect leaked credentials, API keys, and tokens
|
# BRIEF: Secret scanning — detect leaked credentials, API keys, and tokens
|
||||||
#
|
#
|
||||||
# +========================================================================+
|
# +========================================================================+
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
#
|
#
|
||||||
# FILE INFORMATION
|
# FILE INFORMATION
|
||||||
# DEFGROUP: Gitea.Workflow
|
# DEFGROUP: Gitea.Workflow
|
||||||
# INGROUP: mokoplatform.Automation
|
# INGROUP: moko-platform.Automation
|
||||||
# VERSION: 01.08.17
|
# VERSION: 01.00.00
|
||||||
# BRIEF: Auto-create feature branch when an issue is opened
|
# BRIEF: Auto-create feature branch when an issue is opened
|
||||||
|
|
||||||
name: "Universal: Issue Branch"
|
name: "Universal: Issue Branch"
|
||||||
@@ -28,7 +28,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Create branch and comment
|
- name: Create branch and comment
|
||||||
run: |
|
run: |
|
||||||
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
|
TOKEN="${{ secrets.GA_TOKEN }}"
|
||||||
API="${GITEA_URL}/api/v1/repos/${{ github.repository }}"
|
API="${GITEA_URL}/api/v1/repos/${{ github.repository }}"
|
||||||
ISSUE_NUM="${{ github.event.issue.number }}"
|
ISSUE_NUM="${{ github.event.issue.number }}"
|
||||||
ISSUE_TITLE="${{ github.event.issue.title }}"
|
ISSUE_TITLE="${{ github.event.issue.title }}"
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
#
|
#
|
||||||
# FILE INFORMATION
|
# FILE INFORMATION
|
||||||
# DEFGROUP: Gitea.Workflow
|
# DEFGROUP: Gitea.Workflow
|
||||||
# INGROUP: mokoplatform.Notifications
|
# INGROUP: MokoStandards.Notifications
|
||||||
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform
|
# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards
|
||||||
# PATH: /.gitea/workflows/notify.yml
|
# PATH: /.gitea/workflows/notify.yml
|
||||||
# VERSION: 09.23.00
|
# VERSION: 01.00.00
|
||||||
# BRIEF: Push notifications via ntfy on release success or workflow failure
|
# BRIEF: Push notifications via ntfy on release success or workflow failure
|
||||||
|
|
||||||
name: "Universal: Notifications"
|
name: "Universal: Notifications"
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
#
|
#
|
||||||
# FILE INFORMATION
|
# FILE INFORMATION
|
||||||
# DEFGROUP: Gitea.Workflow
|
# DEFGROUP: Gitea.Workflow
|
||||||
# INGROUP: mokoplatform.CI
|
# INGROUP: moko-platform.CI
|
||||||
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/mokoplatform
|
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/moko-platform
|
||||||
# PATH: /templates/workflows/universal/pr-check.yml.template
|
# PATH: /templates/workflows/universal/pr-check.yml.template
|
||||||
# VERSION: 09.23.00
|
# VERSION: 09.23.00
|
||||||
# BRIEF: PR gate — branch policy + code validation before merge
|
# BRIEF: PR gate — branch policy + code validation before merge
|
||||||
|
|||||||
@@ -9,244 +9,3 @@
|
|||||||
# PATH: /templates/workflows/universal/pre-release.yml.template
|
# PATH: /templates/workflows/universal/pre-release.yml.template
|
||||||
# VERSION: 05.01.00
|
# VERSION: 05.01.00
|
||||||
# BRIEF: Auto pre-release on push to dev/alpha/beta/rc branches
|
# BRIEF: Auto pre-release on push to dev/alpha/beta/rc branches
|
||||||
|
|
||||||
name: "Universal: Pre-Release"
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- dev
|
|
||||||
- 'fix/**'
|
|
||||||
- 'patch/**'
|
|
||||||
- 'hotfix/**'
|
|
||||||
- 'bugfix/**'
|
|
||||||
- 'chore/**'
|
|
||||||
- alpha
|
|
||||||
- beta
|
|
||||||
- rc
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
stability:
|
|
||||||
description: 'Pre-release channel'
|
|
||||||
required: true
|
|
||||||
type: choice
|
|
||||||
options:
|
|
||||||
- development
|
|
||||||
- alpha
|
|
||||||
- beta
|
|
||||||
- release-candidate
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
env:
|
|
||||||
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
|
|
||||||
GITEA_ORG: ${{ vars.GITEA_ORG || github.repository_owner }}
|
|
||||||
GITEA_REPO: ${{ vars.GITEA_REPO || github.event.repository.name }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: "Build Pre-Release (${{ inputs.stability || github.ref_name }})"
|
|
||||||
runs-on: release
|
|
||||||
if: >-
|
|
||||||
github.event_name == 'workflow_dispatch' ||
|
|
||||||
github.event_name == 'push'
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
token: ${{ secrets.MOKOGITEA_TOKEN }}
|
|
||||||
ref: ${{ github.ref_name }}
|
|
||||||
|
|
||||||
- name: Setup moko-platform tools
|
|
||||||
env:
|
|
||||||
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
|
|
||||||
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
|
|
||||||
run: |
|
|
||||||
# Use pre-installed /opt/moko-platform if available (updated by cron every 6h)
|
|
||||||
if [ -f /opt/moko-platform/cli/version_bump.php ] && [ -f /opt/moko-platform/cli/manifest_element.php ] && [ -f /opt/moko-platform/vendor/autoload.php ]; then
|
|
||||||
echo Using pre-installed /opt/moko-platform
|
|
||||||
echo MOKO_CLI=/opt/moko-platform/cli >> $GITHUB_ENV
|
|
||||||
else
|
|
||||||
echo Falling back to fresh clone
|
|
||||||
if ! command -v composer > /dev/null 2>&1; then
|
|
||||||
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer > /dev/null 2>&1
|
|
||||||
fi
|
|
||||||
rm -rf /tmp/moko-platform-api
|
|
||||||
CLONE_URL=https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git
|
|
||||||
git clone --depth 1 --branch main --quiet $CLONE_URL /tmp/moko-platform-api
|
|
||||||
cd /tmp/moko-platform-api && composer install --no-dev --no-interaction --quiet
|
|
||||||
echo MOKO_CLI=/tmp/moko-platform-api/cli >> $GITHUB_ENV
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Detect platform
|
|
||||||
id: platform
|
|
||||||
run: |
|
|
||||||
# Auto-detect and update platform if not set in manifest
|
|
||||||
php ${MOKO_CLI}/platform_detect.php --path . --github-output 2>/dev/null || true
|
|
||||||
php ${MOKO_CLI}/manifest_read.php --path . --github-output
|
|
||||||
|
|
||||||
- name: Resolve metadata and bump version
|
|
||||||
id: meta
|
|
||||||
run: |
|
|
||||||
# Auto-detect stability from branch name on push, or use input on dispatch
|
|
||||||
if [ "${{ github.event_name }}" = "push" ]; then
|
|
||||||
case "${{ github.ref_name }}" in
|
|
||||||
rc) STABILITY="release-candidate" ;;
|
|
||||||
alpha) STABILITY="alpha" ;;
|
|
||||||
beta) STABILITY="beta" ;;
|
|
||||||
*) STABILITY="development" ;;
|
|
||||||
esac
|
|
||||||
else
|
|
||||||
STABILITY="${{ inputs.stability || 'development' }}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
case "$STABILITY" in
|
|
||||||
development) SUFFIX="-dev"; TAG="development" ;;
|
|
||||||
alpha) SUFFIX="-alpha"; TAG="alpha" ;;
|
|
||||||
beta) SUFFIX="-beta"; TAG="beta" ;;
|
|
||||||
release-candidate) SUFFIX="-rc"; TAG="release-candidate" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Bump version via CLI: patch for dev/alpha/beta, minor for RC
|
|
||||||
case "$STABILITY" in
|
|
||||||
release-candidate) BUMP="minor" ;;
|
|
||||||
*) BUMP="patch" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
php ${MOKO_CLI}/version_bump.php --path . $([ "$BUMP" = "minor" ] && echo "--minor") 2>/dev/null || true
|
|
||||||
|
|
||||||
# Set stability suffix and verify consistency
|
|
||||||
VERSION=$(php ${MOKO_CLI}/version_read.php --path . 2>/dev/null || echo "00.00.01")
|
|
||||||
VERSION=$(echo "$VERSION" | sed 's/-\(dev\|alpha\|beta\|rc\)$//')
|
|
||||||
|
|
||||||
php ${MOKO_CLI}/version_set_platform.php \
|
|
||||||
--path . --version "$VERSION" --branch "${{ github.ref_name }}" --stability "$STABILITY" 2>/dev/null || true
|
|
||||||
php ${MOKO_CLI}/version_check.php --path . --fix 2>/dev/null || true
|
|
||||||
|
|
||||||
# Ensure licensing tags (updateservers, dlid) if enabled in manifest.xml
|
|
||||||
php ${MOKO_CLI}/manifest_licensing.php --path . --fix 2>/dev/null || true
|
|
||||||
|
|
||||||
# Append suffix for output
|
|
||||||
if [ -n "$SUFFIX" ]; then
|
|
||||||
VERSION="${VERSION}${SUFFIX}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Commit version bump
|
|
||||||
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
|
|
||||||
git config --local user.name "gitea-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 || {
|
|
||||||
git commit -m "chore(version): pre-release bump to ${VERSION} [skip ci]"
|
|
||||||
git push origin HEAD 2>&1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Auto-detect element via manifest_element.php
|
|
||||||
php ${MOKO_CLI}/manifest_element.php \
|
|
||||||
--path . --version "$VERSION" --stability "$STABILITY" \
|
|
||||||
--repo "${GITEA_REPO}" --github-output
|
|
||||||
|
|
||||||
# Read back element outputs
|
|
||||||
EXT_ELEMENT=$(grep '^ext_element=' "$GITHUB_OUTPUT" | tail -1 | cut -d= -f2)
|
|
||||||
ZIP_NAME=$(grep '^zip_name=' "$GITHUB_OUTPUT" | tail -1 | cut -d= -f2)
|
|
||||||
[ -z "$EXT_ELEMENT" ] && EXT_ELEMENT=$(echo "${GITEA_REPO}" | tr '[:upper:]' '[:lower:]' | tr -d ' -')
|
|
||||||
[ -z "$ZIP_NAME" ] && ZIP_NAME="${EXT_ELEMENT}-${VERSION}.zip"
|
|
||||||
|
|
||||||
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "stability=${STABILITY}" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "suffix=${SUFFIX}" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "zip_name=${ZIP_NAME}" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "ext_element=${EXT_ELEMENT}" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
echo "=== Pre-Release: ${EXT_ELEMENT} ${VERSION}${SUFFIX} ==="
|
|
||||||
|
|
||||||
- name: Create release
|
|
||||||
id: release
|
|
||||||
run: |
|
|
||||||
TAG="${{ steps.meta.outputs.tag }}"
|
|
||||||
VERSION="${{ steps.meta.outputs.version }}"
|
|
||||||
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
|
||||||
php ${MOKO_CLI}/release_create.php \
|
|
||||||
--path . --version "$VERSION" --tag "$TAG" \
|
|
||||||
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
|
|
||||||
--repo "${GITEA_REPO}" --branch "${{ github.ref_name }}" --prerelease
|
|
||||||
|
|
||||||
- name: Update release notes from CHANGELOG.md
|
|
||||||
run: |
|
|
||||||
TAG="${{ steps.meta.outputs.tag }}"
|
|
||||||
VERSION="${{ steps.meta.outputs.version }}"
|
|
||||||
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
|
||||||
|
|
||||||
# Extract [Unreleased] section from changelog (everything between [Unreleased] and next ## heading)
|
|
||||||
if [ -f "CHANGELOG.md" ]; then
|
|
||||||
NOTES=$(awk '/^## \[Unreleased\]/{found=1; next} /^## \[/{if(found) exit} found{print}' CHANGELOG.md)
|
|
||||||
[ -z "$NOTES" ] && NOTES="Release ${VERSION}"
|
|
||||||
else
|
|
||||||
NOTES="Release ${VERSION}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Update release body via API
|
|
||||||
RELEASE_ID=$(curl -sf -H "Authorization: token ${{ secrets.MOKOGITEA_TOKEN }}" \
|
|
||||||
"${API_BASE}/releases/tags/${TAG}" | python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
|
|
||||||
|
|
||||||
if [ -n "$RELEASE_ID" ]; then
|
|
||||||
python3 -c "
|
|
||||||
import json, urllib.request
|
|
||||||
body = open('/dev/stdin').read()
|
|
||||||
payload = json.dumps({'body': body}).encode()
|
|
||||||
req = urllib.request.Request(
|
|
||||||
'${API_BASE}/releases/${RELEASE_ID}',
|
|
||||||
data=payload, method='PATCH',
|
|
||||||
headers={
|
|
||||||
'Authorization': 'token ${{ secrets.MOKOGITEA_TOKEN }}',
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
})
|
|
||||||
urllib.request.urlopen(req)
|
|
||||||
" <<< "$NOTES"
|
|
||||||
echo "Release notes updated from CHANGELOG.md"
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Build package and upload
|
|
||||||
id: package
|
|
||||||
run: |
|
|
||||||
VERSION="${{ steps.meta.outputs.version }}"
|
|
||||||
TAG="${{ steps.meta.outputs.tag }}"
|
|
||||||
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
|
||||||
php ${MOKO_CLI}/release_package.php \
|
|
||||||
--path . --version "$VERSION" --tag "$TAG" \
|
|
||||||
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
|
|
||||||
--repo "${GITEA_REPO}" --output /tmp || true
|
|
||||||
|
|
||||||
# updates.xml is generated dynamically by MokoGitea license server
|
|
||||||
# No need to build, commit, or sync updates.xml from workflows
|
|
||||||
|
|
||||||
- name: "Delete lesser pre-release channels (cascade)"
|
|
||||||
continue-on-error: true
|
|
||||||
run: |
|
|
||||||
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
|
||||||
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
|
|
||||||
|
|
||||||
php ${MOKO_CLI}/release_cascade.php \
|
|
||||||
--stability "${{ steps.meta.outputs.stability }}" \
|
|
||||||
--token "${TOKEN}" \
|
|
||||||
--api-base "${API_BASE}"
|
|
||||||
|
|
||||||
- name: Summary
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
VERSION="${{ steps.meta.outputs.version }}"
|
|
||||||
STABILITY="${{ steps.meta.outputs.stability }}"
|
|
||||||
ZIP_NAME="${{ steps.meta.outputs.zip_name }}"
|
|
||||||
SHA256="${{ steps.package.outputs.sha256_zip }}"
|
|
||||||
echo "## Pre-Release Complete" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "|-------|-------|" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "| Version | \`${VERSION}\` |" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "| Channel | ${STABILITY} |" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "| Package | \`${ZIP_NAME}\` |" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "| SHA-256 | \`${SHA256:-n/a}\` |" >> $GITHUB_STEP_SUMMARY
|
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
#
|
|
||||||
# FILE INFORMATION
|
|
||||||
# DEFGROUP: Gitea.Workflow
|
|
||||||
# INGROUP: MokoPlatform.Universal
|
|
||||||
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
|
|
||||||
# PATH: /.mokogitea/workflows/rc-revert.yml
|
|
||||||
# VERSION: 09.23.00
|
|
||||||
# BRIEF: Rename rc/ branch back to dev/ when PR is closed without merge
|
|
||||||
|
|
||||||
name: "RC Revert"
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [closed]
|
|
||||||
|
|
||||||
env:
|
|
||||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
revert:
|
|
||||||
name: Rename rc/ back to dev/
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: >-
|
|
||||||
github.event.pull_request.merged == false &&
|
|
||||||
startsWith(github.event.pull_request.head.ref, 'rc/')
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Rename branch
|
|
||||||
run: |
|
|
||||||
BRANCH="${{ github.event.pull_request.head.ref }}"
|
|
||||||
SUFFIX="${BRANCH#rc/}"
|
|
||||||
DEV_BRANCH="dev/${SUFFIX}"
|
|
||||||
API="${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}/api/v1/repos/${{ github.repository }}/branches"
|
|
||||||
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
|
|
||||||
|
|
||||||
# Create dev/ branch from rc/ branch
|
|
||||||
STATUS=$(curl -sf -o /dev/null -w "%{http_code}" -X POST \
|
|
||||||
-H "Authorization: token ${TOKEN}" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d "{\"new_branch_name\": \"${DEV_BRANCH}\", \"old_branch_name\": \"${BRANCH}\"}" \
|
|
||||||
"${API}" 2>/dev/null || true)
|
|
||||||
|
|
||||||
if [ "$STATUS" = "201" ]; then
|
|
||||||
echo "Created branch: ${DEV_BRANCH}" >> $GITHUB_STEP_SUMMARY
|
|
||||||
else
|
|
||||||
echo "::error::Failed to create ${DEV_BRANCH} from ${BRANCH} (HTTP ${STATUS})"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Delete rc/ branch
|
|
||||||
ENCODED=$(php -r "echo rawurlencode('${BRANCH}');")
|
|
||||||
STATUS=$(curl -sf -o /dev/null -w "%{http_code}" -X DELETE \
|
|
||||||
-H "Authorization: token ${TOKEN}" \
|
|
||||||
"${API}/${ENCODED}" 2>/dev/null || true)
|
|
||||||
|
|
||||||
if [ "$STATUS" = "204" ]; then
|
|
||||||
echo "Deleted branch: ${BRANCH}" >> $GITHUB_STEP_SUMMARY
|
|
||||||
else
|
|
||||||
echo "::warning::Failed to delete ${BRANCH} (HTTP ${STATUS})"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "### RC Reverted" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "${BRANCH} → ${DEV_BRANCH}" >> $GITHUB_STEP_SUMMARY
|
|
||||||
@@ -7,8 +7,8 @@
|
|||||||
#
|
#
|
||||||
# FILE INFORMATION
|
# FILE INFORMATION
|
||||||
# DEFGROUP: Gitea.Workflow
|
# DEFGROUP: Gitea.Workflow
|
||||||
# INGROUP: mokoplatform.Validation
|
# INGROUP: moko-platform.Validation
|
||||||
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/mokoplatform
|
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/moko-platform
|
||||||
# PATH: /templates/workflows/joomla/repo_health.yml.template
|
# PATH: /templates/workflows/joomla/repo_health.yml.template
|
||||||
# VERSION: 09.23.00
|
# VERSION: 09.23.00
|
||||||
# BRIEF: Enforces repository guardrails by validating scripts governance, tooling availability, and core repository health artifacts.
|
# BRIEF: Enforces repository guardrails by validating scripts governance, tooling availability, and core repository health artifacts.
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
#
|
#
|
||||||
# FILE INFORMATION
|
# FILE INFORMATION
|
||||||
# DEFGROUP: Gitea.Workflow
|
# DEFGROUP: Gitea.Workflow
|
||||||
# INGROUP: mokoplatform.Security
|
# INGROUP: MokoStandards.Security
|
||||||
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform
|
# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards
|
||||||
# PATH: /.gitea/workflows/security-audit.yml
|
# PATH: /.gitea/workflows/security-audit.yml
|
||||||
# VERSION: 09.23.00
|
# VERSION: 01.00.00
|
||||||
# BRIEF: Dependency vulnerability scanning for composer and npm packages
|
# BRIEF: Dependency vulnerability scanning for composer and npm packages
|
||||||
|
|
||||||
name: "Universal: Security Audit"
|
name: "Universal: Security Audit"
|
||||||
@@ -80,19 +80,3 @@ jobs:
|
|||||||
-H "Priority: high" \
|
-H "Priority: high" \
|
||||||
-d "Security audit found vulnerabilities. Review dependency updates." \
|
-d "Security audit found vulnerabilities. Review dependency updates." \
|
||||||
"${NTFY_URL}/${NTFY_TOPIC}" || true
|
"${NTFY_URL}/${NTFY_TOPIC}" || true
|
||||||
|
|
||||||
|
|
||||||
- name: Joomla version audit
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
if [ -f "monitoring/joomla-version-audit.php" ] && [ -n "$JOOMLA_SITES" ]; then
|
|
||||||
echo "$JOOMLA_SITES" > /tmp/sites.json
|
|
||||||
php monitoring/joomla-version-audit.php --sites /tmp/sites.json || true
|
|
||||||
echo "### Joomla Version Audit" >> $GITHUB_STEP_SUMMARY
|
|
||||||
rm -f /tmp/sites.json
|
|
||||||
else
|
|
||||||
echo "Joomla audit skipped (no script or JOOMLA_SITES_JSON not configured)"
|
|
||||||
fi
|
|
||||||
env:
|
|
||||||
JOOMLA_SITES: ${{ vars.JOOMLA_SITES_JSON }}
|
|
||||||
|
|
||||||
|
|||||||
+2
-9
@@ -1,13 +1,6 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Admin submenu items (Dashboard, Backups, Profiles) not created on install — `<submenu>` block in manifest was empty
|
|
||||||
- Submenu items not created on update — added `ensureSubmenuItems()` using Joomla's `MenuTable` API with proper nested set positioning
|
|
||||||
- Submenu icons not rendering in Joomla 6 — set `menu_icon` param for level 2+ items (Atum only renders `img` column icons for level 1)
|
|
||||||
- CSS selector `#menu` → `.main-nav` for icon injection (Joomla 6 uses dynamic `id="menu{moduleId}"`)
|
|
||||||
- Use `margin-inline-end` instead of `margin-right` for RTL layout support
|
|
||||||
|
|
||||||
## [01.08.00] --- 2026-06-07
|
## [01.08.00] --- 2026-06-07
|
||||||
|
|
||||||
## [01.07.00] --- 2026-06-07
|
## [01.07.00] --- 2026-06-07
|
||||||
@@ -19,13 +12,13 @@
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
- Dashboard submenu entry as default landing page with `class:home` icon
|
- Dashboard submenu entry as default landing page with `class:home` icon
|
||||||
- `[DEFAULT_DIR]` placeholder for portable backup directory configuration — resolves to `administrator/components/com_mokosuitebackup/backups` at runtime
|
- `[DEFAULT_DIR]` placeholder for portable backup directory configuration — resolves to `administrator/components/com_mokojoombackup/backups` at runtime
|
||||||
- Live AJAX directory validation on backup_dir field — checks existence, writability, and placeholder resolution as user types (debounced 400ms)
|
- Live AJAX directory validation on backup_dir field — checks existence, writability, and placeholder resolution as user types (debounced 400ms)
|
||||||
- `checkDir` AJAX endpoint for real-time directory permission checking
|
- `checkDir` AJAX endpoint for real-time directory permission checking
|
||||||
- Web-accessible warning badge on backup download buttons when archive is inside web root
|
- Web-accessible warning badge on backup download buttons when archive is inside web root
|
||||||
- Inline security warning in FolderPicker when default directory is selected
|
- Inline security warning in FolderPicker when default directory is selected
|
||||||
- Auto `.htaccess` and `index.html` protection for web-accessible backup directories on profile save and at backup time
|
- Auto `.htaccess` and `index.html` protection for web-accessible backup directories on profile save and at backup time
|
||||||
- Font Awesome 6 submenu icons via CSS injection in `MokoSuiteBackupComponent::boot()`
|
- Font Awesome 6 submenu icons via CSS injection in `MokoJoomBackupComponent::boot()`
|
||||||
- `syncMenuIcons()` installer postflight — syncs icon classes to `#__menu` on install and update
|
- `syncMenuIcons()` installer postflight — syncs icon classes to `#__menu` on install and update
|
||||||
- `encryptionPassword` property on `SteppedSession` for upcoming stepped backup encryption support
|
- `encryptionPassword` property on `SteppedSession` for upcoming stepped backup encryption support
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -1,6 +1,6 @@
|
|||||||
# Contributing to MokoSuiteBackup
|
# Contributing to MokoJoomBackup
|
||||||
|
|
||||||
Thank you for your interest in contributing to MokoSuiteBackup.
|
Thank you for your interest in contributing to MokoJoomBackup.
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ Thank you for your interest in contributing to MokoSuiteBackup.
|
|||||||
|
|
||||||
## Reporting Issues
|
## Reporting Issues
|
||||||
|
|
||||||
Report bugs and feature requests via [Issues](https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteBackup/issues).
|
Report bugs and feature requests via [Issues](https://git.mokoconsulting.tech/MokoConsulting/MokoJoomBackup/issues).
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
#
|
#
|
||||||
# MokoSuiteBackup — Full-site backup and restore for Joomla
|
# MokoJoomBackup — Full-site backup and restore for Joomla
|
||||||
#
|
#
|
||||||
# Builds and releases are handled by CI workflows (pre-release.yml,
|
# Builds and releases are handled by CI workflows (pre-release.yml,
|
||||||
# auto-release.yml). This Makefile provides local validation helpers
|
# auto-release.yml). This Makefile provides local validation helpers
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
# CONFIGURATION
|
# CONFIGURATION
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
|
|
||||||
EXTENSION_NAME := mokosuitebackup
|
EXTENSION_NAME := mokojoombackup
|
||||||
EXTENSION_TYPE := package
|
EXTENSION_TYPE := package
|
||||||
|
|
||||||
SRC_DIR := source
|
SRC_DIR := source
|
||||||
@@ -20,7 +20,7 @@ SRC_DIR := source
|
|||||||
# Gitea
|
# Gitea
|
||||||
GITEA_URL := https://git.mokoconsulting.tech
|
GITEA_URL := https://git.mokoconsulting.tech
|
||||||
GITEA_ORG := MokoConsulting
|
GITEA_ORG := MokoConsulting
|
||||||
GITEA_REPO := MokoSuiteBackup
|
GITEA_REPO := MokoJoomBackup
|
||||||
|
|
||||||
# Tools
|
# Tools
|
||||||
PHP := php
|
PHP := php
|
||||||
@@ -44,7 +44,7 @@ COLOR_RED := \033[31m
|
|||||||
.PHONY: help
|
.PHONY: help
|
||||||
help: ## Show this help message
|
help: ## Show this help message
|
||||||
@echo "$(COLOR_BLUE)╔════════════════════════════════════════════════════════════╗$(COLOR_RESET)"
|
@echo "$(COLOR_BLUE)╔════════════════════════════════════════════════════════════╗$(COLOR_RESET)"
|
||||||
@echo "$(COLOR_BLUE)║ MokoSuiteBackup Makefile ║$(COLOR_RESET)"
|
@echo "$(COLOR_BLUE)║ MokoJoomBackup Makefile ║$(COLOR_RESET)"
|
||||||
@echo "$(COLOR_BLUE)╚════════════════════════════════════════════════════════════╝$(COLOR_RESET)"
|
@echo "$(COLOR_BLUE)╚════════════════════════════════════════════════════════════╝$(COLOR_RESET)"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "$(COLOR_GREEN)Available targets:$(COLOR_RESET)"
|
@echo "$(COLOR_GREEN)Available targets:$(COLOR_RESET)"
|
||||||
@@ -158,7 +158,7 @@ release-rc: validate validate-xml ## Trigger release-candidate build via CI work
|
|||||||
|
|
||||||
.PHONY: version
|
.PHONY: version
|
||||||
version: ## Display version from package manifest
|
version: ## Display version from package manifest
|
||||||
@VERSION=$$(grep '<version>' $(SRC_DIR)/pkg_mokosuitebackup.xml | sed 's/.*<version>\(.*\)<\/version>.*/\1/'); \
|
@VERSION=$$(grep '<version>' $(SRC_DIR)/pkg_mokojoombackup.xml | sed 's/.*<version>\(.*\)<\/version>.*/\1/'); \
|
||||||
echo "$(COLOR_BLUE)$(EXTENSION_NAME)$(COLOR_RESET) v$$VERSION ($(EXTENSION_TYPE))"
|
echo "$(COLOR_BLUE)$(EXTENSION_NAME)$(COLOR_RESET) v$$VERSION ($(EXTENSION_TYPE))"
|
||||||
|
|
||||||
# Default target
|
# Default target
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# MokoSuiteBackup
|
# MokoJoomBackup
|
||||||
|
|
||||||
<!-- VERSION: 01.08.17 -->
|
<!-- VERSION: 01.08.00 -->
|
||||||
|
|
||||||
Full-site backup and restore for Joomla — database, files, and configuration.
|
Full-site backup and restore for Joomla — database, files, and configuration.
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
MokoSuiteBackup is a comprehensive backup solution for Joomla 4/5/6 sites. It creates complete site backups including the database, files, and configuration, packaged into downloadable ZIP archives. Supports multiple backup profiles, scheduled backups via CLI/cron, and a REST API for remote management.
|
MokoJoomBackup is a comprehensive backup solution for Joomla 4/5/6 sites. It creates complete site backups including the database, files, and configuration, packaged into downloadable ZIP archives. Supports multiple backup profiles, scheduled backups via CLI/cron, and a REST API for remote management.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
@@ -25,13 +25,13 @@ MokoSuiteBackup is a comprehensive backup solution for Joomla 4/5/6 sites. It cr
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
1. Download `pkg_mokobackup-*.zip` from [Releases](https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteBackup/releases)
|
1. Download `pkg_mokobackup-*.zip` from [Releases](https://git.mokoconsulting.tech/MokoConsulting/MokoJoomBackup/releases)
|
||||||
2. Joomla Administrator > Extensions > Install
|
2. Joomla Administrator > Extensions > Install
|
||||||
3. System plugin enabled automatically on install
|
3. System plugin enabled automatically on install
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
- **Component**: Administrator > Components > MokoSuiteBackup
|
- **Component**: Administrator > Components > MokoJoomBackup
|
||||||
- **Profiles**: Create backup profiles with different file/database filters
|
- **Profiles**: Create backup profiles with different file/database filters
|
||||||
- **System Plugin**: Configure scheduled backup triggers and notifications
|
- **System Plugin**: Configure scheduled backup triggers and notifications
|
||||||
- **CLI**: `php cli/mokobackup.php --profile=1` for cron-based backups
|
- **CLI**: `php cli/mokobackup.php --profile=1` for cron-based backups
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
; MokoJoomBackup — Package language file (en-GB)
|
||||||
|
; @package MokoJoomBackup
|
||||||
|
; @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
|
; @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
|
; @license GPL-3.0-or-later
|
||||||
|
|
||||||
|
PKG_MOKOJOOMBACKUP="Package - MokoJoomBackup"
|
||||||
|
PKG_MOKOJOOMBACKUP_DESCRIPTION="Full-site backup and restore for Joomla — database, files, and configuration. Includes admin component, system plugin, and REST API."
|
||||||
|
PKG_MOKOJOOMBACKUP_PHP_VERSION_ERROR="MokoJoomBackup requires PHP %s or later."
|
||||||
|
PKG_MOKOJOOMBACKUP_POSTINSTALL_UPDATE_SITE="MokoJoomBackup installed successfully. Configure your <a href=\"%s\">Update Site</a> to receive automatic updates."
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
; MokoSuiteBackup — Package language file (en-GB)
|
|
||||||
; @package MokoSuiteBackup
|
|
||||||
; @author Moko Consulting <hello@mokoconsulting.tech>
|
|
||||||
; @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
|
||||||
; @license GPL-3.0-or-later
|
|
||||||
|
|
||||||
PKG_MOKOJOOMBACKUP="Package - MokoSuiteBackup"
|
|
||||||
PKG_MOKOJOOMBACKUP_DESCRIPTION="Full-site backup and restore for Joomla — database, files, and configuration. Includes admin component, system plugin, and REST API."
|
|
||||||
PKG_MOKOJOOMBACKUP_PHP_VERSION_ERROR="MokoSuiteBackup requires PHP %s or later."
|
|
||||||
PKG_MOKOJOOMBACKUP_POSTINSTALL_UPDATE_SITE="MokoSuiteBackup installed successfully. Configure your <a href=\"%s\">Update Site</a> to receive automatic updates."
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
; MokoJoomBackup — Package language file (en-US)
|
||||||
|
; @package MokoJoomBackup
|
||||||
|
; @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
|
; @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
|
; @license GPL-3.0-or-later
|
||||||
|
|
||||||
|
PKG_MOKOJOOMBACKUP="Package - MokoJoomBackup"
|
||||||
|
PKG_MOKOJOOMBACKUP_DESCRIPTION="Full-site backup and restore for Joomla — database, files, and configuration. Includes admin component, system plugin, and REST API."
|
||||||
|
PKG_MOKOJOOMBACKUP_PHP_VERSION_ERROR="MokoJoomBackup requires PHP %s or later."
|
||||||
|
PKG_MOKOJOOMBACKUP_POSTINSTALL_UPDATE_SITE="MokoJoomBackup installed successfully. Configure your <a href=\"%s\">Update Site</a> to receive automatic updates."
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
; MokoSuiteBackup — Package language file (en-US)
|
|
||||||
; @package MokoSuiteBackup
|
|
||||||
; @author Moko Consulting <hello@mokoconsulting.tech>
|
|
||||||
; @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
|
||||||
; @license GPL-3.0-or-later
|
|
||||||
|
|
||||||
PKG_MOKOJOOMBACKUP="Package - MokoSuiteBackup"
|
|
||||||
PKG_MOKOJOOMBACKUP_DESCRIPTION="Full-site backup and restore for Joomla — database, files, and configuration. Includes admin component, system plugin, and REST API."
|
|
||||||
PKG_MOKOJOOMBACKUP_PHP_VERSION_ERROR="MokoSuiteBackup requires PHP %s or later."
|
|
||||||
PKG_MOKOJOOMBACKUP_POSTINSTALL_UPDATE_SITE="MokoSuiteBackup installed successfully. Configure your <a href=\"%s\">Update Site</a> to receive automatic updates."
|
|
||||||
+7
-7
@@ -1,19 +1,19 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Api\Controller;
|
namespace Joomla\Component\MokoJoomBackup\Api\Controller;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
use Joomla\CMS\MVC\Controller\ApiController;
|
use Joomla\CMS\MVC\Controller\ApiController;
|
||||||
use Joomla\Component\MokoSuiteBackup\Administrator\Engine\BackupEngine;
|
use Joomla\Component\MokoJoomBackup\Administrator\Engine\BackupEngine;
|
||||||
|
|
||||||
class BackupsController extends ApiController
|
class BackupsController extends ApiController
|
||||||
{
|
{
|
||||||
@@ -21,7 +21,7 @@ class BackupsController extends ApiController
|
|||||||
protected $default_view = 'backups';
|
protected $default_view = 'backups';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start a new backup (POST /api/index.php/v1/mokosuitebackup/backup)
|
* Start a new backup (POST /api/index.php/v1/mokojoombackup/backup)
|
||||||
*/
|
*/
|
||||||
public function backup(): static
|
public function backup(): static
|
||||||
{
|
{
|
||||||
@@ -47,7 +47,7 @@ class BackupsController extends ApiController
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Download a backup archive (GET /api/index.php/v1/mokosuitebackup/backup/:id/download)
|
* Download a backup archive (GET /api/index.php/v1/mokojoombackup/backup/:id/download)
|
||||||
*/
|
*/
|
||||||
public function download(): static
|
public function download(): static
|
||||||
{
|
{
|
||||||
@@ -74,7 +74,7 @@ class BackupsController extends ApiController
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List backup profiles (GET /api/index.php/v1/mokosuitebackup/profiles)
|
* List backup profiles (GET /api/index.php/v1/mokojoombackup/profiles)
|
||||||
*/
|
*/
|
||||||
public function profiles(): static
|
public function profiles(): static
|
||||||
{
|
{
|
||||||
+3
-3
@@ -1,14 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Api\View\Backups;
|
namespace Joomla\Component\MokoJoomBackup\Api\View\Backups;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
+5
-5
@@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
* CLI backup script for cron/scheduled use.
|
* CLI backup script for cron/scheduled use.
|
||||||
*
|
*
|
||||||
* Usage:
|
* Usage:
|
||||||
* php cli/mokosuitebackup.php --profile=1 --description="Scheduled backup"
|
* php cli/mokojoombackup.php --profile=1 --description="Scheduled backup"
|
||||||
*
|
*
|
||||||
* Must be run from the Joomla root directory.
|
* Must be run from the Joomla root directory.
|
||||||
*/
|
*/
|
||||||
@@ -30,7 +30,7 @@ if (!defined('JPATH_BASE')) {
|
|||||||
require_once JPATH_BASE . '/includes/framework.php';
|
require_once JPATH_BASE . '/includes/framework.php';
|
||||||
|
|
||||||
use Joomla\CMS\Factory;
|
use Joomla\CMS\Factory;
|
||||||
use Joomla\Component\MokoSuiteBackup\Administrator\Engine\BackupEngine;
|
use Joomla\Component\MokoJoomBackup\Administrator\Engine\BackupEngine;
|
||||||
|
|
||||||
// Parse CLI arguments
|
// Parse CLI arguments
|
||||||
$profileId = 1;
|
$profileId = 1;
|
||||||
@@ -51,7 +51,7 @@ if (empty($description)) {
|
|||||||
// Boot the application
|
// Boot the application
|
||||||
$app = Factory::getApplication('administrator');
|
$app = Factory::getApplication('administrator');
|
||||||
|
|
||||||
echo "MokoSuiteBackup CLI\n";
|
echo "MokoJoomBackup CLI\n";
|
||||||
echo "Profile: {$profileId}\n";
|
echo "Profile: {$profileId}\n";
|
||||||
echo "Description: {$description}\n";
|
echo "Description: {$description}\n";
|
||||||
echo "Starting backup...\n\n";
|
echo "Starting backup...\n\n";
|
||||||
+6
-6
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!--
|
<!--
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
@@ -13,15 +13,15 @@
|
|||||||
type="FolderPicker"
|
type="FolderPicker"
|
||||||
label="COM_MOKOJOOMBACKUP_CONFIG_DEFAULT_BACKUP_DIR"
|
label="COM_MOKOJOOMBACKUP_CONFIG_DEFAULT_BACKUP_DIR"
|
||||||
description="COM_MOKOJOOMBACKUP_CONFIG_DEFAULT_BACKUP_DIR_DESC"
|
description="COM_MOKOJOOMBACKUP_CONFIG_DEFAULT_BACKUP_DIR_DESC"
|
||||||
default="administrator/components/com_mokosuitebackup/backups"
|
default="administrator/components/com_mokojoombackup/backups"
|
||||||
addfieldprefix="Joomla\Component\MokoSuiteBackup\Administrator\Field"
|
addfieldprefix="Joomla\Component\MokoJoomBackup\Administrator\Field"
|
||||||
/>
|
/>
|
||||||
<field
|
<field
|
||||||
name="default_profile"
|
name="default_profile"
|
||||||
type="sql"
|
type="sql"
|
||||||
label="COM_MOKOJOOMBACKUP_CONFIG_DEFAULT_PROFILE"
|
label="COM_MOKOJOOMBACKUP_CONFIG_DEFAULT_PROFILE"
|
||||||
description="COM_MOKOJOOMBACKUP_CONFIG_DEFAULT_PROFILE_DESC"
|
description="COM_MOKOJOOMBACKUP_CONFIG_DEFAULT_PROFILE_DESC"
|
||||||
query="SELECT id AS value, title AS text FROM #__mokosuitebackup_profiles WHERE published = 1 ORDER BY ordering ASC"
|
query="SELECT id AS value, title AS text FROM #__mokojoombackup_profiles WHERE published = 1 ORDER BY ordering ASC"
|
||||||
default="1"
|
default="1"
|
||||||
>
|
>
|
||||||
<option value="1">Default Backup Profile</option>
|
<option value="1">Default Backup Profile</option>
|
||||||
@@ -133,7 +133,7 @@
|
|||||||
label="JCONFIG_PERMISSIONS_LABEL"
|
label="JCONFIG_PERMISSIONS_LABEL"
|
||||||
filter="rules"
|
filter="rules"
|
||||||
validate="rules"
|
validate="rules"
|
||||||
component="com_mokosuitebackup"
|
component="com_mokojoombackup"
|
||||||
section="component"
|
section="component"
|
||||||
/>
|
/>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
+4
-4
@@ -68,7 +68,7 @@
|
|||||||
label="COM_MOKOJOOMBACKUP_FIELD_BACKUP_DIR"
|
label="COM_MOKOJOOMBACKUP_FIELD_BACKUP_DIR"
|
||||||
description="COM_MOKOJOOMBACKUP_FIELD_BACKUP_DIR_DESC"
|
description="COM_MOKOJOOMBACKUP_FIELD_BACKUP_DIR_DESC"
|
||||||
default="[DEFAULT_DIR]"
|
default="[DEFAULT_DIR]"
|
||||||
addfieldprefix="Joomla\Component\MokoSuiteBackup\Administrator\Field"
|
addfieldprefix="Joomla\Component\MokoJoomBackup\Administrator\Field"
|
||||||
/>
|
/>
|
||||||
<field
|
<field
|
||||||
name="archive_name_format"
|
name="archive_name_format"
|
||||||
@@ -129,7 +129,7 @@
|
|||||||
description="COM_MOKOJOOMBACKUP_FIELD_EXCLUDE_DIRS_DESC"
|
description="COM_MOKOJOOMBACKUP_FIELD_EXCLUDE_DIRS_DESC"
|
||||||
filter="raw"
|
filter="raw"
|
||||||
hint="tmp"
|
hint="tmp"
|
||||||
addfieldprefix="Joomla\Component\MokoSuiteBackup\Administrator\Field"
|
addfieldprefix="Joomla\Component\MokoJoomBackup\Administrator\Field"
|
||||||
/>
|
/>
|
||||||
<field
|
<field
|
||||||
name="exclude_files"
|
name="exclude_files"
|
||||||
@@ -138,7 +138,7 @@
|
|||||||
description="COM_MOKOJOOMBACKUP_FIELD_EXCLUDE_FILES_DESC"
|
description="COM_MOKOJOOMBACKUP_FIELD_EXCLUDE_FILES_DESC"
|
||||||
filter="raw"
|
filter="raw"
|
||||||
hint="*.bak"
|
hint="*.bak"
|
||||||
addfieldprefix="Joomla\Component\MokoSuiteBackup\Administrator\Field"
|
addfieldprefix="Joomla\Component\MokoJoomBackup\Administrator\Field"
|
||||||
/>
|
/>
|
||||||
<field
|
<field
|
||||||
name="exclude_tables"
|
name="exclude_tables"
|
||||||
@@ -146,7 +146,7 @@
|
|||||||
label="COM_MOKOJOOMBACKUP_FIELD_EXCLUDE_TABLES"
|
label="COM_MOKOJOOMBACKUP_FIELD_EXCLUDE_TABLES"
|
||||||
description="COM_MOKOJOOMBACKUP_FIELD_EXCLUDE_TABLES_DESC"
|
description="COM_MOKOJOOMBACKUP_FIELD_EXCLUDE_TABLES_DESC"
|
||||||
filter="raw"
|
filter="raw"
|
||||||
addfieldprefix="Joomla\Component\MokoSuiteBackup\Administrator\Field"
|
addfieldprefix="Joomla\Component\MokoJoomBackup\Administrator\Field"
|
||||||
/>
|
/>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
+8
-8
@@ -1,10 +1,10 @@
|
|||||||
; MokoSuiteBackup — Component language file (en-GB)
|
; MokoJoomBackup — Component language file (en-GB)
|
||||||
; @package MokoSuiteBackup
|
; @package MokoJoomBackup
|
||||||
; @author Moko Consulting <hello@mokoconsulting.tech>
|
; @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
; @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
; @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
; @license GPL-3.0-or-later
|
; @license GPL-3.0-or-later
|
||||||
|
|
||||||
COM_MOKOJOOMBACKUP="MokoSuiteBackup"
|
COM_MOKOJOOMBACKUP="MokoJoomBackup"
|
||||||
COM_MOKOJOOMBACKUP_DESCRIPTION="Full-site backup and restore for Joomla"
|
COM_MOKOJOOMBACKUP_DESCRIPTION="Full-site backup and restore for Joomla"
|
||||||
|
|
||||||
; Submenu
|
; Submenu
|
||||||
@@ -13,7 +13,7 @@ COM_MOKOJOOMBACKUP_SUBMENU_BACKUPS="Backup Records"
|
|||||||
COM_MOKOJOOMBACKUP_SUBMENU_PROFILES="Backup Profiles"
|
COM_MOKOJOOMBACKUP_SUBMENU_PROFILES="Backup Profiles"
|
||||||
|
|
||||||
; Dashboard view
|
; Dashboard view
|
||||||
COM_MOKOJOOMBACKUP_DASHBOARD_TITLE="MokoSuiteBackup Dashboard"
|
COM_MOKOJOOMBACKUP_DASHBOARD_TITLE="MokoJoomBackup Dashboard"
|
||||||
COM_MOKOJOOMBACKUP_DASHBOARD_LAST_BACKUP="Last Backup"
|
COM_MOKOJOOMBACKUP_DASHBOARD_LAST_BACKUP="Last Backup"
|
||||||
COM_MOKOJOOMBACKUP_DASHBOARD_NO_BACKUPS="No backups yet"
|
COM_MOKOJOOMBACKUP_DASHBOARD_NO_BACKUPS="No backups yet"
|
||||||
COM_MOKOJOOMBACKUP_DASHBOARD_NEXT_SCHEDULED="Next Scheduled"
|
COM_MOKOJOOMBACKUP_DASHBOARD_NEXT_SCHEDULED="Next Scheduled"
|
||||||
@@ -94,7 +94,7 @@ COM_MOKOJOOMBACKUP_FIELD_ENCRYPTION_PASSWORD_DESC="Set a password to encrypt the
|
|||||||
COM_MOKOJOOMBACKUP_FIELD_SPLIT_SIZE="Split Size (MB)"
|
COM_MOKOJOOMBACKUP_FIELD_SPLIT_SIZE="Split Size (MB)"
|
||||||
COM_MOKOJOOMBACKUP_FIELD_SPLIT_SIZE_DESC="Split archive into parts of this size in MB. 0 = no splitting."
|
COM_MOKOJOOMBACKUP_FIELD_SPLIT_SIZE_DESC="Split archive into parts of this size in MB. 0 = no splitting."
|
||||||
COM_MOKOJOOMBACKUP_FIELD_BACKUP_DIR="Backup Directory"
|
COM_MOKOJOOMBACKUP_FIELD_BACKUP_DIR="Backup Directory"
|
||||||
COM_MOKOJOOMBACKUP_FIELD_BACKUP_DIR_DESC="Directory where backup archives are stored. Supports placeholders: [HOME] (user home directory), [host], [date], [year], [month], [day], [profile_name], [site_name], [type]. Use [HOME]/backups to store outside the web root. Absolute paths (starting with /) are used as-is; relative paths resolve from the Joomla root."
|
COM_MOKOJOOMBACKUP_FIELD_BACKUP_DIR_DESC="Directory where backup archives are stored. Supports placeholders: [host], [date], [year], [month], [day], [profile_name], [site_name], [type]. Absolute paths (starting with /) are used as-is; relative paths resolve from the Joomla root."
|
||||||
COM_MOKOJOOMBACKUP_FIELD_ARCHIVE_NAME_FORMAT="Archive Name Format"
|
COM_MOKOJOOMBACKUP_FIELD_ARCHIVE_NAME_FORMAT="Archive Name Format"
|
||||||
COM_MOKOJOOMBACKUP_FIELD_ARCHIVE_NAME_FORMAT_DESC="Filename template for backup archives (without extension). Placeholders: [host] hostname, [date] Ymd, [time] His, [datetime] Ymd_His, [year] [month] [day] [hour] [minute] [second], [profile_id], [profile_name], [site_name], [type], [random]."
|
COM_MOKOJOOMBACKUP_FIELD_ARCHIVE_NAME_FORMAT_DESC="Filename template for backup archives (without extension). Placeholders: [host] hostname, [date] Ymd, [time] His, [datetime] Ymd_His, [year] [month] [day] [hour] [minute] [second], [profile_id], [profile_name], [site_name], [type], [random]."
|
||||||
COM_MOKOJOOMBACKUP_FIELD_INCLUDE_MOKORESTORE="Include Restore Script"
|
COM_MOKOJOOMBACKUP_FIELD_INCLUDE_MOKORESTORE="Include Restore Script"
|
||||||
@@ -216,8 +216,8 @@ COM_MOKOJOOMBACKUP_AKEEBA_NOT_FOUND="Akeeba Backup tables not found. Is Akeeba B
|
|||||||
|
|
||||||
; Update site notice
|
; Update site notice
|
||||||
COM_MOKOJOOMBACKUP_UPDATE_SITE_NOTICE="To receive automatic updates, configure your <a href=\"%s\">Update Site</a> with your download key."
|
COM_MOKOJOOMBACKUP_UPDATE_SITE_NOTICE="To receive automatic updates, configure your <a href=\"%s\">Update Site</a> with your download key."
|
||||||
COM_MOKOJOOMBACKUP_UPDATE_SITE_MISSING="MokoSuiteBackup update site not found. Reinstall the package to register the update server."
|
COM_MOKOJOOMBACKUP_UPDATE_SITE_MISSING="MokoJoomBackup update site not found. Reinstall the package to register the update server."
|
||||||
COM_MOKOJOOMBACKUP_POSTINSTALL_UPDATE_SITE="MokoSuiteBackup installed successfully. Configure your <a href=\"%s\">Update Site</a> to receive automatic updates."
|
COM_MOKOJOOMBACKUP_POSTINSTALL_UPDATE_SITE="MokoJoomBackup installed successfully. Configure your <a href=\"%s\">Update Site</a> to receive automatic updates."
|
||||||
|
|
||||||
; Component Options (config.xml)
|
; Component Options (config.xml)
|
||||||
COM_MOKOJOOMBACKUP_CONFIG_GENERAL="General"
|
COM_MOKOJOOMBACKUP_CONFIG_GENERAL="General"
|
||||||
@@ -245,7 +245,7 @@ COM_MOKOJOOMBACKUP_CONFIG_WEBCRON="Web Cron"
|
|||||||
COM_MOKOJOOMBACKUP_CONFIG_WEBCRON_ENABLED="Enable Web Cron"
|
COM_MOKOJOOMBACKUP_CONFIG_WEBCRON_ENABLED="Enable Web Cron"
|
||||||
COM_MOKOJOOMBACKUP_CONFIG_WEBCRON_ENABLED_DESC="Allow backups to be triggered via a URL with a secret key. Use this when crontab is not available on shared hosting."
|
COM_MOKOJOOMBACKUP_CONFIG_WEBCRON_ENABLED_DESC="Allow backups to be triggered via a URL with a secret key. Use this when crontab is not available on shared hosting."
|
||||||
COM_MOKOJOOMBACKUP_CONFIG_WEBCRON_SECRET="Secret Word"
|
COM_MOKOJOOMBACKUP_CONFIG_WEBCRON_SECRET="Secret Word"
|
||||||
COM_MOKOJOOMBACKUP_CONFIG_WEBCRON_SECRET_DESC="The secret key required in the URL to trigger a backup. Use a long, random string. URL format: index.php?mokosuitebackup_cron=YOUR_SECRET&profile_id=1"
|
COM_MOKOJOOMBACKUP_CONFIG_WEBCRON_SECRET_DESC="The secret key required in the URL to trigger a backup. Use a long, random string. URL format: index.php?mokojoombackup_cron=YOUR_SECRET&profile_id=1"
|
||||||
COM_MOKOJOOMBACKUP_CONFIG_WEBCRON_IP="IP Whitelist"
|
COM_MOKOJOOMBACKUP_CONFIG_WEBCRON_IP="IP Whitelist"
|
||||||
COM_MOKOJOOMBACKUP_CONFIG_WEBCRON_IP_DESC="Comma-separated list of IP addresses allowed to trigger web cron. Leave blank to allow any IP."
|
COM_MOKOJOOMBACKUP_CONFIG_WEBCRON_IP_DESC="Comma-separated list of IP addresses allowed to trigger web cron. Leave blank to allow any IP."
|
||||||
|
|
||||||
+3
-3
@@ -1,10 +1,10 @@
|
|||||||
; MokoSuiteBackup — Component system language file (en-GB)
|
; MokoJoomBackup — Component system language file (en-GB)
|
||||||
; @package MokoSuiteBackup
|
; @package MokoJoomBackup
|
||||||
; @author Moko Consulting <hello@mokoconsulting.tech>
|
; @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
; @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
; @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
; @license GPL-3.0-or-later
|
; @license GPL-3.0-or-later
|
||||||
|
|
||||||
COM_MOKOJOOMBACKUP="MokoSuiteBackup"
|
COM_MOKOJOOMBACKUP="MokoJoomBackup"
|
||||||
COM_MOKOJOOMBACKUP_DESCRIPTION="Full-site backup and restore for Joomla — database, files, and configuration."
|
COM_MOKOJOOMBACKUP_DESCRIPTION="Full-site backup and restore for Joomla — database, files, and configuration."
|
||||||
COM_MOKOJOOMBACKUP_SUBMENU_DASHBOARD="Dashboard"
|
COM_MOKOJOOMBACKUP_SUBMENU_DASHBOARD="Dashboard"
|
||||||
COM_MOKOJOOMBACKUP_SUBMENU_BACKUPS="Backup Records"
|
COM_MOKOJOOMBACKUP_SUBMENU_BACKUPS="Backup Records"
|
||||||
+6
-6
@@ -1,15 +1,15 @@
|
|||||||
; MokoSuiteBackup — Component language file (en-US)
|
; MokoJoomBackup — Component language file (en-US)
|
||||||
; @package MokoSuiteBackup
|
; @package MokoJoomBackup
|
||||||
; @author Moko Consulting <hello@mokoconsulting.tech>
|
; @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
; @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
; @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
; @license GPL-3.0-or-later
|
; @license GPL-3.0-or-later
|
||||||
|
|
||||||
COM_MOKOJOOMBACKUP="MokoSuiteBackup"
|
COM_MOKOJOOMBACKUP="MokoJoomBackup"
|
||||||
COM_MOKOJOOMBACKUP_DESCRIPTION="Full-site backup and restore for Joomla"
|
COM_MOKOJOOMBACKUP_DESCRIPTION="Full-site backup and restore for Joomla"
|
||||||
COM_MOKOJOOMBACKUP_SUBMENU_DASHBOARD="Dashboard"
|
COM_MOKOJOOMBACKUP_SUBMENU_DASHBOARD="Dashboard"
|
||||||
COM_MOKOJOOMBACKUP_SUBMENU_BACKUPS="Backup Records"
|
COM_MOKOJOOMBACKUP_SUBMENU_BACKUPS="Backup Records"
|
||||||
COM_MOKOJOOMBACKUP_SUBMENU_PROFILES="Backup Profiles"
|
COM_MOKOJOOMBACKUP_SUBMENU_PROFILES="Backup Profiles"
|
||||||
COM_MOKOJOOMBACKUP_DASHBOARD_TITLE="MokoSuiteBackup Dashboard"
|
COM_MOKOJOOMBACKUP_DASHBOARD_TITLE="MokoJoomBackup Dashboard"
|
||||||
COM_MOKOJOOMBACKUP_DASHBOARD_LAST_BACKUP="Last Backup"
|
COM_MOKOJOOMBACKUP_DASHBOARD_LAST_BACKUP="Last Backup"
|
||||||
COM_MOKOJOOMBACKUP_DASHBOARD_NO_BACKUPS="No backups yet"
|
COM_MOKOJOOMBACKUP_DASHBOARD_NO_BACKUPS="No backups yet"
|
||||||
COM_MOKOJOOMBACKUP_DASHBOARD_NEXT_SCHEDULED="Next Scheduled"
|
COM_MOKOJOOMBACKUP_DASHBOARD_NEXT_SCHEDULED="Next Scheduled"
|
||||||
@@ -27,8 +27,8 @@ COM_MOKOJOOMBACKUP_TOOLBAR_BACKUP_NOW="Backup Now"
|
|||||||
COM_MOKOJOOMBACKUP_NO_BACKUPS="No backups found. Click 'Backup Now' to create your first backup."
|
COM_MOKOJOOMBACKUP_NO_BACKUPS="No backups found. Click 'Backup Now' to create your first backup."
|
||||||
COM_MOKOJOOMBACKUP_NO_PROFILES="No backup profiles found."
|
COM_MOKOJOOMBACKUP_NO_PROFILES="No backup profiles found."
|
||||||
COM_MOKOJOOMBACKUP_UPDATE_SITE_NOTICE="To receive automatic updates, configure your <a href=\"%s\">Update Site</a> with your download key."
|
COM_MOKOJOOMBACKUP_UPDATE_SITE_NOTICE="To receive automatic updates, configure your <a href=\"%s\">Update Site</a> with your download key."
|
||||||
COM_MOKOJOOMBACKUP_UPDATE_SITE_MISSING="MokoSuiteBackup update site not found. Reinstall the package to register the update server."
|
COM_MOKOJOOMBACKUP_UPDATE_SITE_MISSING="MokoJoomBackup update site not found. Reinstall the package to register the update server."
|
||||||
COM_MOKOJOOMBACKUP_POSTINSTALL_UPDATE_SITE="MokoSuiteBackup installed successfully. Configure your <a href=\"%s\">Update Site</a> to receive automatic updates."
|
COM_MOKOJOOMBACKUP_POSTINSTALL_UPDATE_SITE="MokoJoomBackup installed successfully. Configure your <a href=\"%s\">Update Site</a> to receive automatic updates."
|
||||||
COM_MOKOJOOMBACKUP_CONFIG_GENERAL="General"
|
COM_MOKOJOOMBACKUP_CONFIG_GENERAL="General"
|
||||||
COM_MOKOJOOMBACKUP_CONFIG_DEFAULT_BACKUP_DIR="Default Backup Directory"
|
COM_MOKOJOOMBACKUP_CONFIG_DEFAULT_BACKUP_DIR="Default Backup Directory"
|
||||||
COM_MOKOJOOMBACKUP_CONFIG_DEFAULT_BACKUP_DIR_DESC="Default directory for backup archives, relative to Joomla root. Can be overridden per profile."
|
COM_MOKOJOOMBACKUP_CONFIG_DEFAULT_BACKUP_DIR_DESC="Default directory for backup archives, relative to Joomla root. Can be overridden per profile."
|
||||||
+3
-3
@@ -1,10 +1,10 @@
|
|||||||
; MokoSuiteBackup — Component system language file (en-US)
|
; MokoJoomBackup — Component system language file (en-US)
|
||||||
; @package MokoSuiteBackup
|
; @package MokoJoomBackup
|
||||||
; @author Moko Consulting <hello@mokoconsulting.tech>
|
; @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
; @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
; @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
; @license GPL-3.0-or-later
|
; @license GPL-3.0-or-later
|
||||||
|
|
||||||
COM_MOKOJOOMBACKUP="MokoSuiteBackup"
|
COM_MOKOJOOMBACKUP="MokoJoomBackup"
|
||||||
COM_MOKOJOOMBACKUP_DESCRIPTION="Full-site backup and restore for Joomla — database, files, and configuration."
|
COM_MOKOJOOMBACKUP_DESCRIPTION="Full-site backup and restore for Joomla — database, files, and configuration."
|
||||||
COM_MOKOJOOMBACKUP_SUBMENU_DASHBOARD="Dashboard"
|
COM_MOKOJOOMBACKUP_SUBMENU_DASHBOARD="Dashboard"
|
||||||
COM_MOKOJOOMBACKUP_SUBMENU_BACKUPS="Backup Records"
|
COM_MOKOJOOMBACKUP_SUBMENU_BACKUPS="Backup Records"
|
||||||
+10
-15
@@ -1,13 +1,14 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!--
|
<!--
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
-->
|
-->
|
||||||
<extension type="component" method="upgrade">
|
<extension type="component" method="upgrade">
|
||||||
<name>MokoSuiteBackup</name>
|
<name>com_mokojoombackup</name>
|
||||||
<version>01.08.17-dev</version>
|
<version>01.08.00</version>
|
||||||
<creationDate>2026-06-02</creationDate>
|
<creationDate>2026-06-02</creationDate>
|
||||||
<author>Moko Consulting</author>
|
<author>Moko Consulting</author>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
@@ -16,7 +17,7 @@
|
|||||||
<license>GPL-3.0-or-later</license>
|
<license>GPL-3.0-or-later</license>
|
||||||
<description>COM_MOKOJOOMBACKUP_DESCRIPTION</description>
|
<description>COM_MOKOJOOMBACKUP_DESCRIPTION</description>
|
||||||
|
|
||||||
<namespace path="src">Joomla\Component\MokoSuiteBackup</namespace>
|
<namespace path="src">Joomla\Component\MokoJoomBackup</namespace>
|
||||||
|
|
||||||
<install>
|
<install>
|
||||||
<sql>
|
<sql>
|
||||||
@@ -39,15 +40,9 @@
|
|||||||
<administration>
|
<administration>
|
||||||
<menu img="class:archive">COM_MOKOJOOMBACKUP</menu>
|
<menu img="class:archive">COM_MOKOJOOMBACKUP</menu>
|
||||||
<submenu>
|
<submenu>
|
||||||
<menu link="option=com_mokosuitebackup&view=dashboard"
|
<menu link="option=com_mokojoombackup&view=dashboard" img="class:home">COM_MOKOJOOMBACKUP_SUBMENU_DASHBOARD</menu>
|
||||||
img="class:home"
|
<menu link="option=com_mokojoombackup&view=backups" img="class:database">COM_MOKOJOOMBACKUP_SUBMENU_BACKUPS</menu>
|
||||||
alt="Dashboard">COM_MOKOJOOMBACKUP_SUBMENU_DASHBOARD</menu>
|
<menu link="option=com_mokojoombackup&view=profiles" img="class:cog">COM_MOKOJOOMBACKUP_SUBMENU_PROFILES</menu>
|
||||||
<menu link="option=com_mokosuitebackup&view=backups"
|
|
||||||
img="class:database"
|
|
||||||
alt="Backups">COM_MOKOJOOMBACKUP_SUBMENU_BACKUPS</menu>
|
|
||||||
<menu link="option=com_mokosuitebackup&view=profiles"
|
|
||||||
img="class:cog"
|
|
||||||
alt="Profiles">COM_MOKOJOOMBACKUP_SUBMENU_PROFILES</menu>
|
|
||||||
</submenu>
|
</submenu>
|
||||||
<files folder=".">
|
<files folder=".">
|
||||||
<folder>cli</folder>
|
<folder>cli</folder>
|
||||||
@@ -58,8 +53,8 @@
|
|||||||
<folder>tmpl</folder>
|
<folder>tmpl</folder>
|
||||||
</files>
|
</files>
|
||||||
<languages folder="language">
|
<languages folder="language">
|
||||||
<language tag="en-GB">en-GB/com_mokosuitebackup.ini</language>
|
<language tag="en-GB">en-GB/com_mokojoombackup.ini</language>
|
||||||
<language tag="en-GB">en-GB/com_mokosuitebackup.sys.ini</language>
|
<language tag="en-GB">en-GB/com_mokojoombackup.sys.ini</language>
|
||||||
</languages>
|
</languages>
|
||||||
</administration>
|
</administration>
|
||||||
|
|
||||||
+6
-6
@@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
@@ -15,20 +15,20 @@ use Joomla\CMS\Extension\ComponentInterface;
|
|||||||
use Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory;
|
use Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory;
|
||||||
use Joomla\CMS\Extension\Service\Provider\MVCFactory;
|
use Joomla\CMS\Extension\Service\Provider\MVCFactory;
|
||||||
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
|
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
|
||||||
use Joomla\Component\MokoSuiteBackup\Administrator\Extension\MokoSuiteBackupComponent;
|
use Joomla\Component\MokoJoomBackup\Administrator\Extension\MokoJoomBackupComponent;
|
||||||
use Joomla\DI\Container;
|
use Joomla\DI\Container;
|
||||||
use Joomla\DI\ServiceProviderInterface;
|
use Joomla\DI\ServiceProviderInterface;
|
||||||
|
|
||||||
return new class () implements ServiceProviderInterface {
|
return new class () implements ServiceProviderInterface {
|
||||||
public function register(Container $container): void
|
public function register(Container $container): void
|
||||||
{
|
{
|
||||||
$container->registerServiceProvider(new MVCFactory('\\Joomla\\Component\\MokoSuiteBackup'));
|
$container->registerServiceProvider(new MVCFactory('\\Joomla\\Component\\MokoJoomBackup'));
|
||||||
$container->registerServiceProvider(new ComponentDispatcherFactory('\\Joomla\\Component\\MokoSuiteBackup'));
|
$container->registerServiceProvider(new ComponentDispatcherFactory('\\Joomla\\Component\\MokoJoomBackup'));
|
||||||
|
|
||||||
$container->set(
|
$container->set(
|
||||||
ComponentInterface::class,
|
ComponentInterface::class,
|
||||||
function (Container $container) {
|
function (Container $container) {
|
||||||
$component = new MokoSuiteBackupComponent(
|
$component = new MokoJoomBackupComponent(
|
||||||
$container->get(ComponentDispatcherFactoryInterface::class)
|
$container->get(ComponentDispatcherFactoryInterface::class)
|
||||||
);
|
);
|
||||||
$component->setMVCFactory($container->get(MVCFactoryInterface::class));
|
$component->setMVCFactory($container->get(MVCFactoryInterface::class));
|
||||||
+6
-6
@@ -1,4 +1,4 @@
|
|||||||
CREATE TABLE IF NOT EXISTS `#__mokosuitebackup_profiles` (
|
CREATE TABLE IF NOT EXISTS `#__mokojoombackup_profiles` (
|
||||||
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
`title` VARCHAR(255) NOT NULL DEFAULT '',
|
`title` VARCHAR(255) NOT NULL DEFAULT '',
|
||||||
`description` TEXT NOT NULL,
|
`description` TEXT NOT NULL,
|
||||||
@@ -6,7 +6,7 @@ CREATE TABLE IF NOT EXISTS `#__mokosuitebackup_profiles` (
|
|||||||
`archive_format` VARCHAR(10) NOT NULL DEFAULT 'zip',
|
`archive_format` VARCHAR(10) NOT NULL DEFAULT 'zip',
|
||||||
`compression_level` TINYINT(1) UNSIGNED NOT NULL DEFAULT 5 COMMENT '0=none, 9=max',
|
`compression_level` TINYINT(1) UNSIGNED NOT NULL DEFAULT 5 COMMENT '0=none, 9=max',
|
||||||
`split_size` INT(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '0=no split, otherwise MB per part',
|
`split_size` INT(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '0=no split, otherwise MB per part',
|
||||||
`backup_dir` VARCHAR(512) NOT NULL DEFAULT '[DEFAULT_DIR]',
|
`backup_dir` VARCHAR(512) NOT NULL DEFAULT 'administrator/components/com_mokojoombackup/backups',
|
||||||
`archive_name_format` VARCHAR(512) NOT NULL DEFAULT '[host]_[datetime]_profile[profile_id]' COMMENT 'Filename format with placeholders',
|
`archive_name_format` VARCHAR(512) NOT NULL DEFAULT '[host]_[datetime]_profile[profile_id]' COMMENT 'Filename format with placeholders',
|
||||||
`exclude_dirs` TEXT NOT NULL COMMENT 'Newline-separated directory paths to exclude',
|
`exclude_dirs` TEXT NOT NULL COMMENT 'Newline-separated directory paths to exclude',
|
||||||
`exclude_files` TEXT NOT NULL COMMENT 'Newline-separated filename patterns to exclude',
|
`exclude_files` TEXT NOT NULL COMMENT 'Newline-separated filename patterns to exclude',
|
||||||
@@ -44,7 +44,7 @@ CREATE TABLE IF NOT EXISTS `#__mokosuitebackup_profiles` (
|
|||||||
KEY `idx_published` (`published`)
|
KEY `idx_published` (`published`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `#__mokosuitebackup_records` (
|
CREATE TABLE IF NOT EXISTS `#__mokojoombackup_records` (
|
||||||
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
`profile_id` INT(11) UNSIGNED NOT NULL DEFAULT 1,
|
`profile_id` INT(11) UNSIGNED NOT NULL DEFAULT 1,
|
||||||
`description` VARCHAR(255) NOT NULL DEFAULT '',
|
`description` VARCHAR(255) NOT NULL DEFAULT '',
|
||||||
@@ -74,15 +74,15 @@ CREATE TABLE IF NOT EXISTS `#__mokosuitebackup_records` (
|
|||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
-- Insert default backup profile (IGNORE prevents duplicate key error on update)
|
-- Insert default backup profile (IGNORE prevents duplicate key error on update)
|
||||||
INSERT IGNORE INTO `#__mokosuitebackup_profiles` (
|
INSERT IGNORE INTO `#__mokojoombackup_profiles` (
|
||||||
`id`, `title`, `description`, `backup_type`,
|
`id`, `title`, `description`, `backup_type`,
|
||||||
`archive_format`, `compression_level`, `split_size`, `backup_dir`,
|
`archive_format`, `compression_level`, `split_size`, `backup_dir`,
|
||||||
`exclude_dirs`, `exclude_files`, `exclude_tables`,
|
`exclude_dirs`, `exclude_files`, `exclude_tables`,
|
||||||
`published`, `ordering`, `created`, `modified`
|
`published`, `ordering`, `created`, `modified`
|
||||||
) VALUES (
|
) VALUES (
|
||||||
1, 'Default Backup Profile', 'Full site backup with default settings', 'full',
|
1, 'Default Backup Profile', 'Full site backup with default settings', 'full',
|
||||||
'zip', 5, 0, '[DEFAULT_DIR]',
|
'zip', 5, 0, 'administrator/components/com_mokojoombackup/backups',
|
||||||
'administrator/components/com_mokosuitebackup/backups\ntmp\ncache\nlogs\nadministrator/logs',
|
'administrator/components/com_mokojoombackup/backups\ntmp\ncache\nlogs\nadministrator/logs',
|
||||||
'.gitignore\n.htaccess.bak',
|
'.gitignore\n.htaccess.bak',
|
||||||
'#__session',
|
'#__session',
|
||||||
1, 1, NOW(), NOW()
|
1, 1, NOW(), NOW()
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
DROP TABLE IF EXISTS `#__mokojoombackup_records`;
|
||||||
|
DROP TABLE IF EXISTS `#__mokojoombackup_profiles`;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE `#__mokojoombackup_profiles` CHANGE `include_kickstart` `include_mokorestore` TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'Include MokoRestore standalone restore script in archive';
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
-- MokoJoomBackup 01.01.02
|
||||||
|
-- Consolidated schema updates: NULL defaults, notifications, archive name format
|
||||||
|
|
||||||
|
-- Fix: allow NULL defaults for manifest and log columns
|
||||||
|
ALTER TABLE `#__mokojoombackup_records` MODIFY `manifest` LONGTEXT DEFAULT NULL;
|
||||||
|
ALTER TABLE `#__mokojoombackup_records` MODIFY `log` MEDIUMTEXT DEFAULT NULL;
|
||||||
|
|
||||||
|
-- Add user group notifications column to profiles
|
||||||
|
ALTER TABLE `#__mokojoombackup_profiles` ADD COLUMN `notify_user_groups` VARCHAR(255) NOT NULL DEFAULT '' COMMENT 'Comma-separated Joomla user group IDs' AFTER `notify_email`;
|
||||||
|
|
||||||
|
-- Add archive_name_format column with placeholder support
|
||||||
|
ALTER TABLE `#__mokojoombackup_profiles` ADD COLUMN `archive_name_format` VARCHAR(512) NOT NULL DEFAULT '[host]_[datetime]_profile[profile_id]' COMMENT 'Filename format with placeholders' AFTER `backup_dir`;
|
||||||
+10
-13
@@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
@@ -11,14 +11,14 @@
|
|||||||
* Handles init and step requests from the admin UI JavaScript.
|
* Handles init and step requests from the admin UI JavaScript.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Controller;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Controller;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
use Joomla\CMS\MVC\Controller\BaseController;
|
use Joomla\CMS\MVC\Controller\BaseController;
|
||||||
use Joomla\CMS\Session\Session;
|
use Joomla\CMS\Session\Session;
|
||||||
use Joomla\Component\MokoSuiteBackup\Administrator\Engine\SteppedBackupEngine;
|
use Joomla\Component\MokoJoomBackup\Administrator\Engine\SteppedBackupEngine;
|
||||||
use Joomla\Component\MokoSuiteBackup\Administrator\Utility\BackupDirectory;
|
use Joomla\Component\MokoJoomBackup\Administrator\Utility\BackupDirectory;
|
||||||
|
|
||||||
class AjaxController extends BaseController
|
class AjaxController extends BaseController
|
||||||
{
|
{
|
||||||
@@ -82,14 +82,11 @@ class AjaxController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
$requestPath = $this->input->getString('path', JPATH_ROOT);
|
$requestPath = $this->input->getString('path', JPATH_ROOT);
|
||||||
|
$path = realpath($requestPath) ?: $requestPath;
|
||||||
// Resolve placeholders and relative paths before permission check
|
|
||||||
$resolved = BackupDirectory::resolve($requestPath);
|
|
||||||
$path = realpath($resolved) ?: $resolved;
|
|
||||||
|
|
||||||
// Security: restrict browsing to site root and current user's home
|
// Security: restrict browsing to site root and current user's home
|
||||||
$jRoot = realpath(JPATH_ROOT);
|
$jRoot = realpath(JPATH_ROOT);
|
||||||
$homeDir = BackupDirectory::getHomeDirectory();
|
$homeDir = getenv('HOME') ?: (getenv('USERPROFILE') ?: '');
|
||||||
$allowed = false;
|
$allowed = false;
|
||||||
|
|
||||||
if ($jRoot !== false && strpos($path, $jRoot) === 0) {
|
if ($jRoot !== false && strpos($path, $jRoot) === 0) {
|
||||||
@@ -146,7 +143,7 @@ class AjaxController extends BaseController
|
|||||||
if ($parent !== $path) {
|
if ($parent !== $path) {
|
||||||
if ($jRoot !== false && strpos($parent, $jRoot) === 0) {
|
if ($jRoot !== false && strpos($parent, $jRoot) === 0) {
|
||||||
$parentAllowed = true;
|
$parentAllowed = true;
|
||||||
} elseif ($homeDir !== '' && (strpos($parent, $homeDir) === 0 || $parent === \dirname($homeDir))) {
|
} elseif ($homeDir !== '' && strpos($parent, $homeDir) === 0) {
|
||||||
$parentAllowed = true;
|
$parentAllowed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -188,7 +185,7 @@ class AjaxController extends BaseController
|
|||||||
$db = \Joomla\CMS\Factory::getDbo();
|
$db = \Joomla\CMS\Factory::getDbo();
|
||||||
$query = $db->getQuery(true)
|
$query = $db->getQuery(true)
|
||||||
->select($db->quoteName(['absolute_path', 'log']))
|
->select($db->quoteName(['absolute_path', 'log']))
|
||||||
->from($db->quoteName('#__mokosuitebackup_records'))
|
->from($db->quoteName('#__mokojoombackup_records'))
|
||||||
->where($db->quoteName('id') . ' = ' . (int) $id);
|
->where($db->quoteName('id') . ' = ' . (int) $id);
|
||||||
$db->setQuery($query);
|
$db->setQuery($query);
|
||||||
$record = $db->loadObject();
|
$record = $db->loadObject();
|
||||||
@@ -229,7 +226,7 @@ class AjaxController extends BaseController
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->app->getIdentity()->authorise('core.manage', 'com_mokosuitebackup')) {
|
if (!$this->app->getIdentity()->authorise('core.manage', 'com_mokojoombackup')) {
|
||||||
$this->sendJson(['error' => true, 'message' => 'Access denied']);
|
$this->sendJson(['error' => true, 'message' => 'Access denied']);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
+3
-3
@@ -1,14 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Controller;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Controller;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
+14
-14
@@ -1,21 +1,21 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Controller;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Controller;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
use Joomla\CMS\MVC\Controller\AdminController;
|
use Joomla\CMS\MVC\Controller\AdminController;
|
||||||
use Joomla\CMS\Router\Route;
|
use Joomla\CMS\Router\Route;
|
||||||
use Joomla\Component\MokoSuiteBackup\Administrator\Engine\BackupEngine;
|
use Joomla\Component\MokoJoomBackup\Administrator\Engine\BackupEngine;
|
||||||
use Joomla\Component\MokoSuiteBackup\Administrator\Engine\RestoreEngine;
|
use Joomla\Component\MokoJoomBackup\Administrator\Engine\RestoreEngine;
|
||||||
|
|
||||||
class BackupsController extends AdminController
|
class BackupsController extends AdminController
|
||||||
{
|
{
|
||||||
@@ -47,7 +47,7 @@ class BackupsController extends AdminController
|
|||||||
$this->setMessage($result['message'], 'error');
|
$this->setMessage($result['message'], 'error');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->setRedirect(Route::_('index.php?option=com_mokosuitebackup&view=backups', false));
|
$this->setRedirect(Route::_('index.php?option=com_mokojoombackup&view=backups', false));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -63,7 +63,7 @@ class BackupsController extends AdminController
|
|||||||
|
|
||||||
if (!$item || !$item->id || !$item->filesexist || !is_file($item->absolute_path)) {
|
if (!$item || !$item->id || !$item->filesexist || !is_file($item->absolute_path)) {
|
||||||
$this->setMessage('COM_MOKOJOOMBACKUP_ERROR_FILE_NOT_FOUND', 'error');
|
$this->setMessage('COM_MOKOJOOMBACKUP_ERROR_FILE_NOT_FOUND', 'error');
|
||||||
$this->setRedirect(Route::_('index.php?option=com_mokosuitebackup&view=backups', false));
|
$this->setRedirect(Route::_('index.php?option=com_mokojoombackup&view=backups', false));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -109,7 +109,7 @@ class BackupsController extends AdminController
|
|||||||
|
|
||||||
if (!$id) {
|
if (!$id) {
|
||||||
$this->setMessage('COM_MOKOJOOMBACKUP_ERROR_NO_RECORD_SELECTED', 'error');
|
$this->setMessage('COM_MOKOJOOMBACKUP_ERROR_NO_RECORD_SELECTED', 'error');
|
||||||
$this->setRedirect(Route::_('index.php?option=com_mokosuitebackup&view=backups', false));
|
$this->setRedirect(Route::_('index.php?option=com_mokojoombackup&view=backups', false));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -123,7 +123,7 @@ class BackupsController extends AdminController
|
|||||||
$this->setMessage($result['message'], 'error');
|
$this->setMessage($result['message'], 'error');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->setRedirect(Route::_('index.php?option=com_mokosuitebackup&view=backups', false));
|
$this->setRedirect(Route::_('index.php?option=com_mokojoombackup&view=backups', false));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -138,7 +138,7 @@ class BackupsController extends AdminController
|
|||||||
|
|
||||||
if (!$id) {
|
if (!$id) {
|
||||||
$this->setMessage('COM_MOKOJOOMBACKUP_ERROR_NO_RECORD_SELECTED', 'error');
|
$this->setMessage('COM_MOKOJOOMBACKUP_ERROR_NO_RECORD_SELECTED', 'error');
|
||||||
$this->setRedirect(Route::_('index.php?option=com_mokosuitebackup&view=backups', false));
|
$this->setRedirect(Route::_('index.php?option=com_mokojoombackup&view=backups', false));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -148,21 +148,21 @@ class BackupsController extends AdminController
|
|||||||
|
|
||||||
if (!$item || !$item->id) {
|
if (!$item || !$item->id) {
|
||||||
$this->setMessage('COM_MOKOJOOMBACKUP_ERROR_NO_RECORD_SELECTED', 'error');
|
$this->setMessage('COM_MOKOJOOMBACKUP_ERROR_NO_RECORD_SELECTED', 'error');
|
||||||
$this->setRedirect(Route::_('index.php?option=com_mokosuitebackup&view=backups', false));
|
$this->setRedirect(Route::_('index.php?option=com_mokojoombackup&view=backups', false));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_file($item->absolute_path)) {
|
if (!is_file($item->absolute_path)) {
|
||||||
$this->setMessage('COM_MOKOJOOMBACKUP_ERROR_FILE_NOT_FOUND', 'error');
|
$this->setMessage('COM_MOKOJOOMBACKUP_ERROR_FILE_NOT_FOUND', 'error');
|
||||||
$this->setRedirect(Route::_('index.php?option=com_mokosuitebackup&view=backups', false));
|
$this->setRedirect(Route::_('index.php?option=com_mokojoombackup&view=backups', false));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($item->checksum)) {
|
if (empty($item->checksum)) {
|
||||||
$this->setMessage('COM_MOKOJOOMBACKUP_VERIFY_NO_CHECKSUM', 'warning');
|
$this->setMessage('COM_MOKOJOOMBACKUP_VERIFY_NO_CHECKSUM', 'warning');
|
||||||
$this->setRedirect(Route::_('index.php?option=com_mokosuitebackup&view=backups', false));
|
$this->setRedirect(Route::_('index.php?option=com_mokojoombackup&view=backups', false));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -175,6 +175,6 @@ class BackupsController extends AdminController
|
|||||||
$this->setMessage('COM_MOKOJOOMBACKUP_VERIFY_FAILED', 'error');
|
$this->setMessage('COM_MOKOJOOMBACKUP_VERIFY_FAILED', 'error');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->setRedirect(Route::_('index.php?option=com_mokosuitebackup&view=backups', false));
|
$this->setRedirect(Route::_('index.php?option=com_mokojoombackup&view=backups', false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+3
-3
@@ -1,14 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Controller;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Controller;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
+3
-3
@@ -1,14 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Controller;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Controller;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
+6
-6
@@ -1,21 +1,21 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Controller;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Controller;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
use Joomla\CMS\Factory;
|
use Joomla\CMS\Factory;
|
||||||
use Joomla\CMS\MVC\Controller\AdminController;
|
use Joomla\CMS\MVC\Controller\AdminController;
|
||||||
use Joomla\CMS\Router\Route;
|
use Joomla\CMS\Router\Route;
|
||||||
use Joomla\Component\MokoSuiteBackup\Administrator\Engine\AkeebaImporter;
|
use Joomla\Component\MokoJoomBackup\Administrator\Engine\AkeebaImporter;
|
||||||
|
|
||||||
class ProfilesController extends AdminController
|
class ProfilesController extends AdminController
|
||||||
{
|
{
|
||||||
@@ -40,7 +40,7 @@ class ProfilesController extends AdminController
|
|||||||
|
|
||||||
if (!$detection['profiles']) {
|
if (!$detection['profiles']) {
|
||||||
$this->setMessage('COM_MOKOJOOMBACKUP_AKEEBA_NOT_FOUND', 'error');
|
$this->setMessage('COM_MOKOJOOMBACKUP_AKEEBA_NOT_FOUND', 'error');
|
||||||
$this->setRedirect(Route::_('index.php?option=com_mokosuitebackup&view=profiles', false));
|
$this->setRedirect(Route::_('index.php?option=com_mokojoombackup&view=profiles', false));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -55,7 +55,7 @@ class ProfilesController extends AdminController
|
|||||||
$this->setMessage($result['message'], 'error');
|
$this->setMessage($result['message'], 'error');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->setRedirect(Route::_('index.php?option=com_mokosuitebackup&view=profiles', false));
|
$this->setRedirect(Route::_('index.php?option=com_mokojoombackup&view=profiles', false));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
+12
-12
@@ -1,16 +1,16 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
*
|
*
|
||||||
* Imports Akeeba Backup Pro profiles and backup history into MokoSuiteBackup.
|
* Imports Akeeba Backup Pro profiles and backup history into MokoJoomBackup.
|
||||||
*
|
*
|
||||||
* Reads from #__ak_profiles and #__ak_stats, maps Akeeba's configuration
|
* Reads from #__ak_profiles and #__ak_stats, maps Akeeba's configuration
|
||||||
* format to MokoSuiteBackup's individual column format.
|
* format to MokoJoomBackup's individual column format.
|
||||||
*
|
*
|
||||||
* Akeeba config format:
|
* Akeeba config format:
|
||||||
* INI-style with dot-notation keys, e.g.:
|
* INI-style with dot-notation keys, e.g.:
|
||||||
@@ -25,12 +25,12 @@
|
|||||||
* "databases": {"include": {...}, "exclude": {...}}}
|
* "databases": {"include": {...}, "exclude": {...}}}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Engine;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Engine;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
use Joomla\CMS\Factory;
|
use Joomla\CMS\Factory;
|
||||||
use Joomla\Component\MokoSuiteBackup\Administrator\Utility\BackupDirectory;
|
use Joomla\Component\MokoJoomBackup\Administrator\Utility\BackupDirectory;
|
||||||
|
|
||||||
class AkeebaImporter
|
class AkeebaImporter
|
||||||
{
|
{
|
||||||
@@ -90,7 +90,7 @@ class AkeebaImporter
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Import all Akeeba profiles into MokoSuiteBackup.
|
* Import all Akeeba profiles into MokoJoomBackup.
|
||||||
*
|
*
|
||||||
* @param bool $importHistory Also import backup history from #__ak_stats
|
* @param bool $importHistory Also import backup history from #__ak_stats
|
||||||
*
|
*
|
||||||
@@ -120,7 +120,7 @@ class AkeebaImporter
|
|||||||
$akProfiles = $db->loadObjectList();
|
$akProfiles = $db->loadObjectList();
|
||||||
|
|
||||||
$profilesImported = 0;
|
$profilesImported = 0;
|
||||||
$profileIdMap = []; // akeeba_id => mokosuitebackup_id
|
$profileIdMap = []; // akeeba_id => mokojoombackup_id
|
||||||
|
|
||||||
foreach ($akProfiles as $akProfile) {
|
foreach ($akProfiles as $akProfile) {
|
||||||
$config = $this->parseAkeebaConfig($akProfile->configuration ?? '');
|
$config = $this->parseAkeebaConfig($akProfile->configuration ?? '');
|
||||||
@@ -128,11 +128,11 @@ class AkeebaImporter
|
|||||||
|
|
||||||
$mokoProfile = $this->mapToMokoProfile($akProfile, $config, $filters);
|
$mokoProfile = $this->mapToMokoProfile($akProfile, $config, $filters);
|
||||||
|
|
||||||
$db->insertObject('#__mokosuitebackup_profiles', $mokoProfile, 'id');
|
$db->insertObject('#__mokojoombackup_profiles', $mokoProfile, 'id');
|
||||||
$profileIdMap[$akProfile->id] = $mokoProfile->id;
|
$profileIdMap[$akProfile->id] = $mokoProfile->id;
|
||||||
$profilesImported++;
|
$profilesImported++;
|
||||||
|
|
||||||
$this->log('Imported profile: "' . $akProfile->description . '" (Akeeba #' . $akProfile->id . ' → MokoSuiteBackup #' . $mokoProfile->id . ')');
|
$this->log('Imported profile: "' . $akProfile->description . '" (Akeeba #' . $akProfile->id . ' → MokoJoomBackup #' . $mokoProfile->id . ')');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Import backup history
|
// Import backup history
|
||||||
@@ -201,7 +201,7 @@ class AkeebaImporter
|
|||||||
'log' => 'Imported from Akeeba Backup record #' . $stat->id,
|
'log' => 'Imported from Akeeba Backup record #' . $stat->id,
|
||||||
];
|
];
|
||||||
|
|
||||||
$db->insertObject('#__mokosuitebackup_records', $record, 'id');
|
$db->insertObject('#__mokojoombackup_records', $record, 'id');
|
||||||
$imported++;
|
$imported++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,7 +211,7 @@ class AkeebaImporter
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map an Akeeba profile to a MokoSuiteBackup profile object.
|
* Map an Akeeba profile to a MokoJoomBackup profile object.
|
||||||
*/
|
*/
|
||||||
private function mapToMokoProfile(object $akProfile, array $config, array $filters): object
|
private function mapToMokoProfile(object $akProfile, array $config, array $filters): object
|
||||||
{
|
{
|
||||||
+3
-3
@@ -1,14 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Engine;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Engine;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
+14
-14
@@ -1,19 +1,19 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Engine;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Engine;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
use Joomla\CMS\Factory;
|
use Joomla\CMS\Factory;
|
||||||
use Joomla\Component\MokoSuiteBackup\Administrator\Utility\BackupDirectory;
|
use Joomla\Component\MokoJoomBackup\Administrator\Utility\BackupDirectory;
|
||||||
use Joomla\Event\Event;
|
use Joomla\Event\Event;
|
||||||
|
|
||||||
class BackupEngine
|
class BackupEngine
|
||||||
@@ -47,7 +47,7 @@ class BackupEngine
|
|||||||
// Load profile
|
// Load profile
|
||||||
$query = $db->getQuery(true)
|
$query = $db->getQuery(true)
|
||||||
->select('*')
|
->select('*')
|
||||||
->from($db->quoteName('#__mokosuitebackup_profiles'))
|
->from($db->quoteName('#__mokojoombackup_profiles'))
|
||||||
->where($db->quoteName('id') . ' = ' . $profileId);
|
->where($db->quoteName('id') . ' = ' . $profileId);
|
||||||
$db->setQuery($query);
|
$db->setQuery($query);
|
||||||
$profile = $db->loadObject();
|
$profile = $db->loadObject();
|
||||||
@@ -105,7 +105,7 @@ class BackupEngine
|
|||||||
'log' => '',
|
'log' => '',
|
||||||
];
|
];
|
||||||
|
|
||||||
$db->insertObject('#__mokosuitebackup_records', $record, 'id');
|
$db->insertObject('#__mokojoombackup_records', $record, 'id');
|
||||||
$recordId = $record->id;
|
$recordId = $record->id;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -249,7 +249,7 @@ class BackupEngine
|
|||||||
$logContent = implode("\n", $this->log);
|
$logContent = implode("\n", $this->log);
|
||||||
$logPath = preg_replace('/\.(zip|tar\.gz)$/i', '.log', $archivePath);
|
$logPath = preg_replace('/\.(zip|tar\.gz)$/i', '.log', $archivePath);
|
||||||
if (@file_put_contents($logPath, $logContent) === false) {
|
if (@file_put_contents($logPath, $logContent) === false) {
|
||||||
error_log('MokoSuiteBackup: Could not write log file: ' . $logPath);
|
error_log('MokoJoomBackup: Could not write log file: ' . $logPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Final record update
|
// Final record update
|
||||||
@@ -268,7 +268,7 @@ class BackupEngine
|
|||||||
'log' => $logContent,
|
'log' => $logContent,
|
||||||
];
|
];
|
||||||
|
|
||||||
$db->updateObject('#__mokosuitebackup_records', $update, 'id');
|
$db->updateObject('#__mokojoombackup_records', $update, 'id');
|
||||||
|
|
||||||
// Send success notification
|
// Send success notification
|
||||||
NotificationSender::send($profile, $update, true, implode("\n", $this->log));
|
NotificationSender::send($profile, $update, true, implode("\n", $this->log));
|
||||||
@@ -296,7 +296,7 @@ class BackupEngine
|
|||||||
'log' => implode("\n", $this->log),
|
'log' => implode("\n", $this->log),
|
||||||
];
|
];
|
||||||
|
|
||||||
$db->updateObject('#__mokosuitebackup_records', $update, 'id');
|
$db->updateObject('#__mokojoombackup_records', $update, 'id');
|
||||||
|
|
||||||
// Send failure notification
|
// Send failure notification
|
||||||
NotificationSender::send($profile, $update, false, implode("\n", $this->log));
|
NotificationSender::send($profile, $update, false, implode("\n", $this->log));
|
||||||
@@ -416,7 +416,7 @@ class BackupEngine
|
|||||||
{
|
{
|
||||||
$query = $db->getQuery(true)
|
$query = $db->getQuery(true)
|
||||||
->select($db->quoteName('manifest'))
|
->select($db->quoteName('manifest'))
|
||||||
->from($db->quoteName('#__mokosuitebackup_records'))
|
->from($db->quoteName('#__mokojoombackup_records'))
|
||||||
->where($db->quoteName('profile_id') . ' = ' . $profileId)
|
->where($db->quoteName('profile_id') . ' = ' . $profileId)
|
||||||
->where($db->quoteName('status') . ' = ' . $db->quote('complete'))
|
->where($db->quoteName('status') . ' = ' . $db->quote('complete'))
|
||||||
->where($db->quoteName('manifest') . ' != ' . $db->quote(''))
|
->where($db->quoteName('manifest') . ' != ' . $db->quote(''))
|
||||||
@@ -472,14 +472,14 @@ class BackupEngine
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispatch the onMokoSuiteBackupAfterRun event so plugins (actionlog, etc.) can react.
|
* Dispatch the onMokoJoomBackupAfterRun event so plugins (actionlog, etc.) can react.
|
||||||
*/
|
*/
|
||||||
private function dispatchAfterRun(bool $success, int $recordId, string $description, int $profileId, string $origin): void
|
private function dispatchAfterRun(bool $success, int $recordId, string $description, int $profileId, string $origin): void
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$app = Factory::getApplication();
|
$app = Factory::getApplication();
|
||||||
|
|
||||||
$event = new Event('onMokoSuiteBackupAfterRun', [
|
$event = new Event('onMokoJoomBackupAfterRun', [
|
||||||
'success' => $success,
|
'success' => $success,
|
||||||
'record_id' => $recordId,
|
'record_id' => $recordId,
|
||||||
'description' => $description,
|
'description' => $description,
|
||||||
@@ -487,10 +487,10 @@ class BackupEngine
|
|||||||
'origin' => $origin,
|
'origin' => $origin,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$app->getDispatcher()->dispatch('onMokoSuiteBackupAfterRun', $event);
|
$app->getDispatcher()->dispatch('onMokoJoomBackupAfterRun', $event);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
// Never let a listener failure break the backup result, but log it
|
// Never let a listener failure break the backup result, but log it
|
||||||
error_log('MokoSuiteBackup: onAfterRun listener error: ' . $e->getMessage());
|
error_log('MokoJoomBackup: onAfterRun listener error: ' . $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
+4
-4
@@ -1,14 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Engine;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Engine;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ class DatabaseDumper
|
|||||||
$prefix = $db->getPrefix();
|
$prefix = $db->getPrefix();
|
||||||
$output = [];
|
$output = [];
|
||||||
|
|
||||||
$output[] = '-- MokoSuiteBackup Database Dump';
|
$output[] = '-- MokoJoomBackup Database Dump';
|
||||||
$output[] = '-- Generated: ' . date('Y-m-d H:i:s');
|
$output[] = '-- Generated: ' . date('Y-m-d H:i:s');
|
||||||
$output[] = '-- Server: ' . $db->getServerType();
|
$output[] = '-- Server: ' . $db->getServerType();
|
||||||
$output[] = '-- Database: ' . $db->getName();
|
$output[] = '-- Database: ' . $db->getName();
|
||||||
+5
-5
@@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
* and DROP TABLE before CREATE TABLE for clean restores.
|
* and DROP TABLE before CREATE TABLE for clean restores.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Engine;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Engine;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ class DatabaseImporter
|
|||||||
// Log but don't abort — some statements may fail on
|
// Log but don't abort — some statements may fail on
|
||||||
// different MySQL versions (e.g. charset differences)
|
// different MySQL versions (e.g. charset differences)
|
||||||
// but the overall restore should continue.
|
// but the overall restore should continue.
|
||||||
error_log('MokoSuiteBackup SQL import warning: ' . $e->getMessage());
|
error_log('MokoJoomBackup SQL import warning: ' . $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,7 +115,7 @@ class DatabaseImporter
|
|||||||
$db->execute();
|
$db->execute();
|
||||||
$statementsExecuted++;
|
$statementsExecuted++;
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
error_log('MokoSuiteBackup SQL import warning (final): ' . $e->getMessage());
|
error_log('MokoJoomBackup SQL import warning (final): ' . $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
+3
-3
@@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
* {"path/to/file": {"size": 1234, "mtime": 1717350000}, ...}
|
* {"path/to/file": {"size": 1234, "mtime": 1717350000}, ...}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Engine;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Engine;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
+3
-3
@@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
* Skips database.sql and sensitive files that should not be overwritten.
|
* Skips database.sql and sensitive files that should not be overwritten.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Engine;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Engine;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
+3
-3
@@ -1,14 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Engine;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Engine;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
+3
-3
@@ -1,14 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Engine;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Engine;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
+3
-3
@@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
* No SDK dependency — pure PHP with cURL.
|
* No SDK dependency — pure PHP with cURL.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Engine;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Engine;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
+3
-3
@@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
* The RestoreEngine can then restore from the extracted files.
|
* The RestoreEngine can then restore from the extracted files.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Engine;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Engine;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
+6
-6
@@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
* with a Joomla-styled wizard interface.
|
* with a Joomla-styled wizard interface.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Engine;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Engine;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ class MokoRestore
|
|||||||
*
|
*
|
||||||
* DELETE THIS FILE AFTER INSTALLATION IS COMPLETE.
|
* DELETE THIS FILE AFTER INSTALLATION IS COMPLETE.
|
||||||
*
|
*
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GPL-3.0-or-later
|
* @license GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
@@ -763,7 +763,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica N
|
|||||||
<body>
|
<body>
|
||||||
<div class="mr-header">
|
<div class="mr-header">
|
||||||
<h1>MokoRestore</h1>
|
<h1>MokoRestore</h1>
|
||||||
<p>Standalone Site Installer — MokoSuiteBackup</p>
|
<p>Standalone Site Installer — MokoJoomBackup</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mr-container">
|
<div class="mr-container">
|
||||||
@@ -927,7 +927,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica N
|
|||||||
|
|
||||||
<div class="mr-footer">
|
<div class="mr-footer">
|
||||||
MokoRestore — <a href="https://mokoconsulting.tech" target="_blank">Moko Consulting</a>
|
MokoRestore — <a href="https://mokoconsulting.tech" target="_blank">Moko Consulting</a>
|
||||||
— Part of MokoSuiteBackup
|
— Part of MokoJoomBackup
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
+8
-8
@@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
* Uses Joomla's built-in mail system (Factory::getMailer()).
|
* Uses Joomla's built-in mail system (Factory::getMailer()).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Engine;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Engine;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ class NotificationSender
|
|||||||
|
|
||||||
// Build subject
|
// Build subject
|
||||||
$statusLabel = $success ? 'SUCCESS' : 'FAILED';
|
$statusLabel = $success ? 'SUCCESS' : 'FAILED';
|
||||||
$mailer->setSubject("[MokoSuiteBackup] {$statusLabel}: {$record->description} — {$siteName}");
|
$mailer->setSubject("[MokoJoomBackup] {$statusLabel}: {$record->description} — {$siteName}");
|
||||||
|
|
||||||
// Build body
|
// Build body
|
||||||
$duration = '';
|
$duration = '';
|
||||||
@@ -92,7 +92,7 @@ class NotificationSender
|
|||||||
? number_format($record->total_size / 1048576, 2) . ' MB'
|
? number_format($record->total_size / 1048576, 2) . ' MB'
|
||||||
: 'N/A';
|
: 'N/A';
|
||||||
|
|
||||||
$body = "MokoSuiteBackup Notification\n"
|
$body = "MokoJoomBackup Notification\n"
|
||||||
. "============================\n\n"
|
. "============================\n\n"
|
||||||
. "Site: {$siteName}\n"
|
. "Site: {$siteName}\n"
|
||||||
. "URL: {$siteUrl}\n"
|
. "URL: {$siteUrl}\n"
|
||||||
@@ -125,7 +125,7 @@ class NotificationSender
|
|||||||
}
|
}
|
||||||
|
|
||||||
$body .= "\n--\n"
|
$body .= "\n--\n"
|
||||||
. "MokoSuiteBackup — https://mokoconsulting.tech\n";
|
. "MokoJoomBackup — https://mokoconsulting.tech\n";
|
||||||
|
|
||||||
$mailer->setBody($body);
|
$mailer->setBody($body);
|
||||||
$mailer->isHtml(false);
|
$mailer->isHtml(false);
|
||||||
@@ -133,7 +133,7 @@ class NotificationSender
|
|||||||
return $mailer->Send();
|
return $mailer->Send();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
// Don't let notification failure break the backup flow
|
// Don't let notification failure break the backup flow
|
||||||
error_log('MokoSuiteBackup notification error: ' . $e->getMessage());
|
error_log('MokoJoomBackup notification error: ' . $e->getMessage());
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -172,7 +172,7 @@ class NotificationSender
|
|||||||
|
|
||||||
return $db->loadColumn() ?: [];
|
return $db->loadColumn() ?: [];
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
error_log('MokoSuiteBackup: Could not resolve user group emails: ' . $e->getMessage());
|
error_log('MokoJoomBackup: Could not resolve user group emails: ' . $e->getMessage());
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
+4
-6
@@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
@@ -11,12 +11,12 @@
|
|||||||
* directory paths and archive filename formats.
|
* directory paths and archive filename formats.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Engine;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Engine;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
use Joomla\CMS\Factory;
|
use Joomla\CMS\Factory;
|
||||||
use Joomla\Component\MokoSuiteBackup\Administrator\Utility\BackupDirectory;
|
use Joomla\Component\MokoJoomBackup\Administrator\Utility\BackupDirectory;
|
||||||
|
|
||||||
class PlaceholderResolver
|
class PlaceholderResolver
|
||||||
{
|
{
|
||||||
@@ -40,7 +40,6 @@ class PlaceholderResolver
|
|||||||
'[type]' => 'Backup type (full, database, files, differential)',
|
'[type]' => 'Backup type (full, database, files, differential)',
|
||||||
'[random]' => 'Random 6-character hex string',
|
'[random]' => 'Random 6-character hex string',
|
||||||
'[DEFAULT_DIR]' => 'Default backup directory',
|
'[DEFAULT_DIR]' => 'Default backup directory',
|
||||||
'[HOME]' => 'Home directory of the PHP process owner',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
private array $replacements;
|
private array $replacements;
|
||||||
@@ -78,7 +77,6 @@ class PlaceholderResolver
|
|||||||
'[type]' => $profile->backup_type ?? 'full',
|
'[type]' => $profile->backup_type ?? 'full',
|
||||||
'[random]' => bin2hex(random_bytes(3)),
|
'[random]' => bin2hex(random_bytes(3)),
|
||||||
'[DEFAULT_DIR]' => BackupDirectory::getDefaultAbsolute(),
|
'[DEFAULT_DIR]' => BackupDirectory::getDefaultAbsolute(),
|
||||||
'[HOME]' => BackupDirectory::getHomeDirectory(),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
+3
-3
@@ -1,14 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Engine;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Engine;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
+5
-5
@@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
* 6. Clean up staging directory
|
* 6. Clean up staging directory
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Engine;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Engine;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ class RestoreEngine
|
|||||||
// Load backup record
|
// Load backup record
|
||||||
$query = $db->getQuery(true)
|
$query = $db->getQuery(true)
|
||||||
->select('*')
|
->select('*')
|
||||||
->from($db->quoteName('#__mokosuitebackup_records'))
|
->from($db->quoteName('#__mokojoombackup_records'))
|
||||||
->where($db->quoteName('id') . ' = ' . $recordId);
|
->where($db->quoteName('id') . ' = ' . $recordId);
|
||||||
$db->setQuery($query);
|
$db->setQuery($query);
|
||||||
$record = $db->loadObject();
|
$record = $db->loadObject();
|
||||||
@@ -77,7 +77,7 @@ class RestoreEngine
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create staging directory
|
// Create staging directory
|
||||||
$this->stagingDir = JPATH_ROOT . '/tmp/mokosuitebackup-restore-' . $record->tag;
|
$this->stagingDir = JPATH_ROOT . '/tmp/mokojoombackup-restore-' . $record->tag;
|
||||||
|
|
||||||
if (is_dir($this->stagingDir)) {
|
if (is_dir($this->stagingDir)) {
|
||||||
$this->recursiveDelete($this->stagingDir);
|
$this->recursiveDelete($this->stagingDir);
|
||||||
+3
-3
@@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
* No SDK dependency — pure PHP with cURL.
|
* No SDK dependency — pure PHP with cURL.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Engine;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Engine;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
+14
-14
@@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
@@ -16,12 +16,12 @@
|
|||||||
* where ini_set() and set_time_limit() are disabled.
|
* where ini_set() and set_time_limit() are disabled.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Engine;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Engine;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
use Joomla\CMS\Factory;
|
use Joomla\CMS\Factory;
|
||||||
use Joomla\Component\MokoSuiteBackup\Administrator\Utility\BackupDirectory;
|
use Joomla\Component\MokoJoomBackup\Administrator\Utility\BackupDirectory;
|
||||||
|
|
||||||
class SteppedBackupEngine
|
class SteppedBackupEngine
|
||||||
{
|
{
|
||||||
@@ -37,7 +37,7 @@ class SteppedBackupEngine
|
|||||||
// Load profile
|
// Load profile
|
||||||
$query = $db->getQuery(true)
|
$query = $db->getQuery(true)
|
||||||
->select('*')
|
->select('*')
|
||||||
->from($db->quoteName('#__mokosuitebackup_profiles'))
|
->from($db->quoteName('#__mokojoombackup_profiles'))
|
||||||
->where($db->quoteName('id') . ' = ' . $profileId);
|
->where($db->quoteName('id') . ' = ' . $profileId);
|
||||||
$db->setQuery($query);
|
$db->setQuery($query);
|
||||||
$profile = $db->loadObject();
|
$profile = $db->loadObject();
|
||||||
@@ -100,7 +100,7 @@ class SteppedBackupEngine
|
|||||||
'log' => '',
|
'log' => '',
|
||||||
];
|
];
|
||||||
|
|
||||||
$db->insertObject('#__mokosuitebackup_records', $record, 'id');
|
$db->insertObject('#__mokojoombackup_records', $record, 'id');
|
||||||
$session->recordId = $record->id;
|
$session->recordId = $record->id;
|
||||||
|
|
||||||
// Determine what work needs to be done and estimate steps
|
// Determine what work needs to be done and estimate steps
|
||||||
@@ -228,7 +228,7 @@ class SteppedBackupEngine
|
|||||||
$flags = $session->tableIndex === 0 ? 0 : FILE_APPEND;
|
$flags = $session->tableIndex === 0 ? 0 : FILE_APPEND;
|
||||||
|
|
||||||
if ($session->tableIndex === 0) {
|
if ($session->tableIndex === 0) {
|
||||||
$header = "-- MokoSuiteBackup Database Dump\n"
|
$header = "-- MokoJoomBackup Database Dump\n"
|
||||||
. "-- Generated: " . date('Y-m-d H:i:s') . "\n"
|
. "-- Generated: " . date('Y-m-d H:i:s') . "\n"
|
||||||
. "-- Prefix: " . $db->getPrefix() . "\n\n"
|
. "-- Prefix: " . $db->getPrefix() . "\n\n"
|
||||||
. "SET SQL_MODE = \"NO_AUTO_VALUE_ON_ZERO\";\n"
|
. "SET SQL_MODE = \"NO_AUTO_VALUE_ON_ZERO\";\n"
|
||||||
@@ -315,7 +315,7 @@ class SteppedBackupEngine
|
|||||||
|
|
||||||
// Clean up temp SQL file
|
// Clean up temp SQL file
|
||||||
if (is_file($sqlFile) && !@unlink($sqlFile)) {
|
if (is_file($sqlFile) && !@unlink($sqlFile)) {
|
||||||
error_log('MokoSuiteBackup: Could not delete temp SQL file: ' . $sqlFile);
|
error_log('MokoJoomBackup: Could not delete temp SQL file: ' . $sqlFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
$totalSize = file_exists($session->archivePath) ? filesize($session->archivePath) : 0;
|
$totalSize = file_exists($session->archivePath) ? filesize($session->archivePath) : 0;
|
||||||
@@ -344,7 +344,7 @@ class SteppedBackupEngine
|
|||||||
'filesexist' => 1,
|
'filesexist' => 1,
|
||||||
];
|
];
|
||||||
|
|
||||||
$db->updateObject('#__mokosuitebackup_records', $update, 'id');
|
$db->updateObject('#__mokojoombackup_records', $update, 'id');
|
||||||
|
|
||||||
$session->currentStep++;
|
$session->currentStep++;
|
||||||
$session->phase = ($session->remoteStorage !== 'none') ? 'upload' : 'complete';
|
$session->phase = ($session->remoteStorage !== 'none') ? 'upload' : 'complete';
|
||||||
@@ -366,7 +366,7 @@ class SteppedBackupEngine
|
|||||||
// Reload profile for remote settings
|
// Reload profile for remote settings
|
||||||
$query = $db->getQuery(true)
|
$query = $db->getQuery(true)
|
||||||
->select('*')
|
->select('*')
|
||||||
->from($db->quoteName('#__mokosuitebackup_profiles'))
|
->from($db->quoteName('#__mokojoombackup_profiles'))
|
||||||
->where($db->quoteName('id') . ' = ' . $session->profileId);
|
->where($db->quoteName('id') . ' = ' . $session->profileId);
|
||||||
$db->setQuery($query);
|
$db->setQuery($query);
|
||||||
$profile = $db->loadObject();
|
$profile = $db->loadObject();
|
||||||
@@ -402,7 +402,7 @@ class SteppedBackupEngine
|
|||||||
'filesexist' => is_file($session->archivePath) ? 1 : 0,
|
'filesexist' => is_file($session->archivePath) ? 1 : 0,
|
||||||
];
|
];
|
||||||
|
|
||||||
$db->updateObject('#__mokosuitebackup_records', $update, 'id');
|
$db->updateObject('#__mokojoombackup_records', $update, 'id');
|
||||||
|
|
||||||
$session->currentStep++;
|
$session->currentStep++;
|
||||||
$session->phase = 'complete';
|
$session->phase = 'complete';
|
||||||
@@ -421,7 +421,7 @@ class SteppedBackupEngine
|
|||||||
// Write log file alongside the archive
|
// Write log file alongside the archive
|
||||||
$logPath = BackupDirectory::logPathFromArchive($session->archivePath);
|
$logPath = BackupDirectory::logPathFromArchive($session->archivePath);
|
||||||
if (@file_put_contents($logPath, $logContent) === false) {
|
if (@file_put_contents($logPath, $logContent) === false) {
|
||||||
error_log('MokoSuiteBackup: Could not write log file: ' . $logPath);
|
error_log('MokoJoomBackup: Could not write log file: ' . $logPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
$update = (object) [
|
$update = (object) [
|
||||||
@@ -431,7 +431,7 @@ class SteppedBackupEngine
|
|||||||
'log' => $logContent,
|
'log' => $logContent,
|
||||||
];
|
];
|
||||||
|
|
||||||
$db->updateObject('#__mokosuitebackup_records', $update, 'id');
|
$db->updateObject('#__mokojoombackup_records', $update, 'id');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -447,7 +447,7 @@ class SteppedBackupEngine
|
|||||||
'log' => implode("\n", $session->log),
|
'log' => implode("\n", $session->log),
|
||||||
];
|
];
|
||||||
|
|
||||||
$db->updateObject('#__mokosuitebackup_records', $update, 'id');
|
$db->updateObject('#__mokojoombackup_records', $update, 'id');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
+4
-4
@@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
* Phases: init → database → files → finalize → upload → complete
|
* Phases: init → database → files → finalize → upload → complete
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Engine;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Engine;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ class SteppedSession
|
|||||||
|
|
||||||
private static function getSessionDir(): string
|
private static function getSessionDir(): string
|
||||||
{
|
{
|
||||||
$dir = JPATH_ROOT . '/tmp/mokosuitebackup-sessions';
|
$dir = JPATH_ROOT . '/tmp/mokojoombackup-sessions';
|
||||||
|
|
||||||
if (!is_dir($dir)) {
|
if (!is_dir($dir)) {
|
||||||
if (!mkdir($dir, 0755, true)) {
|
if (!mkdir($dir, 0755, true)) {
|
||||||
+3
-3
@@ -1,14 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Engine;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Engine;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
+3
-3
@@ -1,14 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Engine;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Engine;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package MokoJoomBackup
|
||||||
|
* @subpackage com_mokojoombackup
|
||||||
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Extension;
|
||||||
|
|
||||||
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
|
use Joomla\CMS\Extension\MVCComponent;
|
||||||
|
use Joomla\CMS\Factory;
|
||||||
|
|
||||||
|
class MokoJoomBackupComponent extends MVCComponent
|
||||||
|
{
|
||||||
|
public function boot(): void
|
||||||
|
{
|
||||||
|
parent::boot();
|
||||||
|
|
||||||
|
try {
|
||||||
|
$app = Factory::getApplication();
|
||||||
|
|
||||||
|
if (!$app->isClient('administrator')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$wa = $app->getDocument()->getWebAssetManager();
|
||||||
|
$wa->addInlineStyle(
|
||||||
|
'#menu a[href*="com_mokojoombackup"][href*="view=dashboard"] .sidebar-item-title::before,'
|
||||||
|
. ' #menu a[href*="com_mokojoombackup"][href*="view=backups"] .sidebar-item-title::before,'
|
||||||
|
. ' #menu a[href*="com_mokojoombackup"][href*="view=profiles"] .sidebar-item-title::before'
|
||||||
|
. ' { font-family: "Font Awesome 6 Free"; font-weight: 900; margin-right: .5em; }'
|
||||||
|
. ' #menu a[href*="com_mokojoombackup"][href*="view=dashboard"] .sidebar-item-title::before { content: "\f015"; }'
|
||||||
|
. ' #menu a[href*="com_mokojoombackup"][href*="view=backups"] .sidebar-item-title::before { content: "\f1c0"; }'
|
||||||
|
. ' #menu a[href*="com_mokojoombackup"][href*="view=profiles"] .sidebar-item-title::before { content: "\f013"; }'
|
||||||
|
);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
error_log('MokoJoomBackup: boot() CSS injection failed: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-3
@@ -1,14 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Field;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Field;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
+4
-4
@@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
* Loads the directory tree from the server via AJAX (browseDir endpoint).
|
* Loads the directory tree from the server via AJAX (browseDir endpoint).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Field;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Field;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
@@ -163,7 +163,7 @@ class DirectoryFilterField extends FormField
|
|||||||
const tokenName = Joomla.getOptions('csrf.token') || '';
|
const tokenName = Joomla.getOptions('csrf.token') || '';
|
||||||
if (tokenName) form.append(tokenName, '1');
|
if (tokenName) form.append(tokenName, '1');
|
||||||
|
|
||||||
fetch('index.php?option=com_mokosuitebackup&format=json', {
|
fetch('index.php?option=com_mokojoombackup&format=json', {
|
||||||
method: 'POST', body: form,
|
method: 'POST', body: form,
|
||||||
headers: { 'X-Requested-With': 'XMLHttpRequest' }
|
headers: { 'X-Requested-With': 'XMLHttpRequest' }
|
||||||
})
|
})
|
||||||
+3
-3
@@ -1,14 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Field;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Field;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
+9
-55
@@ -1,21 +1,21 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Field;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Field;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
use Joomla\CMS\Factory;
|
use Joomla\CMS\Factory;
|
||||||
use Joomla\CMS\Form\FormField;
|
use Joomla\CMS\Form\FormField;
|
||||||
use Joomla\CMS\Language\Text;
|
use Joomla\CMS\Language\Text;
|
||||||
use Joomla\Component\MokoSuiteBackup\Administrator\Utility\BackupDirectory;
|
use Joomla\Component\MokoJoomBackup\Administrator\Utility\BackupDirectory;
|
||||||
|
|
||||||
class FolderPickerField extends FormField
|
class FolderPickerField extends FormField
|
||||||
{
|
{
|
||||||
@@ -51,7 +51,6 @@ class FolderPickerField extends FormField
|
|||||||
|
|
||||||
$placeholders = [
|
$placeholders = [
|
||||||
'[DEFAULT_DIR]' => BackupDirectory::getDefaultAbsolute(),
|
'[DEFAULT_DIR]' => BackupDirectory::getDefaultAbsolute(),
|
||||||
'[HOME]' => BackupDirectory::getHomeDirectory(),
|
|
||||||
'[host]' => $hostname,
|
'[host]' => $hostname,
|
||||||
'[site_name]' => $sanitizedSiteName ?: 'joomla',
|
'[site_name]' => $sanitizedSiteName ?: 'joomla',
|
||||||
'[profile_id]' => '1',
|
'[profile_id]' => '1',
|
||||||
@@ -91,14 +90,11 @@ class FolderPickerField extends FormField
|
|||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="text" name="{$name}" id="{$id}" value="{$value}"
|
<input type="text" name="{$name}" id="{$id}" value="{$value}"
|
||||||
class="form-control" maxlength="512"
|
class="form-control" maxlength="512"
|
||||||
placeholder="[HOME]/backups or [DEFAULT_DIR]" />
|
placeholder="[DEFAULT_DIR] or /home/user/backups/[host]" />
|
||||||
<button type="button" class="btn btn-outline-secondary" id="{$id}_btn">
|
<button type="button" class="btn btn-outline-secondary" id="{$id}_btn">
|
||||||
<span class="icon-folder-open" aria-hidden="true"></span>
|
<span class="icon-folder-open" aria-hidden="true"></span>
|
||||||
Browse
|
Browse
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn btn-outline-info" data-bs-toggle="modal" data-bs-target="#{$id}_helpModal" title="Available placeholders">
|
|
||||||
<span class="icon-question-circle" aria-hidden="true"></span>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-1" id="{$id}_status">
|
<div class="mt-1" id="{$id}_status">
|
||||||
<small class="{$statusClass}">
|
<small class="{$statusClass}">
|
||||||
@@ -110,44 +106,6 @@ class FolderPickerField extends FormField
|
|||||||
<span class="icon-warning-circle" aria-hidden="true"></span>
|
<span class="icon-warning-circle" aria-hidden="true"></span>
|
||||||
The default backup directory is inside the web root. Backup archives may be directly downloadable if <code>.htaccess</code> is not supported. For better security, use a path outside the web root.
|
The default backup directory is inside the web root. Backup archives may be directly downloadable if <code>.htaccess</code> is not supported. For better security, use a path outside the web root.
|
||||||
</div>
|
</div>
|
||||||
<div class="modal fade" id="{$id}_helpModal" tabindex="-1" aria-labelledby="{$id}_helpLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title" id="{$id}_helpLabel">Backup Directory Placeholders</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<p>Use these placeholders in the backup directory path. They are resolved at backup time.</p>
|
|
||||||
<table class="table table-sm table-striped">
|
|
||||||
<thead><tr><th>Placeholder</th><th>Description</th><th>Example</th></tr></thead>
|
|
||||||
<tbody>
|
|
||||||
<tr><td><code>[HOME]</code></td><td>Home directory of the server user</td><td><code>{$placeholders['[HOME]']}</code></td></tr>
|
|
||||||
<tr><td><code>[DEFAULT_DIR]</code></td><td>Default backup directory (inside web root)</td><td><code>{$placeholders['[DEFAULT_DIR]']}</code></td></tr>
|
|
||||||
<tr><td><code>[host]</code></td><td>Server hostname</td><td><code>{$placeholders['[host]']}</code></td></tr>
|
|
||||||
<tr><td><code>[site_name]</code></td><td>Joomla site name</td><td><code>{$placeholders['[site_name]']}</code></td></tr>
|
|
||||||
<tr><td><code>[date]</code></td><td>Date (Ymd)</td><td><code>{$placeholders['[date]']}</code></td></tr>
|
|
||||||
<tr><td><code>[year]</code></td><td>Four-digit year</td><td><code>{$placeholders['[year]']}</code></td></tr>
|
|
||||||
<tr><td><code>[month]</code></td><td>Two-digit month</td><td><code>{$placeholders['[month]']}</code></td></tr>
|
|
||||||
<tr><td><code>[day]</code></td><td>Two-digit day</td><td><code>{$placeholders['[day]']}</code></td></tr>
|
|
||||||
<tr><td><code>[profile_id]</code></td><td>Backup profile ID</td><td><code>1</code></td></tr>
|
|
||||||
<tr><td><code>[profile_name]</code></td><td>Profile title</td><td><code>default</code></td></tr>
|
|
||||||
<tr><td><code>[type]</code></td><td>Backup type</td><td><code>full</code></td></tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<h6>Recommended Paths</h6>
|
|
||||||
<ul class="list-unstyled">
|
|
||||||
<li><code>[HOME]/backups</code> — Outside web root (recommended)</li>
|
|
||||||
<li><code>[HOME]/backups/[host]</code> — Per-site subdirectory</li>
|
|
||||||
<li><code>[DEFAULT_DIR]</code> — Inside web root (protected by .htaccess)</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="{$id}_browser" class="card mt-2" style="display:none; max-height:300px; overflow-y:auto;">
|
<div id="{$id}_browser" class="card mt-2" style="display:none; max-height:300px; overflow-y:auto;">
|
||||||
<div class="card-body p-2">
|
<div class="card-body p-2">
|
||||||
<div id="{$id}_tree"></div>
|
<div id="{$id}_tree"></div>
|
||||||
@@ -204,12 +162,8 @@ class FolderPickerField extends FormField
|
|||||||
function setDefaultDirWarning() {
|
function setDefaultDirWarning() {
|
||||||
var warn = document.getElementById(fieldId + '_defaultwarn');
|
var warn = document.getElementById(fieldId + '_defaultwarn');
|
||||||
var val = input.value.trim();
|
var val = input.value.trim();
|
||||||
var resolved = resolve(val);
|
var isDefault = (!val || val === '[DEFAULT_DIR]' || val === 'administrator/components/com_mokojoombackup/backups');
|
||||||
var jRoot = placeholders['[DEFAULT_DIR]'].replace(/\/administrator\/components\/com_mokosuitebackup\/backups$/, '');
|
if (warn) warn.style.display = isDefault ? 'block' : 'none';
|
||||||
var isInsideWebRoot = resolved && resolved.indexOf(jRoot) === 0;
|
|
||||||
var isOldDefault = val === 'administrator/components/com_mokosuitebackup/backups' || val === 'administrator/components/com_mokojoombackup/backups' || val === '[DEFAULT_DIR]';
|
|
||||||
var showWarning = isOldDefault || isInsideWebRoot;
|
|
||||||
if (warn) warn.style.display = showWarning ? 'block' : 'none';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkDirPermissions() {
|
function checkDirPermissions() {
|
||||||
@@ -225,7 +179,7 @@ class FolderPickerField extends FormField
|
|||||||
var tokenName = Joomla.getOptions('csrf.token') || '';
|
var tokenName = Joomla.getOptions('csrf.token') || '';
|
||||||
if (tokenName) form.append(tokenName, '1');
|
if (tokenName) form.append(tokenName, '1');
|
||||||
|
|
||||||
fetch('index.php?option=com_mokosuitebackup&format=json', {
|
fetch('index.php?option=com_mokojoombackup&format=json', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: form,
|
body: form,
|
||||||
headers: { 'X-Requested-With': 'XMLHttpRequest' }
|
headers: { 'X-Requested-With': 'XMLHttpRequest' }
|
||||||
@@ -283,7 +237,7 @@ class FolderPickerField extends FormField
|
|||||||
var tokenName = Joomla.getOptions('csrf.token') || '';
|
var tokenName = Joomla.getOptions('csrf.token') || '';
|
||||||
if (tokenName) form.append(tokenName, '1');
|
if (tokenName) form.append(tokenName, '1');
|
||||||
|
|
||||||
fetch('index.php?option=com_mokosuitebackup&format=json', {
|
fetch('index.php?option=com_mokojoombackup&format=json', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: form,
|
body: form,
|
||||||
headers: { 'X-Requested-With': 'XMLHttpRequest' }
|
headers: { 'X-Requested-With': 'XMLHttpRequest' }
|
||||||
+5
-5
@@ -1,14 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Model;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Model;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ class BackupModel extends AdminModel
|
|||||||
public function getForm($data = [], $loadData = true)
|
public function getForm($data = [], $loadData = true)
|
||||||
{
|
{
|
||||||
$form = $this->loadForm(
|
$form = $this->loadForm(
|
||||||
'com_mokosuitebackup.backup',
|
'com_mokojoombackup.backup',
|
||||||
'backup',
|
'backup',
|
||||||
['control' => 'jform', 'load_data' => $loadData]
|
['control' => 'jform', 'load_data' => $loadData]
|
||||||
);
|
);
|
||||||
@@ -30,7 +30,7 @@ class BackupModel extends AdminModel
|
|||||||
|
|
||||||
protected function loadFormData(): object
|
protected function loadFormData(): object
|
||||||
{
|
{
|
||||||
$data = Factory::getApplication()->getUserState('com_mokosuitebackup.edit.backup.data', []);
|
$data = Factory::getApplication()->getUserState('com_mokojoombackup.edit.backup.data', []);
|
||||||
|
|
||||||
if (empty($data)) {
|
if (empty($data)) {
|
||||||
$data = $this->getItem();
|
$data = $this->getItem();
|
||||||
+5
-5
@@ -1,14 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Model;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Model;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
@@ -41,11 +41,11 @@ class BackupsModel extends ListModel
|
|||||||
$query = $db->getQuery(true);
|
$query = $db->getQuery(true);
|
||||||
|
|
||||||
$query->select('a.*')
|
$query->select('a.*')
|
||||||
->from($db->quoteName('#__mokosuitebackup_records', 'a'));
|
->from($db->quoteName('#__mokojoombackup_records', 'a'));
|
||||||
|
|
||||||
// Join profile title
|
// Join profile title
|
||||||
$query->select($db->quoteName('p.title', 'profile_title'))
|
$query->select($db->quoteName('p.title', 'profile_title'))
|
||||||
->join('LEFT', $db->quoteName('#__mokosuitebackup_profiles', 'p') . ' ON p.id = a.profile_id');
|
->join('LEFT', $db->quoteName('#__mokojoombackup_profiles', 'p') . ' ON p.id = a.profile_id');
|
||||||
|
|
||||||
// Filter by status
|
// Filter by status
|
||||||
$status = $this->getState('filter.status');
|
$status = $this->getState('filter.status');
|
||||||
+20
-30
@@ -1,20 +1,20 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Model;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Model;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
use Joomla\CMS\Factory;
|
use Joomla\CMS\Factory;
|
||||||
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
|
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
|
||||||
use Joomla\Component\MokoSuiteBackup\Administrator\Utility\BackupDirectory;
|
use Joomla\Component\MokoJoomBackup\Administrator\Utility\BackupDirectory;
|
||||||
|
|
||||||
class DashboardModel extends BaseDatabaseModel
|
class DashboardModel extends BaseDatabaseModel
|
||||||
{
|
{
|
||||||
@@ -28,8 +28,8 @@ class DashboardModel extends BaseDatabaseModel
|
|||||||
$db = $this->getDatabase();
|
$db = $this->getDatabase();
|
||||||
$query = $db->getQuery(true)
|
$query = $db->getQuery(true)
|
||||||
->select('r.*, p.title AS profile_title')
|
->select('r.*, p.title AS profile_title')
|
||||||
->from($db->quoteName('#__mokosuitebackup_records', 'r'))
|
->from($db->quoteName('#__mokojoombackup_records', 'r'))
|
||||||
->join('LEFT', $db->quoteName('#__mokosuitebackup_profiles', 'p') . ' ON p.id = r.profile_id')
|
->join('LEFT', $db->quoteName('#__mokojoombackup_profiles', 'p') . ' ON p.id = r.profile_id')
|
||||||
->where($db->quoteName('r.status') . ' = ' . $db->quote('complete'))
|
->where($db->quoteName('r.status') . ' = ' . $db->quote('complete'))
|
||||||
->order($db->quoteName('r.backupend') . ' DESC');
|
->order($db->quoteName('r.backupend') . ' DESC');
|
||||||
$db->setQuery($query, 0, 1);
|
$db->setQuery($query, 0, 1);
|
||||||
@@ -38,7 +38,7 @@ class DashboardModel extends BaseDatabaseModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query com_scheduler for the next scheduled MokoSuiteBackup task.
|
* Query com_scheduler for the next scheduled MokoJoomBackup task.
|
||||||
*
|
*
|
||||||
* @return object|null Object with next_execution and title, or null
|
* @return object|null Object with next_execution and title, or null
|
||||||
*/
|
*/
|
||||||
@@ -50,7 +50,7 @@ class DashboardModel extends BaseDatabaseModel
|
|||||||
$query = $db->getQuery(true)
|
$query = $db->getQuery(true)
|
||||||
->select($db->quoteName(['t.next_execution', 't.title']))
|
->select($db->quoteName(['t.next_execution', 't.title']))
|
||||||
->from($db->quoteName('#__scheduler_tasks', 't'))
|
->from($db->quoteName('#__scheduler_tasks', 't'))
|
||||||
->where($db->quoteName('t.type') . ' = ' . $db->quote('mokosuitebackup.run_profile'))
|
->where($db->quoteName('t.type') . ' = ' . $db->quote('mokojoombackup.run_profile'))
|
||||||
->where($db->quoteName('t.state') . ' = 1')
|
->where($db->quoteName('t.state') . ' = 1')
|
||||||
->order($db->quoteName('t.next_execution') . ' ASC');
|
->order($db->quoteName('t.next_execution') . ' ASC');
|
||||||
$db->setQuery($query, 0, 1);
|
$db->setQuery($query, 0, 1);
|
||||||
@@ -74,7 +74,7 @@ class DashboardModel extends BaseDatabaseModel
|
|||||||
$query = $db->getQuery(true)
|
$query = $db->getQuery(true)
|
||||||
->select('COUNT(*) AS total_count')
|
->select('COUNT(*) AS total_count')
|
||||||
->select('COALESCE(SUM(' . $db->quoteName('total_size') . '), 0) AS total_size')
|
->select('COALESCE(SUM(' . $db->quoteName('total_size') . '), 0) AS total_size')
|
||||||
->from($db->quoteName('#__mokosuitebackup_records'))
|
->from($db->quoteName('#__mokojoombackup_records'))
|
||||||
->where($db->quoteName('status') . ' = ' . $db->quote('complete'));
|
->where($db->quoteName('status') . ' = ' . $db->quote('complete'));
|
||||||
$db->setQuery($query);
|
$db->setQuery($query);
|
||||||
$stats = $db->loadObject();
|
$stats = $db->loadObject();
|
||||||
@@ -83,7 +83,7 @@ class DashboardModel extends BaseDatabaseModel
|
|||||||
$cutoff = date('Y-m-d H:i:s', strtotime('-7 days'));
|
$cutoff = date('Y-m-d H:i:s', strtotime('-7 days'));
|
||||||
$query = $db->getQuery(true)
|
$query = $db->getQuery(true)
|
||||||
->select('COUNT(*) AS fail_count')
|
->select('COUNT(*) AS fail_count')
|
||||||
->from($db->quoteName('#__mokosuitebackup_records'))
|
->from($db->quoteName('#__mokojoombackup_records'))
|
||||||
->where($db->quoteName('status') . ' = ' . $db->quote('fail'))
|
->where($db->quoteName('status') . ' = ' . $db->quote('fail'))
|
||||||
->where($db->quoteName('backupstart') . ' >= ' . $db->quote($cutoff));
|
->where($db->quoteName('backupstart') . ' >= ' . $db->quote($cutoff));
|
||||||
$db->setQuery($query);
|
$db->setQuery($query);
|
||||||
@@ -129,7 +129,7 @@ class DashboardModel extends BaseDatabaseModel
|
|||||||
$db2 = $this->getDatabase();
|
$db2 = $this->getDatabase();
|
||||||
$qDir = $db2->getQuery(true)
|
$qDir = $db2->getQuery(true)
|
||||||
->select($db2->quoteName('backup_dir'))
|
->select($db2->quoteName('backup_dir'))
|
||||||
->from($db2->quoteName('#__mokosuitebackup_profiles'))
|
->from($db2->quoteName('#__mokojoombackup_profiles'))
|
||||||
->where($db2->quoteName('published') . ' = 1')
|
->where($db2->quoteName('published') . ' = 1')
|
||||||
->where($db2->quoteName('backup_dir') . ' != ' . $db2->quote(''))
|
->where($db2->quoteName('backup_dir') . ' != ' . $db2->quote(''))
|
||||||
->where($db2->quoteName('backup_dir') . ' IS NOT NULL');
|
->where($db2->quoteName('backup_dir') . ' IS NOT NULL');
|
||||||
@@ -176,26 +176,16 @@ class DashboardModel extends BaseDatabaseModel
|
|||||||
{
|
{
|
||||||
$db = $this->getDatabase();
|
$db = $this->getDatabase();
|
||||||
$query = $db->getQuery(true)
|
$query = $db->getQuery(true)
|
||||||
->select($db->quoteName('backup_dir'))
|
->select('COUNT(*)')
|
||||||
->from($db->quoteName('#__mokosuitebackup_profiles'))
|
->from($db->quoteName('#__mokojoombackup_profiles'))
|
||||||
->where($db->quoteName('published') . ' = 1');
|
->where($db->quoteName('published') . ' = 1')
|
||||||
|
->where('(' . $db->quoteName('backup_dir') . ' = ' . $db->quote(BackupDirectory::DEFAULT_RELATIVE)
|
||||||
|
. ' OR ' . $db->quoteName('backup_dir') . ' = ' . $db->quote(BackupDirectory::PLACEHOLDER)
|
||||||
|
. ' OR ' . $db->quoteName('backup_dir') . ' = ' . $db->quote('')
|
||||||
|
. ' OR ' . $db->quoteName('backup_dir') . ' IS NULL)');
|
||||||
$db->setQuery($query);
|
$db->setQuery($query);
|
||||||
$dirs = $db->loadColumn();
|
|
||||||
|
|
||||||
// Warn only if any profile's resolved path is inside the web root
|
return (int) $db->loadResult() > 0;
|
||||||
foreach ($dirs as $dir) {
|
|
||||||
$resolved = BackupDirectory::resolve($dir ?: BackupDirectory::DEFAULT_RELATIVE);
|
|
||||||
|
|
||||||
if (BackupDirectory::hasPlaceholders($resolved)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (BackupDirectory::isWebAccessible($resolved)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -208,7 +198,7 @@ class DashboardModel extends BaseDatabaseModel
|
|||||||
$db = $this->getDatabase();
|
$db = $this->getDatabase();
|
||||||
$query = $db->getQuery(true)
|
$query = $db->getQuery(true)
|
||||||
->select($db->quoteName(['id', 'title', 'backup_type']))
|
->select($db->quoteName(['id', 'title', 'backup_type']))
|
||||||
->from($db->quoteName('#__mokosuitebackup_profiles'))
|
->from($db->quoteName('#__mokojoombackup_profiles'))
|
||||||
->where($db->quoteName('published') . ' = 1')
|
->where($db->quoteName('published') . ' = 1')
|
||||||
->order($db->quoteName('ordering') . ' ASC');
|
->order($db->quoteName('ordering') . ' ASC');
|
||||||
$db->setQuery($query);
|
$db->setQuery($query);
|
||||||
+5
-5
@@ -1,14 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package MokoSuiteBackup
|
* @package MokoJoomBackup
|
||||||
* @subpackage com_mokosuitebackup
|
* @subpackage com_mokojoombackup
|
||||||
* @author Moko Consulting <hello@mokoconsulting.tech>
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
||||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||||
* @license GNU General Public License version 3 or later; see LICENSE
|
* @license GNU General Public License version 3 or later; see LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Joomla\Component\MokoSuiteBackup\Administrator\Model;
|
namespace Joomla\Component\MokoJoomBackup\Administrator\Model;
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ class ProfileModel extends AdminModel
|
|||||||
public function getForm($data = [], $loadData = true)
|
public function getForm($data = [], $loadData = true)
|
||||||
{
|
{
|
||||||
$form = $this->loadForm(
|
$form = $this->loadForm(
|
||||||
'com_mokosuitebackup.profile',
|
'com_mokojoombackup.profile',
|
||||||
'profile',
|
'profile',
|
||||||
['control' => 'jform', 'load_data' => $loadData]
|
['control' => 'jform', 'load_data' => $loadData]
|
||||||
);
|
);
|
||||||
@@ -30,7 +30,7 @@ class ProfileModel extends AdminModel
|
|||||||
|
|
||||||
protected function loadFormData(): object
|
protected function loadFormData(): object
|
||||||
{
|
{
|
||||||
$data = Factory::getApplication()->getUserState('com_mokosuitebackup.edit.profile.data', []);
|
$data = Factory::getApplication()->getUserState('com_mokojoombackup.edit.profile.data', []);
|
||||||
|
|
||||||
if (empty($data)) {
|
if (empty($data)) {
|
||||||
$data = $this->getItem();
|
$data = $this->getItem();
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user