diff --git a/.github/workflows/auto-release.yml b/.github/workflows/auto-release.yml index 2570789..eefafbf 100644 --- a/.github/workflows/auto-release.yml +++ b/.github/workflows/auto-release.yml @@ -58,7 +58,7 @@ permissions: jobs: release: name: Build & Release Pipeline - runs-on: ubuntu-latest + runs-on: release if: >- github.event.pull_request.merged == true || github.event_name == 'workflow_dispatch' @@ -75,6 +75,10 @@ jobs: MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_TOKEN }}"}}' run: | + # Ensure PHP + Composer are available + 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 @@ -564,7 +568,6 @@ jobs: new_downloads = ( " \n" f" {zip_url}\n" - f" {tar_url}\n" " " ) block = re.sub(r' .*?', new_downloads, block, flags=re.DOTALL) @@ -592,69 +595,29 @@ jobs: --author="gitea-actions[bot] " || true git push || true - # Sync updates.xml to main via PR (respects branch protection) - if [ "$CURRENT_BRANCH" != "main" ]; then - GA_TOKEN="${{ secrets.GA_TOKEN }}" - API="${GITEA_URL:-https://git.mokoconsulting.tech}/api/v1/repos/${{ github.repository }}" - PR_BRANCH="chore/update-xml-${VERSION}" + # Sync updates.xml to main via direct API (always runs — may be on version/XX branch) + GA_TOKEN="${{ secrets.GA_TOKEN }}" + API="${GITEA_URL:-https://git.mokoconsulting.tech}/api/v1/repos/${{ github.repository }}" - # Create branch from main - MAIN_SHA=$(curl -sf -H "Authorization: token ${GA_TOKEN}" \ - "${API}/branches/main" | jq -r '.commit.sha // empty') + FILE_SHA=$(curl -sf -H "Authorization: token ${GA_TOKEN}" \ + "${API}/contents/updates.xml?ref=main" | jq -r '.sha // empty') - if [ -n "$MAIN_SHA" ]; then - curl -sf -X POST -H "Authorization: token ${GA_TOKEN}" \ - -H "Content-Type: application/json" \ - "${API}/branches" \ - -d "$(jq -n --arg name "$PR_BRANCH" --arg sha "$MAIN_SHA" \ - '{new_branch_name: $name, old_branch_name: "main"}')" > /dev/null 2>&1 || true - - # Update updates.xml on the PR branch - FILE_SHA=$(curl -sf -H "Authorization: token ${GA_TOKEN}" \ - "${API}/contents/updates.xml?ref=${PR_BRANCH}" | jq -r '.sha // empty') - - if [ -n "$FILE_SHA" ]; then - CONTENT=$(base64 -w0 updates.xml) - curl -sf -X PUT -H "Authorization: token ${GA_TOKEN}" \ - -H "Content-Type: application/json" \ - "${API}/contents/updates.xml" \ - -d "$(jq -n \ - --arg content "$CONTENT" \ - --arg sha "$FILE_SHA" \ - --arg msg "chore: update stable channel to ${VERSION} [skip ci]" \ - --arg branch "$PR_BRANCH" \ - '{content: $content, sha: $sha, message: $msg, branch: $branch}' - )" > /dev/null 2>&1 - - # Create PR - PR_URL=$(curl -sf -X POST -H "Authorization: token ${GA_TOKEN}" \ - -H "Content-Type: application/json" \ - "${API}/pulls" \ - -d "$(jq -n \ - --arg title "chore: update updates.xml for ${VERSION} [skip ci]" \ - --arg head "$PR_BRANCH" \ - --arg base "main" \ - --arg body "Auto-generated by release workflow. Updates updates.xml with SHA-256 and download URLs for ${VERSION}." \ - '{title: $title, head: $head, base: $base, body: $body}' - )" | jq -r '.number // empty') - - # Auto-merge the PR - if [ -n "$PR_URL" ]; then - curl -sf -X POST -H "Authorization: token ${GA_TOKEN}" \ - -H "Content-Type: application/json" \ - "${API}/pulls/${PR_URL}/merge" \ - -d '{"Do":"merge","merge_message_field":"chore: update updates.xml for '"${VERSION}"' [skip ci]"}' > /dev/null 2>&1 \ - && echo "updates.xml synced to main via PR #${PR_URL}" \ - || echo "PR #${PR_URL} created but auto-merge failed — merge manually" - - # Cleanup: delete PR branch - curl -sf -X DELETE -H "Authorization: token ${GA_TOKEN}" \ - "${API}/branches/${PR_BRANCH}" > /dev/null 2>&1 || true - else - echo "WARNING: failed to create PR for updates.xml sync" - fi - fi - fi + if [ -n "$FILE_SHA" ]; then + CONTENT=$(base64 -w0 updates.xml) + curl -sf -X PUT -H "Authorization: token ${GA_TOKEN}" \ + -H "Content-Type: application/json" \ + "${API}/contents/updates.xml" \ + -d "$(jq -n \ + --arg content "$CONTENT" \ + --arg sha "$FILE_SHA" \ + --arg msg "chore: sync updates.xml ${VERSION} [skip ci]" \ + --arg branch "main" \ + '{content: $content, sha: $sha, message: $msg, branch: $branch}' + )" > /dev/null 2>&1 \ + && echo "updates.xml synced to main via API" \ + || echo "WARNING: failed to sync updates.xml to main" + else + echo "WARNING: could not get updates.xml SHA from main" fi fi diff --git a/.github/workflows/update-payload.yml b/.github/workflows/update-payload.yml index 6a82008..d047ceb 100644 --- a/.github/workflows/update-payload.yml +++ b/.github/workflows/update-payload.yml @@ -1,4 +1,4 @@ -name: Update MokoCassiopeia Payload +name: Update MokoOnyx Payload on: push: @@ -14,25 +14,25 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Get latest MokoCassiopeia release URL + - name: Get latest MokoOnyx stable release URL id: moko run: | - DOWNLOAD_URL=$(curl -s https://api.github.com/repos/mokoconsulting-tech/MokoCassiopeia/releases \ - | jq -r '[.[] | select(.prerelease == false and .draft == false and (.assets | length > 0)][0].assets[0].browser_download_url') + DOWNLOAD_URL=$(curl -s https://git.mokoconsulting.tech/api/v1/repos/MokoConsulting/MokoOnyx/releases \ + | jq -r '[.[] | select(.prerelease == false and .draft == false and (.assets | length > 0))][0].assets[0].browser_download_url') echo "url=$DOWNLOAD_URL" >> $GITHUB_OUTPUT echo "Found: $DOWNLOAD_URL" - - name: Download MokoCassiopeia zip + - name: Download MokoOnyx zip if: steps.moko.outputs.url != 'null' run: | mkdir -p src/payload - curl -sL "${{ steps.moko.outputs.url }}" -o src/payload/mokocassiopeia.zip + curl -sL "${{ steps.moko.outputs.url }}" -o src/payload/mokoonyx.zip ls -la src/payload/ - name: Check if payload changed id: diff run: | - git add src/payload/mokocassiopeia.zip + git add src/payload/mokoonyx.zip if git diff --cached --quiet; then echo "changed=false" >> $GITHUB_OUTPUT else @@ -44,5 +44,5 @@ jobs: run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - git commit -m "chore: update mokocassiopeia payload" + git commit -m "chore: update mokoonyx payload" git push diff --git a/.github/workflows/update-server.yml b/.github/workflows/update-server.yml index cd9b515..f2972eb 100644 --- a/.github/workflows/update-server.yml +++ b/.github/workflows/update-server.yml @@ -13,16 +13,27 @@ # Writes updates.xml with multiple entries: # - stable on push to main (from auto-release) # - rc on push to rc/** -# - development on push to dev/** +# - development on push to dev or dev/** # # Joomla filters by user's "Minimum Stability" setting. name: Update Joomla Update Server XML Feed on: + push: + branches: + - 'dev' + - 'dev/**' + - 'alpha/**' + - 'beta/**' + - 'rc/**' + paths: + - 'src/**' + - 'htdocs/**' pull_request: types: [closed] branches: + - 'dev' - 'dev/**' - 'alpha/**' - 'beta/**' @@ -56,9 +67,9 @@ permissions: jobs: update-xml: name: Update updates.xml - runs-on: ubuntu-latest + runs-on: release if: >- - github.event.pull_request.merged == true || github.event_name == 'workflow_dispatch' + github.event.pull_request.merged == true || github.event_name == 'workflow_dispatch' || github.event_name == 'push' steps: - name: Checkout repository @@ -73,6 +84,9 @@ jobs: MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_TOKEN }}"}}' run: | + 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 @@ -109,7 +123,7 @@ jobs: STABILITY="beta" elif [[ "$BRANCH" == alpha/* ]]; then STABILITY="alpha" - elif [[ "$BRANCH" == dev/* ]]; then + elif [[ "$BRANCH" == dev/* ]] || [[ "$BRANCH" == "dev" ]]; then STABILITY="development" else STABILITY="stable" @@ -271,9 +285,7 @@ jobs: NEW_ENTRY="${NEW_ENTRY} \n" NEW_ENTRY="${NEW_ENTRY} ${INFO_URL}\n" NEW_ENTRY="${NEW_ENTRY} \n" - TAR_URL="${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/download/${RELEASE_TAG}/${EXT_ELEMENT}-${DISPLAY_VERSION}.tar.gz" NEW_ENTRY="${NEW_ENTRY} ${DOWNLOAD_URL}\n" - NEW_ENTRY="${NEW_ENTRY} ${TAR_URL}\n" NEW_ENTRY="${NEW_ENTRY} \n" [ -n "$SHA256" ] && NEW_ENTRY="${NEW_ENTRY} ${SHA256}\n" NEW_ENTRY="${NEW_ENTRY} ${TARGET_PLATFORM}\n" @@ -367,6 +379,33 @@ jobs: git push } + # -- Sync updates.xml to main (for non-main branches) ---------------------- + - name: Sync updates.xml to main + if: github.ref_name != 'main' + run: | + API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" + GA_TOKEN="${{ secrets.GA_TOKEN }}" + + FILE_SHA=$(curl -sf -H "Authorization: token ${GA_TOKEN}" \ + "${API_BASE}/contents/updates.xml?ref=main" | python3 -c "import sys,json; print(json.load(sys.stdin).get('sha',''))" 2>/dev/null || true) + + if [ -n "$FILE_SHA" ] && [ -f "updates.xml" ]; then + CONTENT=$(base64 -w0 updates.xml) + curl -sf -X PUT -H "Authorization: token ${GA_TOKEN}" \ + -H "Content-Type: application/json" \ + "${API_BASE}/contents/updates.xml" \ + -d "$(python3 -c "import json; print(json.dumps({ + 'content': '${CONTENT}', + 'sha': '${FILE_SHA}', + 'message': 'chore: sync updates.xml from ${STABILITY} [skip ci]', + 'branch': 'main' + }))")" > /dev/null 2>&1 \ + && echo "updates.xml synced to main (${STABILITY})" >> $GITHUB_STEP_SUMMARY \ + || echo "WARNING: failed to sync updates.xml to main" >> $GITHUB_STEP_SUMMARY + else + echo "WARNING: could not get updates.xml SHA from main" >> $GITHUB_STEP_SUMMARY + fi + # -- Mirror to GitHub (stable and rc only) -------------------------------- - name: Mirror release to GitHub if: >- @@ -388,7 +427,7 @@ jobs: done - name: SFTP deploy to dev server - if: contains(github.ref, 'dev/') + if: contains(github.ref, 'dev/') || github.ref == 'refs/heads/dev' env: DEV_HOST: ${{ vars.DEV_FTP_HOST }} DEV_PATH: ${{ vars.DEV_FTP_PATH }} diff --git a/.gitignore b/.gitignore index 01449c1..4229e70 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,8 @@ TODO.md .env .env.local .env.*.local +.joomla-api-mcp.json +.mcp.json *.local.php *.secret.php configuration.php @@ -100,6 +102,7 @@ replit.md *.tar.gz *.tgz *.zip +!src/payload/*.zip artifacts/ release/ releases/ diff --git a/README.md b/README.md index 1c43871..e25489a 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ DEFGROUP: Joomla.Plugin INGROUP: MokoWaaS REPO: https://github.com/mokoconsulting-tech/mokowaas - VERSION: 02.01.15 + VERSION: 02.01.20 PATH: /README.md BRIEF: Rebranding plugin for MokoWaaS platform NOTE: Internal WaaS identity abstraction layer @@ -23,7 +23,7 @@ # MokoWaaS Plugin -[![Version](https://img.shields.io/badge/version-02.01.11-blue.svg?logo=v&logoColor=white)](https://github.com/mokoconsulting-tech/MokoWaaS/releases/tag/v02) +[![Version](https://img.shields.io/badge/version-02.01.18-blue.svg?logo=v&logoColor=white)](https://github.com/mokoconsulting-tech/MokoWaaS/releases/tag/v02) [![License](https://img.shields.io/badge/license-GPL--3.0--or--later-green.svg?logo=gnu&logoColor=white)](LICENSE) [![Joomla](https://img.shields.io/badge/Joomla-5.x%20%7C%206.x-red.svg?logo=joomla&logoColor=white)](https://www.joomla.org) [![PHP](https://img.shields.io/badge/PHP-8.1%2B-777BB4.svg?logo=php&logoColor=white)](https://www.php.net) @@ -322,22 +322,18 @@ See [LICENSE.md](LICENSE.md) for the full license text. This extension follows the [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards) version governance model using semantic versioning: `MAJOR.MINOR.PATCH` -Current version: **01.04.00** +Current version: **02.01.18** ## Changelog See [CHANGELOG.md](CHANGELOG.md) for a complete version history. -### Recent Changes (v01.04.00 - 2026-02-22) +### Recent Changes (v02.01.18 - 2026-04-23) -- Added complete Joomla 5.x system plugin implementation -- Created main plugin class with event handlers -- Implemented plugin manifest with Joomla 5.x namespace support -- Added dependency injection service provider -- Created plugin language files -- Integrated with language override system -- Enhanced language overrides (57+ strings) -- Fixed typo in error messages (OCCURRED) +- Always install and lock MokoOnyx template on install/update +- Always unlock MokoCassiopeia on install/update (allow uninstall) +- Bundle MokoOnyx payload (replaces MokoCassiopeia payload) +- Update payload workflow to fetch MokoOnyx from Gitea releases ## Contributing diff --git a/src/Extension/MokoWaaS.php b/src/Extension/MokoWaaS.php index 84575d4..e67eb2f 100644 --- a/src/Extension/MokoWaaS.php +++ b/src/Extension/MokoWaaS.php @@ -80,6 +80,9 @@ class MokoWaaS extends CMSPlugin // Security: HTTPS redirect (runs for all clients) $this->enforceHttps(); + // Dev mode: disable caching + $this->enforceDevMode(); + // Admin-only WaaS controls if ($this->app->isClient('administrator')) { @@ -965,6 +968,27 @@ class MokoWaaS extends CMSPlugin * * @since 02.01.08 */ + /** + * Disable caching when development mode is active. + * + * Sets the Joomla caching config to 0 at runtime so no page + * or component cache is used. Does not modify configuration.php. + * + * @return void + * + * @since 02.01.15 + */ + protected function enforceDevMode() + { + if (!$this->params->get('dev_mode', 0)) + { + return; + } + + $config = Factory::getConfig(); + $config->set('caching', 0); + } + protected function enforceHttps() { if (!$this->params->get('force_https', 0)) @@ -1529,8 +1553,78 @@ class MokoWaaS extends CMSPlugin */ protected function injectColorScheme($doc) { - // Colors are applied via Atum template style params in - // enforceAtumBranding(). No additional CSS injection needed. + $primary = $this->params->get('color_primary', ''); + $brandIcon = $this->params->get('brand_icon', ''); + $css = ''; + + // Brand button colors derived from primary color + if (!empty($primary)) + { + $primary = htmlspecialchars($primary, ENT_QUOTES, 'UTF-8'); + + $css .= '.btn-primary,' + . '.btn-primary:not(:disabled):not(.disabled){' + . 'background-color:' . $primary . ';' + . 'border-color:' . $primary . ';' + . 'color:#000;' + . 'box-shadow:0 2px 4px rgba(0,0,0,.15);}' + . '.btn-primary:hover,.btn-primary:focus{' + . 'background-color:' . $primary . ';' + . 'border-color:' . $primary . ';' + . 'color:#000;' + . 'filter:brightness(0.85);' + . 'box-shadow:0 4px 8px rgba(0,0,0,.2);}' + . '.btn-primary:active,.btn-primary.active{' + . 'background-color:' . $primary . ';' + . 'border-color:' . $primary . ';' + . 'color:#000;' + . 'filter:brightness(0.75);}' + . '.btn-outline-primary{' + . 'color:' . $primary . ';' + . 'border-color:' . $primary . ';' + . 'border-width:2px;}' + . '.btn-outline-primary:hover,.btn-outline-primary:focus{' + . 'background-color:' . $primary . ';' + . 'border-color:' . $primary . ';' + . 'color:#000;}'; + } + + // Drawer toggle button: flat edge on the sidebar-facing side + // Close button in drawer: styled to match brand + $css .= '[dir="ltr"] .main-nav-container .menu-collapse,' + . '[dir="ltr"] .sidebar-toggle{' + . 'border-top-left-radius:0!important;' + . 'border-bottom-left-radius:0!important;}' + . '[dir="rtl"] .main-nav-container .menu-collapse,' + . '[dir="rtl"] .sidebar-toggle{' + . 'border-top-right-radius:0!important;' + . 'border-bottom-right-radius:0!important;}' + . '.sidebar-wrapper .btn-close,' + . '.sidebar-wrapper [data-bs-dismiss]{' + . 'opacity:1;' + . 'filter:none;' + . 'font-size:1.1rem;}'; + + // Brand icon override (FontAwesome unicode codepoint) + if (!empty($brandIcon)) + { + $brandIcon = preg_replace('/[^a-fA-F0-9]/', '', $brandIcon); + + if (!empty($brandIcon)) + { + $css .= '.icon-joomla::before,' + . '.icon-brands.fa-joomla::before{' + . 'font-family:"Font Awesome 6 Free"!important;' + . 'content:"\\' . $brandIcon . '"!important;' + . 'font-weight:900!important;}'; + } + } + + if (!empty(trim($css))) + { + $css = str_replace('', '', $css); + $doc->addStyleDeclaration($css); + } } /** diff --git a/src/administrator/language/overrides/en-GB.override.ini b/src/administrator/language/overrides/en-GB.override.ini index 7832edd..ca5081b 100644 --- a/src/administrator/language/overrides/en-GB.override.ini +++ b/src/administrator/language/overrides/en-GB.override.ini @@ -107,3 +107,14 @@ JLIB_INSTALLER_ERROR_NOTFINDJOOMLAXMLSETUPFILE="Installer: Can't find {{BRAND_NA JLIB_HTML_POWERED_BY="Powered by {{BRAND_NAME}}" COM_ADMIN_HELP_DOCUMENTATION="{{BRAND_NAME}} Documentation" COM_ADMIN_HELP_SUPPORT="{{BRAND_NAME}} Support" + +; ===== Akeeba Ticket System (ATS) ===== +COM_ATS="{{BRAND_NAME}} Tickets" +COM_ATS_TITLE_TICKETS="{{BRAND_NAME}} Tickets" +COM_ATS_TITLE_TICKET="{{BRAND_NAME}} Ticket" +COM_ATS_TITLE_NEWTICKET="New {{BRAND_NAME}} Ticket" +COM_ATS_TITLE_CATEGORIES="Ticket Categories" +COM_ATS_MSG_TICKET_SAVED="Your {{BRAND_NAME}} ticket has been saved." +COM_ATS_MSG_TICKET_CLOSED="Your {{BRAND_NAME}} ticket has been closed." +COM_ATS_MSG_REPLY_SAVED="Your reply has been saved." +COM_ATS_LBL_POWEREDBY="Powered by {{BRAND_NAME}}" diff --git a/src/administrator/language/overrides/en-US.override.ini b/src/administrator/language/overrides/en-US.override.ini index dd17beb..02fc67f 100644 --- a/src/administrator/language/overrides/en-US.override.ini +++ b/src/administrator/language/overrides/en-US.override.ini @@ -107,3 +107,14 @@ JLIB_INSTALLER_ERROR_NOTFINDJOOMLAXMLSETUPFILE="Installer: Can't find {{BRAND_NA JLIB_HTML_POWERED_BY="Powered by {{BRAND_NAME}}" COM_ADMIN_HELP_DOCUMENTATION="{{BRAND_NAME}} Documentation" COM_ADMIN_HELP_SUPPORT="{{BRAND_NAME}} Support" + +; ===== Akeeba Ticket System (ATS) ===== +COM_ATS="{{BRAND_NAME}} Tickets" +COM_ATS_TITLE_TICKETS="{{BRAND_NAME}} Tickets" +COM_ATS_TITLE_TICKET="{{BRAND_NAME}} Ticket" +COM_ATS_TITLE_NEWTICKET="New {{BRAND_NAME}} Ticket" +COM_ATS_TITLE_CATEGORIES="Ticket Categories" +COM_ATS_MSG_TICKET_SAVED="Your {{BRAND_NAME}} ticket has been saved." +COM_ATS_MSG_TICKET_CLOSED="Your {{BRAND_NAME}} ticket has been closed." +COM_ATS_MSG_REPLY_SAVED="Your reply has been saved." +COM_ATS_LBL_POWEREDBY="Powered by {{BRAND_NAME}}" diff --git a/src/language/en-GB/plg_system_mokowaas.ini b/src/language/en-GB/plg_system_mokowaas.ini index 9ab299c..8ba246f 100644 --- a/src/language/en-GB/plg_system_mokowaas.ini +++ b/src/language/en-GB/plg_system_mokowaas.ini @@ -55,6 +55,9 @@ PLG_SYSTEM_MOKOWAAS_ALLOWED_IPS_NOTE_DESC="Emergency access requires an IP white PLG_SYSTEM_MOKOWAAS_FIELDSET_MAINTENANCE_LABEL="Maintenance" PLG_SYSTEM_MOKOWAAS_FIELDSET_MAINTENANCE_DESC="One-time maintenance actions. Set to Yes and save to execute. Resets to No automatically after execution." +PLG_SYSTEM_MOKOWAAS_DEV_MODE_LABEL="Development Mode" +PLG_SYSTEM_MOKOWAAS_DEV_MODE_DESC="Disables all Joomla caching at runtime. Useful during development and testing. Does not modify configuration.php." + PLG_SYSTEM_MOKOWAAS_RESET_HITS_LABEL="Reset All Hits" PLG_SYSTEM_MOKOWAAS_RESET_HITS_DESC="Set all article hit counters to zero across the site. This action executes on save and resets to No." PLG_SYSTEM_MOKOWAAS_DELETE_VERSIONS_LABEL="Delete All Versions" @@ -74,6 +77,8 @@ PLG_SYSTEM_MOKOWAAS_COLOR_HEADER_LABEL="Header Color" PLG_SYSTEM_MOKOWAAS_COLOR_HEADER_DESC="Background color for the admin top header bar." PLG_SYSTEM_MOKOWAAS_COLOR_LINK_LABEL="Link Color" PLG_SYSTEM_MOKOWAAS_COLOR_LINK_DESC="Color for hyperlinks in the admin interface." +PLG_SYSTEM_MOKOWAAS_BRAND_ICON_LABEL="Brand Icon (FontAwesome)" +PLG_SYSTEM_MOKOWAAS_BRAND_ICON_DESC="FontAwesome unicode codepoint for the brand icon that replaces the Joomla logo icon. Enter the hex code only (e.g. f6d5 for fa-hat-cowboy). Find codes at fontawesome.com/icons." PLG_SYSTEM_MOKOWAAS_CUSTOM_CSS_LABEL="Custom CSS" PLG_SYSTEM_MOKOWAAS_CUSTOM_CSS_DESC="Additional CSS injected into admin pages. Use for fine-tuning visual presentation." diff --git a/src/language/en-US/plg_system_mokowaas.ini b/src/language/en-US/plg_system_mokowaas.ini index 9ab299c..8ba246f 100644 --- a/src/language/en-US/plg_system_mokowaas.ini +++ b/src/language/en-US/plg_system_mokowaas.ini @@ -55,6 +55,9 @@ PLG_SYSTEM_MOKOWAAS_ALLOWED_IPS_NOTE_DESC="Emergency access requires an IP white PLG_SYSTEM_MOKOWAAS_FIELDSET_MAINTENANCE_LABEL="Maintenance" PLG_SYSTEM_MOKOWAAS_FIELDSET_MAINTENANCE_DESC="One-time maintenance actions. Set to Yes and save to execute. Resets to No automatically after execution." +PLG_SYSTEM_MOKOWAAS_DEV_MODE_LABEL="Development Mode" +PLG_SYSTEM_MOKOWAAS_DEV_MODE_DESC="Disables all Joomla caching at runtime. Useful during development and testing. Does not modify configuration.php." + PLG_SYSTEM_MOKOWAAS_RESET_HITS_LABEL="Reset All Hits" PLG_SYSTEM_MOKOWAAS_RESET_HITS_DESC="Set all article hit counters to zero across the site. This action executes on save and resets to No." PLG_SYSTEM_MOKOWAAS_DELETE_VERSIONS_LABEL="Delete All Versions" @@ -74,6 +77,8 @@ PLG_SYSTEM_MOKOWAAS_COLOR_HEADER_LABEL="Header Color" PLG_SYSTEM_MOKOWAAS_COLOR_HEADER_DESC="Background color for the admin top header bar." PLG_SYSTEM_MOKOWAAS_COLOR_LINK_LABEL="Link Color" PLG_SYSTEM_MOKOWAAS_COLOR_LINK_DESC="Color for hyperlinks in the admin interface." +PLG_SYSTEM_MOKOWAAS_BRAND_ICON_LABEL="Brand Icon (FontAwesome)" +PLG_SYSTEM_MOKOWAAS_BRAND_ICON_DESC="FontAwesome unicode codepoint for the brand icon that replaces the Joomla logo icon. Enter the hex code only (e.g. f6d5 for fa-hat-cowboy). Find codes at fontawesome.com/icons." PLG_SYSTEM_MOKOWAAS_CUSTOM_CSS_LABEL="Custom CSS" PLG_SYSTEM_MOKOWAAS_CUSTOM_CSS_DESC="Additional CSS injected into admin pages. Use for fine-tuning visual presentation." diff --git a/src/language/overrides/en-GB.override.ini b/src/language/overrides/en-GB.override.ini index 2e5381d..d773e7b 100644 --- a/src/language/overrides/en-GB.override.ini +++ b/src/language/overrides/en-GB.override.ini @@ -53,3 +53,14 @@ JLIB_APPLICATION_ERROR_COMPONENT_NOT_FOUND="Component not found." ; ===== Version and About ===== JLIB_HTML_POWERED_BY="Powered by {{BRAND_NAME}}" + +; ===== Akeeba Ticket System (ATS) ===== +COM_ATS="{{BRAND_NAME}} Tickets" +COM_ATS_TITLE_TICKETS="{{BRAND_NAME}} Tickets" +COM_ATS_TITLE_TICKET="{{BRAND_NAME}} Ticket" +COM_ATS_TITLE_NEWTICKET="New {{BRAND_NAME}} Ticket" +COM_ATS_TITLE_CATEGORIES="Ticket Categories" +COM_ATS_MSG_TICKET_SAVED="Your {{BRAND_NAME}} ticket has been saved." +COM_ATS_MSG_TICKET_CLOSED="Your {{BRAND_NAME}} ticket has been closed." +COM_ATS_MSG_REPLY_SAVED="Your reply has been saved." +COM_ATS_LBL_POWEREDBY="Powered by {{BRAND_NAME}}" diff --git a/src/language/overrides/en-US.override.ini b/src/language/overrides/en-US.override.ini index d015444..a23405e 100644 --- a/src/language/overrides/en-US.override.ini +++ b/src/language/overrides/en-US.override.ini @@ -53,3 +53,14 @@ JLIB_APPLICATION_ERROR_COMPONENT_NOT_FOUND="Component not found." ; ===== Version and About ===== JLIB_HTML_POWERED_BY="Powered by {{BRAND_NAME}}" + +; ===== Akeeba Ticket System (ATS) ===== +COM_ATS="{{BRAND_NAME}} Tickets" +COM_ATS_TITLE_TICKETS="{{BRAND_NAME}} Tickets" +COM_ATS_TITLE_TICKET="{{BRAND_NAME}} Ticket" +COM_ATS_TITLE_NEWTICKET="New {{BRAND_NAME}} Ticket" +COM_ATS_TITLE_CATEGORIES="Ticket Categories" +COM_ATS_MSG_TICKET_SAVED="Your {{BRAND_NAME}} ticket has been saved." +COM_ATS_MSG_TICKET_CLOSED="Your {{BRAND_NAME}} ticket has been closed." +COM_ATS_MSG_REPLY_SAVED="Your reply has been saved." +COM_ATS_LBL_POWEREDBY="Powered by {{BRAND_NAME}}" diff --git a/src/mokowaas.xml b/src/mokowaas.xml index 65aceec..784927b 100644 --- a/src/mokowaas.xml +++ b/src/mokowaas.xml @@ -162,6 +162,13 @@ label="PLG_SYSTEM_MOKOWAAS_FIELDSET_MAINTENANCE_LABEL" description="PLG_SYSTEM_MOKOWAAS_FIELDSET_MAINTENANCE_DESC" > + + + + + getQuery(true) - ->select([$db->quoteName('extension_id'), $db->quoteName('enabled')]) + ->select($db->quoteName('extension_id')) ->from($db->quoteName('#__extensions')) ->where($db->quoteName('element') . ' = ' . $db->quote('mokoonyx')) ->where($db->quoteName('type') . ' = ' . $db->quote('template')); $onyx = $db->setQuery($query)->loadObject(); + // Install from payload if missing + if (!$onyx) + { + $this->installMokoOnyxFromPayload(); + + // Re-check after install + $onyx = $db->setQuery($query)->loadObject(); + } + if ($onyx) { // Lock and protect MokoOnyx @@ -245,73 +254,49 @@ class plgSystemMokoWaaSInstallerScript implements InstallerScriptInterface )->execute(); $this->setDefaultTemplate('mokoonyx', 0); - - // Unlock MokoCassiopeia if present (allow uninstall) - $db->setQuery( - $db->getQuery(true) - ->update($db->quoteName('#__extensions')) - ->set($db->quoteName('locked') . ' = 0') - ->set($db->quoteName('protected') . ' = 0') - ->where($db->quoteName('element') . ' = ' . $db->quote('mokocassiopeia')) - ->where($db->quoteName('type') . ' = ' . $db->quote('template')) - )->execute(); - - return; } - // Fallback: MokoCassiopeia - $query = $db->getQuery(true) - ->select([$db->quoteName('extension_id'), $db->quoteName('enabled')]) - ->from($db->quoteName('#__extensions')) - ->where($db->quoteName('element') . ' = ' . $db->quote('mokocassiopeia')) - ->where($db->quoteName('type') . ' = ' . $db->quote('template')); - $template = $db->setQuery($query)->loadObject(); + // Always unlock MokoCassiopeia (allow uninstall) + $db->setQuery( + $db->getQuery(true) + ->update($db->quoteName('#__extensions')) + ->set($db->quoteName('locked') . ' = 0') + ->set($db->quoteName('protected') . ' = 0') + ->where($db->quoteName('element') . ' = ' . $db->quote('mokocassiopeia')) + ->where($db->quoteName('type') . ' = ' . $db->quote('template')) + )->execute(); + } - if ($template) - { - // Lock, protect, and set as default - $db->setQuery( - $db->getQuery(true) - ->update($db->quoteName('#__extensions')) - ->set($db->quoteName('enabled') . ' = 1') - ->set($db->quoteName('locked') . ' = 1') - ->set($db->quoteName('protected') . ' = 1') - ->where($db->quoteName('extension_id') . ' = ' - . (int) $template->extension_id) - ); - $db->execute(); - - $this->setDefaultTemplate('mokocassiopeia', 0); - - return; - } - - // Template not installed — install from bundled payload + /** + * Install MokoOnyx from the bundled payload zip. + * + * @return void + * + * @since 02.01.17 + */ + private function installMokoOnyxFromPayload() + { $pluginPath = JPATH_PLUGINS . '/system/mokowaas'; - $payloadZip = $pluginPath . '/payload/mokocassiopeia.zip'; + $payloadZip = $pluginPath . '/payload/mokoonyx.zip'; if (!file_exists($payloadZip)) { Factory::getApplication()->enqueueMessage( - 'MokoCassiopeia payload not found at ' - . $payloadZip, + 'MokoOnyx payload not found. Please install MokoOnyx manually from ' + . 'Gitea Releases.', 'warning' ); return; } - $tmpDir = JPATH_ROOT . '/tmp/mokocassiopeia'; + $tmpDir = JPATH_ROOT . '/tmp/mokoonyx'; try { - - // Extract the bundled zip $archive = new \Joomla\Archive\Archive(); $archive->extract($payloadZip, $tmpDir); - // Release zips should have templateDetails.xml at root - // or one level deep $installDir = $tmpDir; if (!file_exists($tmpDir . '/templateDetails.xml')) @@ -325,8 +310,7 @@ class plgSystemMokoWaaSInstallerScript implements InstallerScriptInterface else { Factory::getApplication()->enqueueMessage( - 'MokoCassiopeia: templateDetails.xml not ' - . 'found in archive.', + 'MokoOnyx: templateDetails.xml not found in archive.', 'warning' ); @@ -338,17 +322,15 @@ class plgSystemMokoWaaSInstallerScript implements InstallerScriptInterface if ($installer->install($installDir)) { - $this->ensureMokoCassiopeia(); - Factory::getApplication()->enqueueMessage( - 'MokoCassiopeia installed and locked.', + 'MokoOnyx installed successfully.', 'message' ); } else { Factory::getApplication()->enqueueMessage( - 'MokoCassiopeia installation failed.', + 'MokoOnyx installation from payload failed.', 'warning' ); } @@ -356,7 +338,7 @@ class plgSystemMokoWaaSInstallerScript implements InstallerScriptInterface catch (\Exception $e) { Factory::getApplication()->enqueueMessage( - 'MokoCassiopeia error: ' . $e->getMessage(), + 'MokoOnyx error: ' . $e->getMessage(), 'warning' ); } diff --git a/updates.xml b/updates.xml index b1dce64..ab97bcd 100644 --- a/updates.xml +++ b/updates.xml @@ -11,7 +11,7 @@ System - MokoWaaS (development) mokowaas plugin - 02.01.15-dev + 02.01.20-dev site system @@ -19,10 +19,9 @@ https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS - https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases/download/development/mokowaas-02.01.15-dev.zip - https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases/download/development/mokowaas-02.01.15-dev.tar.gz + https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases/download/development/mokowaas-02.01.20-dev.zip - 7fcd567f42dcdfee58aeb6fc82f904e1cd970be6ba2fae3690d279d7e48737ed + edb7ccb285d9d5889a559c55b85e2555006c0b41040ddf0f8a4dd34f1ca0f14b Moko Consulting https://mokoconsulting.tech