diff --git a/.mokogitea/workflows/update-server.yml b/.mokogitea/workflows/update-server.yml index 6e617f6a..510ad8ef 100644 --- a/.mokogitea/workflows/update-server.yml +++ b/.mokogitea/workflows/update-server.yml @@ -73,12 +73,12 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@v4 with: token: ${{ secrets.GA_TOKEN }} fetch-depth: 0 - - name: Setup MokoStandards tools + - name: Setup moko-platform tools env: MOKO_CLONE_TOKEN: ${{ secrets.GA_TOKEN }} MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting @@ -87,11 +87,15 @@ jobs: 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 fi - 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 + if [ -d "/tmp/moko-platform" ]; then + echo "moko-platform already available — skipping clone" + else + git clone --depth 1 --branch main --quiet \ + "https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git" \ + /tmp/moko-platform 2>/dev/null || true + fi + if [ -d "/tmp/moko-platform" ] && [ -f "/tmp/moko-platform/composer.json" ]; then + cd /tmp/moko-platform && composer install --no-dev --no-interaction --quiet 2>/dev/null || true fi - name: Generate updates.xml entry @@ -100,14 +104,14 @@ jobs: BRANCH="${{ github.ref_name }}" REPO="${{ github.repository }}" API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" - VERSION=$(php /tmp/mokostandards-api/cli/version_read.php --path . 2>/dev/null || echo "0.0.0") + VERSION=$(php /tmp/moko-platform/cli/version_read.php --path . 2>/dev/null || echo "0.0.0") # Auto-bump patch on all branches (dev, alpha, beta, rc) git config --local user.email "gitea-actions[bot]@mokoconsulting.tech" git config --local user.name "gitea-actions[bot]" - BUMPED=$(php /tmp/mokostandards-api/cli/version_bump.php --path . 2>/dev/null || true) + BUMPED=$(php /tmp/moko-platform/cli/version_bump.php --path . 2>/dev/null || true) if [ -n "$BUMPED" ]; then - VERSION=$(php /tmp/mokostandards-api/cli/version_read.php --path . 2>/dev/null || echo "$VERSION") + VERSION=$(php /tmp/moko-platform/cli/version_read.php --path . 2>/dev/null || echo "$VERSION") git add -A git commit -m "chore(version): auto-bump patch ${VERSION} [skip ci]" \ --author="gitea-actions[bot] " 2>/dev/null || true @@ -442,15 +446,190 @@ jobs: printf ',"password":"%s"}' "$DEV_PASS" >> /tmp/sftp-config.json fi - 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 --path . --src-dir "$SOURCE_DIR" --config /tmp/sftp-config.json - elif [ -f "/tmp/mokostandards-api/deploy/deploy-sftp.php" ]; then - php /tmp/mokostandards-api/deploy/deploy-sftp.php --path . --src-dir "$SOURCE_DIR" --config /tmp/sftp-config.json + PLATFORM=$(php /tmp/moko-platform/cli/platform_detect.php --path . 2>/dev/null || true) + if [ "$PLATFORM" = "waas-component" ] && [ -f "/tmp/moko-platform/deploy/deploy-joomla.php" ]; then + php /tmp/moko-platform/deploy/deploy-joomla.php --path . --src-dir "$SOURCE_DIR" --config /tmp/sftp-config.json + elif [ -f "/tmp/moko-platform/deploy/deploy-sftp.php" ]; then + php /tmp/moko-platform/deploy/deploy-sftp.php --path . --src-dir "$SOURCE_DIR" --config /tmp/sftp-config.json fi rm -f /tmp/deploy_key /tmp/sftp-config.json echo "SFTP deploy to dev complete" >> $GITHUB_STEP_SUMMARY + - name: Validate updates.xml integrity + run: | + ERRORS=0 + + if [ ! -f "updates.xml" ]; then + echo "::error::updates.xml not found" + exit 1 + fi + + # Well-formed XML + if ! python3 -c "import xml.etree.ElementTree as ET; ET.parse('updates.xml')" 2>/dev/null; then + echo "::error::updates.xml is not valid XML" + ERRORS=$((ERRORS+1)) + fi + + python3 << 'PYEOF' + import xml.etree.ElementTree as ET, sys, re, os + + tree = ET.parse("updates.xml") + root = tree.getroot() + updates = root.findall("update") + errors = 0 + warnings = 0 + seen_tags = set() + + # All 5 channels MUST be present + REQUIRED_CHANNELS = {"stable", "rc", "beta", "alpha", "dev"} + VALID_TAGS = REQUIRED_CHANNELS | {"development"} # accept legacy alias + REPO = os.environ.get("GITEA_REPO", "") + ORG = os.environ.get("GITEA_ORG", "MokoConsulting") + REPO_BASE = f"https://git.mokoconsulting.tech/{ORG}/" + + # Gitea release tag names per channel (Moko standard) + RELEASE_TAG_MAP = { + "stable": "stable", + "rc": "release-candidate", + "beta": "beta", + "alpha": "alpha", + "dev": "development", + "development": "development", + } + + # Joomla update XML required fields per + # https://docs.joomla.org/Deploying_an_Update_Server + REQUIRED_FIELDS = ["name", "element", "type", "version", "infourl"] + + for i, u in enumerate(updates): + tag_el = u.find("tags/tag") + tag = tag_el.text.strip() if tag_el is not None and tag_el.text else None + label = f"Entry {i+1} ({tag or '?'})" + + # -- Required Joomla fields -- + for field in REQUIRED_FIELDS: + el = u.find(field) + if el is None or not (el.text or "").strip(): + print(f"::error::{label}: missing required <{field}>") + errors += 1 + + # -- -- + dl = u.find("downloads/downloadurl") + if dl is None or not (dl.text or "").strip(): + print(f"::error::{label}: missing ") + errors += 1 + else: + dl_url = dl.text.strip() + # Must point to org repo + if REPO_BASE not in dl_url: + print(f"::error::{label}: download URL not under {REPO_BASE}: {dl_url}") + errors += 1 + # Must end in .zip + if not dl_url.endswith(".zip"): + print(f"::error::{label}: download URL must end in .zip: {dl_url}") + errors += 1 + # Must use correct Gitea release tag in path + if tag and tag in RELEASE_TAG_MAP: + expected_tag = RELEASE_TAG_MAP[tag] + if f"/download/{expected_tag}/" not in dl_url: + print(f"::error::{label}: download URL should contain /download/{expected_tag}/ but got: {dl_url}") + errors += 1 + + # -- (required for Joomla to match update) -- + client = u.find("client") + if client is None or not (client.text or "").strip(): + print(f"::error::{label}: missing (required for Joomla update matching)") + errors += 1 + + # -- -- + tp = u.find("targetplatform") + if tp is None: + print(f"::error::{label}: missing ") + errors += 1 + else: + tp_name = tp.get("name", "") + tp_ver = tp.get("version", "") + if tp_name != "joomla": + print(f"::error::{label}: targetplatform name should be 'joomla', got '{tp_name}'") + errors += 1 + if not tp_ver: + print(f"::error::{label}: targetplatform missing version regex") + errors += 1 + elif "5" not in tp_ver or "6" not in tp_ver: + print(f"::warning::{label}: targetplatform version may not cover Joomla 5+6: {tp_ver}") + warnings += 1 + + # -- must be valid Joomla type -- + type_el = u.find("type") + if type_el is not None and type_el.text: + valid_types = {"component", "module", "plugin", "template", "library", "package", "file"} + if type_el.text.strip() not in valid_types: + print(f"::error::{label}: invalid type '{type_el.text}' (expected: {valid_types})") + errors += 1 + + # -- format (XX.YY.ZZ with optional suffix) -- + ver_el = u.find("version") + if ver_el is not None and ver_el.text: + if not re.match(r"^\d{2}\.\d{2}\.\d{2}(-\w+)?$", ver_el.text.strip()): + print(f"::warning::{label}: version '{ver_el.text}' does not match XX.YY.ZZ format") + warnings += 1 + + # -- and -- + for field in ["maintainer", "maintainerurl"]: + el = u.find(field) + if el is None or not (el.text or "").strip(): + print(f"::warning::{label}: missing <{field}>") + warnings += 1 + + # -- Valid stability tag -- + if tag is None: + print(f"::error::{label}: missing ") + errors += 1 + elif tag not in VALID_TAGS: + print(f"::error::{label}: invalid tag '{tag}' (expected: {VALID_TAGS})") + errors += 1 + + # -- Duplicate tag check -- + norm_tag = "dev" if tag == "development" else tag + if norm_tag in seen_tags: + print(f"::error::{label}: duplicate channel '{tag}'") + errors += 1 + if norm_tag: + seen_tags.add(norm_tag) + + # -- All 5 channels must exist -- + missing = REQUIRED_CHANNELS - seen_tags + if missing: + print(f"::error::Missing required update channels: {', '.join(sorted(missing))}") + errors += 1 + + # -- Version ordering: higher stability must not exceed dev version -- + channel_versions = {} + for u in updates: + tag_el = u.find("tags/tag") + ver_el = u.find("version") + if tag_el is not None and ver_el is not None and tag_el.text and ver_el.text: + norm = "dev" if tag_el.text.strip() == "development" else tag_el.text.strip() + # Strip suffix for comparison (01.00.18-dev -> 01.00.18) + base_ver = re.sub(r"-\w+$", "", ver_el.text.strip()) + channel_versions[norm] = base_ver + + # Cascade check: dev >= alpha >= beta >= rc >= stable + ORDER = ["dev", "alpha", "beta", "rc", "stable"] + for j in range(1, len(ORDER)): + current = ORDER[j] + previous = ORDER[j - 1] + if current in channel_versions and previous in channel_versions: + if channel_versions[current] > channel_versions[previous]: + print(f"::error::{current} version ({channel_versions[current]}) is ahead of {previous} ({channel_versions[previous]})") + errors += 1 + + # -- Summary -- + print(f"\nupdates.xml validation: {len(updates)} entries, {errors} error(s), {warnings} warning(s)") + if errors > 0: + sys.exit(1) + PYEOF + - name: Summary if: always() run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index fb097dbc..f5160823 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Alias offline bypass: aliases with offline=No override Joomla's global offline setting, allowing access via alias domain while main site is down - Block non-master users from viewing or editing MokoWaaS plugin settings - Master user bypasses ALL tenant restrictions (install from URL, global config, sysinfo, installer, templates) +- Admin Help menu redirected to configured support URL (replaces help.joomla.org) ### Fixed - Install API endpoint: extract ZIP to temp directory before passing to Joomla Installer (was passing ZIP path directly) diff --git a/README.md b/README.md index 8bb1a09b..347b6f52 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ DEFGROUP: Joomla.Plugin INGROUP: MokoWaaS REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS - VERSION: 02.08.03 + VERSION: 02.10.03 PATH: /README.md BRIEF: MokoWaaS platform plugin for Joomla --> diff --git a/src/packages/com_mokowaas/mokowaas.xml b/src/packages/com_mokowaas/mokowaas.xml index 06c2e721..7318bff7 100644 --- a/src/packages/com_mokowaas/mokowaas.xml +++ b/src/packages/com_mokowaas/mokowaas.xml @@ -7,7 +7,7 @@ GPL-3.0-or-later hello@mokoconsulting.tech https://mokoconsulting.tech - 02.08.03 + 02.10.00 Minimal API-only component for MokoWaaS. Provides REST endpoints for site health, cache, updates, and backups. Moko\Component\MokoWaaS\Api diff --git a/src/packages/plg_system_mokowaas/Extension/MokoWaaS.php b/src/packages/plg_system_mokowaas/Extension/MokoWaaS.php index eb5f2c3b..7cd510cd 100644 --- a/src/packages/plg_system_mokowaas/Extension/MokoWaaS.php +++ b/src/packages/plg_system_mokowaas/Extension/MokoWaaS.php @@ -653,7 +653,7 @@ class MokoWaaS extends CMSPlugin return [ '{{BRAND_NAME}}' => $this->params->get('brand_name', 'MokoWaaS'), '{{COMPANY_NAME}}' => $this->params->get('company_name', 'Moko Consulting'), - '{{SUPPORT_URL}}' => $this->params->get('support_url', 'https://mokoconsulting.tech'), + '{{SUPPORT_URL}}' => $this->params->get('support_url', 'https://mokoconsulting.tech/support'), ]; } @@ -936,6 +936,7 @@ class MokoWaaS extends CMSPlugin } $this->injectFavicon($doc); + $this->redirectHelpMenu($doc); // Hide MokoWaaS from plugin list for non-master users if (!$this->isMasterUser()) @@ -975,6 +976,32 @@ class MokoWaaS extends CMSPlugin "); } + /** + * Redirect the admin Help menu link to the configured support URL. + * + * Joomla's Atum template hardcodes the Help link to help.joomla.org. + * This replaces it with the WaaS support URL via JS injection. + * + * @param \Joomla\CMS\Document\HtmlDocument $doc Document object + * + * @return void + * + * @since 02.10.00 + */ + protected function redirectHelpMenu($doc) + { + $supportUrl = $this->params->get('support_url', 'https://mokoconsulting.tech/support'); + + $doc->addScriptDeclaration(" + document.addEventListener('DOMContentLoaded', function() { + document.querySelectorAll('a[href*=\"help.joomla.org\"], a[href*=\"docs.joomla.org\"]').forEach(function(link) { + link.href = " . json_encode($supportUrl) . "; + link.target = '_blank'; + }); + }); + "); + } + /** * Protect the plugin from being disabled or uninstalled by non-master users. * Does NOT self-heal (no lock) — master users can still disable if needed. diff --git a/src/packages/plg_system_mokowaas/mokowaas.xml b/src/packages/plg_system_mokowaas/mokowaas.xml index a579876c..d13ff311 100644 --- a/src/packages/plg_system_mokowaas/mokowaas.xml +++ b/src/packages/plg_system_mokowaas/mokowaas.xml @@ -30,7 +30,7 @@ GNU General Public License version 3 or later; see LICENSE.md hello@mokoconsulting.tech https://mokoconsulting.tech - 02.08.03 + 02.10.00 This plugin rebrands the Joomla system interface with MokoWaaS identity. It applies language overrides and ensures consistent branding across the platform. Moko\Plugin\System\MokoWaaS script.php @@ -108,7 +108,7 @@ type="url" label="PLG_SYSTEM_MOKOWAAS_SUPPORT_URL_LABEL" description="PLG_SYSTEM_MOKOWAAS_SUPPORT_URL_DESC" - default="https://mokoconsulting.tech" + default="https://mokoconsulting.tech/support" />
$params->get('brand_name', 'MokoWaaS'), '{{COMPANY_NAME}}' => $params->get('company_name', 'Moko Consulting'), - '{{SUPPORT_URL}}' => $params->get('support_url', 'https://mokoconsulting.tech'), + '{{SUPPORT_URL}}' => $params->get('support_url', 'https://mokoconsulting.tech/support'), ]; } diff --git a/src/packages/plg_webservices_mokowaas/mokowaas.xml b/src/packages/plg_webservices_mokowaas/mokowaas.xml index 721388ed..aa6075e3 100644 --- a/src/packages/plg_webservices_mokowaas/mokowaas.xml +++ b/src/packages/plg_webservices_mokowaas/mokowaas.xml @@ -7,7 +7,7 @@ GPL-3.0-or-later hello@mokoconsulting.tech https://mokoconsulting.tech - 02.08.03 + 02.10.00 Joomla Web Services API routes for MokoWaaS site management — health checks, cache, updates, backups, and site info. Moko\Plugin\WebServices\MokoWaaS diff --git a/src/pkg_mokowaas.xml b/src/pkg_mokowaas.xml index 153d4a43..7875de20 100644 --- a/src/pkg_mokowaas.xml +++ b/src/pkg_mokowaas.xml @@ -2,7 +2,7 @@ MokoWaaS mokowaas - 02.08.03 + 02.10.00 2026-05-23 Moko Consulting hello@mokoconsulting.tech diff --git a/updates.xml b/updates.xml index 1b029a55..293258a2 100644 --- a/updates.xml +++ b/updates.xml @@ -1,7 +1,7 @@ @@ -10,12 +10,12 @@ MokoWaaS update pkg_mokowaas package - 02.08.02 + 02.09.00 site stable https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases/tag/stable - https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases/download/development/pkg_mokowaas-02.08.02-dev.zip + https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases/download/stable/pkg_mokowaas-02.09.00.zip Moko Consulting @@ -26,12 +26,12 @@ MokoWaaS update pkg_mokowaas package - 02.08.02 + 02.09.00 site rc https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases/tag/development - https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases/download/development/pkg_mokowaas-02.08.02-dev.zip + https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases/download/development/pkg_mokowaas-02.09.00-dev.zip Moko Consulting @@ -42,12 +42,12 @@ MokoWaaS update pkg_mokowaas package - 02.08.02 + 02.09.00 site beta https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases/tag/development - https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases/download/development/pkg_mokowaas-02.08.02-dev.zip + https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases/download/development/pkg_mokowaas-02.09.00-dev.zip Moko Consulting @@ -58,12 +58,12 @@ MokoWaaS update pkg_mokowaas package - 02.08.02 + 02.09.00 site alpha https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases/tag/development - https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases/download/development/pkg_mokowaas-02.08.02-dev.zip + https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases/download/development/pkg_mokowaas-02.09.00-dev.zip Moko Consulting @@ -74,12 +74,12 @@ MokoWaaS update pkg_mokowaas package - 02.08.02 + 02.09.00 site dev https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases/tag/development - https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases/download/development/pkg_mokowaas-02.08.02-dev.zip + https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases/download/development/pkg_mokowaas-02.09.00-dev.zip Moko Consulting @@ -92,14 +92,33 @@ plugin system site - 02.08.02 + 02.09.00 stable https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases/tag/development - https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases/download/development/pkg_mokowaas-02.08.02-dev.zip + https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases/download/development/pkg_mokowaas-02.09.00-dev.zip Moko Consulting https://mokoconsulting.tech + + + MokoWaaS + MokoWaaS development build. + pkg_mokowaas + package + 02.10.03 + 2026-05-26 + https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases/tag/development + + https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases/download/development/pkg_mokowaas-02.10.03-dev.zip + + ddf956ccf7f33d37b923c501bd7a58a38614b3566500c57b24eee0f5ac0201b9 + development + Moko Consulting + https://mokoconsulting.tech + + +