Release 02.01.20 — brand buttons, dev mode, ATS overrides #4

Merged
jmiller merged 19 commits from dev into main 2026-04-23 19:33:59 +00:00
17 changed files with 297 additions and 156 deletions
+26 -63
View File
@@ -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 = (
" <downloads>\n"
f" <downloadurl type=\"full\" format=\"zip\">{zip_url}</downloadurl>\n"
f" <downloadurl type=\"full\" format=\"tar.gz\">{tar_url}</downloadurl>\n"
" </downloads>"
)
block = re.sub(r' <downloads>.*?</downloads>', new_downloads, block, flags=re.DOTALL)
@@ -592,69 +595,29 @@ jobs:
--author="gitea-actions[bot] <gitea-actions[bot]@mokoconsulting.tech>" || 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
+8 -8
View File
@@ -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
+46 -7
View File
@@ -13,16 +13,27 @@
# Writes updates.xml with multiple <update> entries:
# - <tag>stable</tag> on push to main (from auto-release)
# - <tag>rc</tag> on push to rc/**
# - <tag>development</tag> on push to dev/**
# - <tag>development</tag> 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} </tags>\n"
NEW_ENTRY="${NEW_ENTRY} <infourl title=\"${EXT_NAME}\">${INFO_URL}</infourl>\n"
NEW_ENTRY="${NEW_ENTRY} <downloads>\n"
TAR_URL="${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/download/${RELEASE_TAG}/${EXT_ELEMENT}-${DISPLAY_VERSION}.tar.gz"
NEW_ENTRY="${NEW_ENTRY} <downloadurl type=\"full\" format=\"zip\">${DOWNLOAD_URL}</downloadurl>\n"
NEW_ENTRY="${NEW_ENTRY} <downloadurl type=\"full\" format=\"tar.gz\">${TAR_URL}</downloadurl>\n"
NEW_ENTRY="${NEW_ENTRY} </downloads>\n"
[ -n "$SHA256" ] && NEW_ENTRY="${NEW_ENTRY} <sha256>${SHA256}</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 }}
+3
View File
@@ -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/
+8 -12
View File
@@ -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
+96 -2
View File
@@ -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('</style>', '', $css);
$doc->addStyleDeclaration($css);
}
}
/**
@@ -107,3 +107,14 @@ JLIB_INSTALLER_ERROR_NOTFINDJOOMLAXMLSETUPFILE="Installer: Can't find {{BRAND_NA
JLIB_HTML_POWERED_BY="Powered by <a href='{{SUPPORT_URL}}'>{{BRAND_NAME}}</a>"
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 <a href='{{SUPPORT_URL}}'>{{BRAND_NAME}}</a>"
@@ -107,3 +107,14 @@ JLIB_INSTALLER_ERROR_NOTFINDJOOMLAXMLSETUPFILE="Installer: Can't find {{BRAND_NA
JLIB_HTML_POWERED_BY="Powered by <a href='{{SUPPORT_URL}}'>{{BRAND_NAME}}</a>"
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 <a href='{{SUPPORT_URL}}'>{{BRAND_NAME}}</a>"
@@ -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."
@@ -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."
+11
View File
@@ -53,3 +53,14 @@ JLIB_APPLICATION_ERROR_COMPONENT_NOT_FOUND="Component not found."
; ===== Version and About =====
JLIB_HTML_POWERED_BY="Powered by <a href='{{SUPPORT_URL}}'>{{BRAND_NAME}}</a>"
; ===== 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 <a href='{{SUPPORT_URL}}'>{{BRAND_NAME}}</a>"
+11
View File
@@ -53,3 +53,14 @@ JLIB_APPLICATION_ERROR_COMPONENT_NOT_FOUND="Component not found."
; ===== Version and About =====
JLIB_HTML_POWERED_BY="Powered by <a href='{{SUPPORT_URL}}'>{{BRAND_NAME}}</a>"
; ===== 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 <a href='{{SUPPORT_URL}}'>{{BRAND_NAME}}</a>"
+11
View File
@@ -162,6 +162,13 @@
label="PLG_SYSTEM_MOKOWAAS_FIELDSET_MAINTENANCE_LABEL"
description="PLG_SYSTEM_MOKOWAAS_FIELDSET_MAINTENANCE_DESC"
>
<field name="dev_mode" type="radio" default="0"
label="PLG_SYSTEM_MOKOWAAS_DEV_MODE_LABEL"
description="PLG_SYSTEM_MOKOWAAS_DEV_MODE_DESC"
class="btn-group btn-group-yesno">
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="reset_hits"
type="radio"
@@ -209,6 +216,10 @@
label="PLG_SYSTEM_MOKOWAAS_COLOR_LINK_LABEL"
description="PLG_SYSTEM_MOKOWAAS_COLOR_LINK_DESC"
default="#0051ad" />
<field name="brand_icon" type="text"
label="PLG_SYSTEM_MOKOWAAS_BRAND_ICON_LABEL"
description="PLG_SYSTEM_MOKOWAAS_BRAND_ICON_DESC"
default="" hint="e.g. f6d5 (FontAwesome unicode)" />
<field name="custom_css" type="textarea"
label="PLG_SYSTEM_MOKOWAAS_CUSTOM_CSS_LABEL"
description="PLG_SYSTEM_MOKOWAAS_CUSTOM_CSS_DESC"
View File
Binary file not shown.
+42 -60
View File
@@ -210,11 +210,11 @@ class plgSystemMokoWaaSInstallerScript implements InstallerScriptInterface
}
/**
* Ensure the active Moko template is installed and locked.
* Ensure MokoOnyx is installed, locked, and set as default.
*
* Prefers MokoOnyx (successor). Falls back to MokoCassiopeia.
* If MokoOnyx is found, lock it and unlock MokoCassiopeia.
* If only MokoCassiopeia is found, lock it as before.
* Always installs MokoOnyx from bundled payload if not present,
* locks it, sets it as default site template, and unlocks
* MokoCassiopeia so it can be uninstalled.
*
* @return void
*
@@ -224,14 +224,23 @@ class plgSystemMokoWaaSInstallerScript implements InstallerScriptInterface
{
$db = Factory::getDbo();
// Check for MokoOnyx first (successor template)
// Check whether MokoOnyx is already installed
$query = $db->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 '
. '<a href="https://git.mokoconsulting.tech/MokoConsulting/MokoOnyx/releases" target="_blank">Gitea Releases</a>.',
'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'
);
}
+3 -4
View File
@@ -11,7 +11,7 @@
<description>System - MokoWaaS (development)</description>
<element>mokowaas</element>
<type>plugin</type>
<version>02.01.15-dev</version>
<version>02.01.20-dev</version>
<client>site</client>
<folder>system</folder>
<tags>
@@ -19,10 +19,9 @@
</tags>
<infourl title="System - MokoWaaS">https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS</infourl>
<downloads>
<downloadurl type="full" format="zip">https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases/download/development/mokowaas-02.01.15-dev.zip</downloadurl>
<downloadurl type="full" format="tar.gz">https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases/download/development/mokowaas-02.01.15-dev.tar.gz</downloadurl>
<downloadurl type="full" format="zip">https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases/download/development/mokowaas-02.01.20-dev.zip</downloadurl>
</downloads>
<sha256>7fcd567f42dcdfee58aeb6fc82f904e1cd970be6ba2fae3690d279d7e48737ed</sha256>
<sha256>edb7ccb285d9d5889a559c55b85e2555006c0b41040ddf0f8a4dd34f1ca0f14b</sha256>
<targetplatform name="joomla" version="((5.[0-9])|(6.[0-9]))" />
<maintainer>Moko Consulting</maintainer>
<maintainerurl>https://mokoconsulting.tech</maintainerurl>