433 Commits

Author SHA1 Message Date
gitea-actions[bot] bf9c94bbf8 chore(version): pre-release bump to 02.48.24-dev [skip ci] 2026-06-25 19:45:58 +00:00
gitea-actions[bot] 19d4b63ca6 chore(version): pre-release bump to 02.48.23-dev [skip ci] 2026-06-25 17:47:17 +00:00
gitea-actions[bot] 95e0ff04a4 chore(version): pre-release bump to 02.48.22-dev [skip ci] 2026-06-25 17:47:03 +00:00
gitea-actions[bot] 57748a2a23 chore(version): auto-bump patch 02.48.21-dev [skip ci] 2026-06-25 17:46:55 +00:00
jmiller 3f4f2f2d43 feat: auto-enrich IPs with country flags across all admin pages
Universal: Auto Version Bump / Version Bump (push) Successful in 7s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 15s
DB-IP plugin onAfterRender scans admin HTML for IP addresses in
<code> tags, looks up geolocation, prepends country flag emoji and
adds city/region/country hover tooltip. Caches lookups per request,
skips private/loopback IPs and already-enriched elements.
2026-06-25 12:46:42 -05:00
gitea-actions[bot] 7ac776ff28 chore(version): pre-release bump to 02.48.20-dev [skip ci] 2026-06-25 17:43:34 +00:00
gitea-actions[bot] 89b71a5a65 chore(version): pre-release bump to 02.48.19-dev [skip ci] 2026-06-25 17:39:16 +00:00
gitea-actions[bot] 0b3eb7c7aa chore(version): pre-release bump to 02.48.18-dev [skip ci] 2026-06-25 17:38:56 +00:00
gitea-actions[bot] 4b809778f4 chore(version): auto-bump patch 02.48.17-dev [skip ci] 2026-06-25 17:38:43 +00:00
jmiller 7ab1fe4cdd fix: PIN copy revert timeout changed to 5 seconds
Universal: Auto Version Bump / Version Bump (push) Successful in 11s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 22s
2026-06-25 12:38:25 -05:00
gitea-actions[bot] 21bdd9a8a2 chore(version): pre-release bump to 02.48.16-dev [skip ci] 2026-06-25 17:23:58 +00:00
gitea-actions[bot] 2124a550a2 chore(version): pre-release bump to 02.48.15-dev [skip ci] 2026-06-25 17:23:42 +00:00
gitea-actions[bot] 882e7ae675 chore(version): auto-bump patch 02.48.14-dev [skip ci] 2026-06-25 17:23:33 +00:00
jmiller 5249edf54a feat: add MokoSuiteBackup quick action button on dashboard
Universal: Auto Version Bump / Version Bump (push) Successful in 8s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 15s
Shows when com_mokosuitebackup is installed, links directly to
the backup component.
2026-06-25 12:23:22 -05:00
gitea-actions[bot] 2c4363b391 chore(version): pre-release bump to 02.48.13-dev [skip ci] 2026-06-25 17:09:28 +00:00
gitea-actions[bot] 00f385c129 chore(version): pre-release bump to 02.48.12-dev [skip ci] 2026-06-25 17:09:06 +00:00
gitea-actions[bot] cc1d4a5fd5 chore(version): auto-bump patch 02.48.11-dev [skip ci] 2026-06-25 17:08:55 +00:00
jmiller 0b59dadb67 fix: PIN copy revert uses data-pin instead of captured text
Universal: Auto Version Bump / Version Bump (push) Successful in 8s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 17s
Clicking while showing "Copied!" captured "Copied!" as the revert
value, so the PIN text never returned. Now uses the stable data-pin
attribute as the revert source.
2026-06-25 12:08:43 -05:00
gitea-actions[bot] 4394788460 chore(version): pre-release bump to 02.48.10-dev [skip ci] 2026-06-25 17:04:36 +00:00
gitea-actions[bot] f51c2ae3dc chore(version): auto-bump patch 02.48.09-dev [skip ci] 2026-06-25 17:04:26 +00:00
jmiller 27f7e5299a fix: remove ci-platform.yml (mokocli self-test, not for Joomla repos)
Universal: Auto Version Bump / Version Bump (push) Successful in 8s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 15s
2026-06-25 17:04:17 +00:00
gitea-actions[bot] 51f9fd4aee chore(version): pre-release bump to 02.48.08-dev [skip ci] 2026-06-25 16:49:23 +00:00
gitea-actions[bot] 877be22900 chore(version): pre-release bump to 02.48.07-dev [skip ci] 2026-06-25 16:48:54 +00:00
gitea-actions[bot] 6e435a5f5a chore(version): auto-bump patch 02.48.06-dev [skip ci] 2026-06-25 16:48:41 +00:00
jmiller 9de56e605a fix: prevent duplicate PIN copy handlers from multiple modules
Universal: Auto Version Bump / Version Bump (push) Successful in 9s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 49s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 28s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
- Guard with window._mokoPinBound and data-bound to prevent
  multi-module pages from attaching N click handlers per badge
- Extract bindCopy() for reuse after request-then-copy flow
- Ensure title="Click to copy" tooltip on all PIN elements
2026-06-25 11:48:10 -05:00
gitea-actions[bot] 4276f95fb6 chore(version): pre-release bump to 02.48.05-dev [skip ci] 2026-06-25 16:47:23 +00:00
gitea-actions[bot] cd62da8f0e chore(version): pre-release bump to 02.48.04-dev [skip ci] 2026-06-25 16:46:40 +00:00
gitea-actions[bot] ac055f8f21 chore(version): auto-bump patch 02.48.03-dev [skip ci] 2026-06-25 16:46:31 +00:00
jmiller 5811dac4aa fix: PIN copy shows inline Copied! feedback for 30 seconds
Universal: Auto Version Bump / Version Bump (push) Successful in 8s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 16s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 31s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
- Wrap PIN text in .mokosuiteclient-pin-text span for all badge contexts
- Change revert timeout from 1.5s to 30s so PIN is readable during support calls
- Fix post-request badge rebuild to include text span for copy feedback
2026-06-25 11:46:17 -05:00
gitea-actions[bot] c4391e50a3 chore(version): pre-release bump to 02.48.02-dev [skip ci] 2026-06-25 16:40:36 +00:00
gitea-actions[bot] 3446c01786 chore(version): pre-release bump to 02.48.01-dev [skip ci] 2026-06-25 16:39:41 +00:00
gitea-actions[bot] cc8c720185 chore(version): auto-bump patch 02.48.00-dev [skip ci] 2026-06-25 16:39:31 +00:00
jmiller cfa605f36a fix: fetchLocalHealth accepts degraded health responses (non-200)
Universal: Auto Version Bump / Version Bump (push) Successful in 7s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 17s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 51s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Heartbeat was not sending health/backup data to HQ because
fetchLocalHealth rejected 503 responses from degraded sites.
2026-06-25 11:39:18 -05:00
gitea-actions[bot] af55244b65 chore(version): pre-release bump to 02.47.99-dev [skip ci] 2026-06-25 16:34:59 +00:00
gitea-actions[bot] 31fb9ab725 chore(version): auto-bump patch 02.47.98-dev [skip ci] 2026-06-25 16:34:44 +00:00
jmiller 4e6edeef85 refactor: unify PIN UI into SupportPinHelper renderBadge/renderScript
Universal: Auto Version Bump / Version Bump (push) Successful in 9s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 29s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 47s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Replaces 3 separate inline PIN implementations (dashboard, cpanel
module, cache module) with shared helper methods. Adds click-to-copy
on all PIN badges.
2026-06-25 11:34:32 -05:00
gitea-actions[bot] b426d40dc9 chore(version): pre-release bump to 02.47.97-dev [skip ci] 2026-06-25 16:27:11 +00:00
jmiller 79da4b2d8f Merge pull request 'fix: add SQL update file to match manifest version' (#266) from fix/schema-version-file into dev
Universal: Auto Version Bump / Version Bump (push) Has been skipped
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 47s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 29s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
fix: add SQL update file to match manifest version
2026-06-25 16:26:34 +00:00
gitea-actions[bot] 63b6a879f1 chore(version): pre-release bump to 02.47.96-dev [skip ci]
Branch Cleanup / Delete merged branch (pull_request) Successful in 2s
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
2026-06-25 16:25:18 +00:00
jmiller c2c5258220 fix: add SQL update file to match manifest version
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 29s
Joomla's Database view requires a SQL update file matching the manifest
version. Missing file causes persistent schema version mismatch warning.
2026-06-25 11:24:51 -05:00
gitea-actions[bot] 800a39a66f chore(version): pre-release bump to 02.47.95-dev [skip ci] 2026-06-25 16:15:36 +00:00
gitea-actions[bot] 4bb861cd06 chore(version): pre-release bump to 02.47.94-dev [skip ci] 2026-06-25 16:14:36 +00:00
gitea-actions[bot] 4d125bbd63 chore(version): auto-bump patch 02.47.93-dev [skip ci] 2026-06-25 16:14:20 +00:00
jmiller dbab14dda7 fix: health endpoint cron check SQL error producing bare LIMIT 5
Universal: Auto Version Bump / Version Bump (push) Successful in 16s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 25s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 1m37s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
2026-06-25 11:13:35 -05:00
gitea-actions[bot] 759398d70e chore(version): pre-release bump to 02.47.92-dev [skip ci] 2026-06-25 15:25:46 +00:00
gitea-actions[bot] 61170edf55 chore(version): auto-bump patch 02.47.91-dev [skip ci] 2026-06-25 15:25:36 +00:00
jmiller 81a95e6e23 feat: HQ config sync, menu language fix, catalog cleanup
Universal: Auto Version Bump / Version Bump (push) Successful in 9s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 25s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 54s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Client stores HQ-configured support_pin_hours from heartbeat response.
PIN TTL now configurable from HQ instead of hardcoded 72h. Admin sidebar
menu loads component-local language files fixing untranslated keys for
MokoSuiteCross. Removed MokoSuiteHQ from extension catalog.
2026-06-25 10:25:20 -05:00
gitea-actions[bot] 4b21c43e56 chore(version): pre-release bump to 02.47.90-dev [skip ci] 2026-06-25 14:49:32 +00:00
gitea-actions[bot] f683e27183 chore(version): auto-bump patch 02.47.89-dev [skip ci] 2026-06-25 14:49:23 +00:00
jmiller d1b18340ea fix: flush PSR-4 autoload cache after install for Joomla 6 compat
Universal: Auto Version Bump / Version Bump (push) Successful in 10s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 15s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 48s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Joomla 6 replaced the namespace column with a file-based autoload
cache. Package installs can regenerate it before all sub-extensions
are extracted, causing class-not-found errors (e.g. DB-IP plugin).
Deleting the cache in postflight forces a clean rebuild.
2026-06-25 09:49:10 -05:00
gitea-actions[bot] 76601cec37 chore(version): pre-release bump to 02.47.88-dev [skip ci] 2026-06-25 13:31:54 +00:00
gitea-actions[bot] 9106b1a4ae chore(version): auto-bump patch 02.47.87-dev [skip ci] 2026-06-25 13:31:43 +00:00
jmiller e563d08543 feat: SupportPinHelper, 4-button status bar, help buttons, PIN in heartbeat
Universal: Auto Version Bump / Version Bump (push) Successful in 10s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 24s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 39s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
- Add shared SupportPinHelper for consistent PIN generation across
  dashboard, cpanel module, cache module, and AJAX controller
- Cache module status bar now has 4 buttons: Site (frontend link),
  Support PIN, Clear Cache, Clear Temp
- Add ToolbarHelper::help() to all 10 admin views pointing to
  Gitea wiki pages
- Include support PIN in heartbeat payload to MokoSuiteHQ
- Fix license plugin missing src/ and language/ directories
- Refactor dashboard and cpanel module to use SupportPinHelper
2026-06-25 08:31:21 -05:00
gitea-actions[bot] 88377b101a chore(version): pre-release bump to 02.47.86-dev [skip ci] 2026-06-24 12:15:20 +00:00
gitea-actions[bot] 2a594e26b1 chore(version): pre-release bump to 02.47.85-dev [skip ci] 2026-06-23 23:48:48 +00:00
gitea-actions[bot] 8f5324e6a9 chore(version): auto-bump patch 02.47.84-dev [skip ci] 2026-06-23 23:48:33 +00:00
Jonathan Miller 053acbcdc3 fix: remove orphaned array fragments from sed deletion of service calls
Universal: Auto Version Bump / Version Bump (push) Successful in 14s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 23s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 41s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
The sed -i removal of AutomationEngine::fire() and
NotificationService::securityAlert() left dangling array elements
in onUserAfterSave, onContentAfterSave, onUserAfterLogin, and
onUserLoginFailure causing PHP parse errors on suite.dev.
2026-06-23 18:48:14 -05:00
gitea-actions[bot] a35316e041 chore(version): pre-release bump to 02.47.83-dev [skip ci] 2026-06-23 22:58:09 +00:00
gitea-actions[bot] d9a37d6783 chore(version): auto-bump patch 02.47.82-dev [skip ci] 2026-06-23 22:57:58 +00:00
Jonathan Miller ee63f49657 fix: restore backup bridge, DB-IP, license plugins to package
Universal: Auto Version Bump / Version Bump (push) Successful in 14s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 26s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 16s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
- Added plg_system_mokosuiteclient_backup, _dbip, _license to
  pkg_mokosuiteclient.xml (were missing from package manifest)
- Install script enables backup + license plugins on install
- Dashboard PLUGIN_META includes all three with icons/descriptions
2026-06-23 17:57:40 -05:00
gitea-actions[bot] 9b0f67a43a chore(version): pre-release bump to 02.47.81-dev [skip ci] 2026-06-23 22:32:57 +00:00
gitea-actions[bot] 96fe631e61 chore(version): auto-bump patch 02.47.80-dev [skip ci] 2026-06-23 22:32:12 +00:00
Jonathan Miller 35a3d40c6a fix: address all 9 PR review findings
Universal: Auto Version Bump / Version Bump (push) Successful in 1m0s
Generic: Project CI / Lint & Validate (pull_request) Failing after 24s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 50s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 8s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 9s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 55s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 11s
Universal: PR Check / Validate PR (pull_request) Failing after 10s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 2s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 50s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 54s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
1. Sourcerer: expanded forbidden function blocklist (+12 functions),
   added backtick, variable function, and string concat detection
2. Removed orphaned ticket API routes from webservices plugin
3. Removed orphaned tickets submenu from component manifest
4. Added mokosuiteclient.htaccess ACL action to access.xml + language
5. Removed dead AutomationEngine/NotificationService calls from plugin
6. SSL verify enabled in ExtensionsModel (install + update fetch)
7. ConditionsHelper: escape # delimiter in URL regex patterns
8. ReReplacer: escape / delimiter in user-supplied regex patterns
9. CLAUDE.md: removed ticket references, added content tools
2026-06-23 17:31:09 -05:00
gitea-actions[bot] 51185b548f chore(version): pre-release bump to 02.47.79-dev [skip ci] 2026-06-23 22:10:14 +00:00
gitea-actions[bot] 4d534c724d chore(version): auto-bump patch 02.47.78-dev [skip ci] 2026-06-23 22:09:56 +00:00
Jonathan Miller 333966416b feat: support PIN on-demand with 72-hour TTL + controller cleanup
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 5s
Generic: Project CI / Lint & Validate (pull_request) Successful in 10s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 13s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 1s
Universal: Auto Version Bump / Version Bump (push) Successful in 15s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 41s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 23s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 51s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 1m1s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 1m2s
Generic: Project CI / Tests (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
- PIN hidden by default — "Request PIN" button generates on click
- PIN valid for 72 hours (stored as support_pin_requested_at in params)
- HMAC uses 72h window instead of daily date for stability
- requestPin() AJAX endpoint in controller stores timestamp + returns PIN
- Applied to both dashboard info bar and cpanel module
- Dashboard JS handles PIN request with badge replacement
- Cpanel JS handles same with inline script
- Fixed orphaned ticket code fragments in controller (syntax error)
- Removed duplicate maintenance section
2026-06-23 17:09:36 -05:00
gitea-actions[bot] 8f3d3cea8b chore(version): pre-release bump to 02.47.77-dev [skip ci] 2026-06-23 19:32:02 +00:00
gitea-actions[bot] 44664426f5 chore(version): auto-bump patch 02.47.76-dev [skip ci] 2026-06-23 19:31:37 +00:00
Jonathan Miller 37721cd061 feat: full extension catalog + channel gating by domain
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 9s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 8s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: Auto Version Bump / Version Bump (push) Successful in 22s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 18s
Generic: Project CI / Lint & Validate (pull_request) Failing after 39s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 44s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 48s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 35s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 1m11s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
- catalog.xml: all 21 MokoSuite repos listed with proper categories
  (Platform, Business, Industry, Content, SEO, Modules, Templates)
- Update server URLs point to main branch (stable releases)
- Dev channel only available on *.mokoconsulting.tech domains
- Non-Moko domains forced to stable regardless of Joomla config
- ExtensionsModel respects Joomla's com_installer update_channel
  param on Moko domains, skips dev-tagged versions on stable channel
2026-06-23 14:31:07 -05:00
gitea-actions[bot] ef6052006e chore(version): pre-release bump to 02.47.75-dev [skip ci] 2026-06-23 19:27:44 +00:00
gitea-actions[bot] 19b3b33d70 chore(version): auto-bump patch 02.47.74-dev [skip ci] 2026-06-23 19:27:16 +00:00
Jonathan Miller 0a374ac8d5 feat: fuzzy detection of all MokoSuite/MokoJoom ecosystem packages
Universal: PR Check / Branch Policy (pull_request) Successful in 3s
Generic: Repo Health / Access control (pull_request) Successful in 3s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: PR Check / Validate PR (pull_request) Failing after 9s
Generic: Project CI / Lint & Validate (pull_request) Failing after 17s
Universal: Auto Version Bump / Version Bump (push) Successful in 22s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 19s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 44s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 47s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 27s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
- DashboardModel.getMokoExtensions() now fuzzy-matches mokosuite*,
  mokosuiteclient*, mokosuitehq*, mokosuitecrm*, mokojoom* across
  packages, components, modules, plugins, and libraries
- Each extension tagged with product family for grouping
- Heartbeat payload includes moko_packages map (element → version)
  so HQ can see all installed MokoSuite products per site
- Menu module already catches com_moko% (no change needed)
2026-06-23 14:26:52 -05:00
gitea-actions[bot] 32e76ecc75 chore(version): pre-release bump to 02.47.73-dev [skip ci] 2026-06-23 19:25:32 +00:00
gitea-actions[bot] d89d0f95f6 chore(version): auto-bump patch 02.47.72-dev [skip ci] 2026-06-23 19:25:01 +00:00
Jonathan Miller 3c4fe24056 feat: enforce ACLs in dashboard WAF sections and sidebar menu
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 8s
Universal: PR Check / Validate PR (pull_request) Failing after 7s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: Auto Version Bump / Version Bump (push) Successful in 20s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 48s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 31s
Generic: Project CI / Lint & Validate (pull_request) Failing after 57s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 59s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 1m1s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 1m9s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
- Dashboard: WAF chart and Recent WAF Blocks gated behind
  mokosuiteclient.security.waflog ACL
- Menu: all items ACL-gated, added Snippets/Templates/Replacements/
  Conditions entries, removed ticket items, super admins bypass all
2026-06-23 14:24:36 -05:00
gitea-actions[bot] abfdbbcaa2 chore(version): pre-release bump to 02.47.71-dev [skip ci] 2026-06-23 19:23:30 +00:00
gitea-actions[bot] 6e03ff7560 chore(version): auto-bump patch 02.47.70-dev [skip ci] 2026-06-23 19:22:56 +00:00
Jonathan Miller 8cc8cadda2 chore: remove all ticket/helpdesk code — migrated to MokoSuiteCRM
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 6s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 9s
Universal: PR Check / Validate PR (pull_request) Failing after 10s
Universal: Auto Version Bump / Version Bump (push) Successful in 17s
Generic: Repo Health / Access control (pull_request) Successful in 3s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 19s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 49s
Generic: Project CI / Lint & Validate (pull_request) Failing after 49s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 50s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 54s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 32s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
- Controller: removed 20+ ticket methods (createTicket, addReply,
  updateStatus, saveCategory, saveCanned, uploadAttachment, etc.)
- Controller: updated VIEW_ACL map — removed tickets/canned/categories,
  added snippets/templates/replacements/conditions
- Controller: WAF log ACL changed from core.admin to security.waflog
- Deleted: TicketsModel, AttachmentService, AutomationEngine,
  NotificationService, TicketsController (API)
- Deleted: all Ticket/Tickets/Ticketsettings/Canned views and templates
  (admin and site)
- Removed importAts method
2026-06-23 14:22:34 -05:00
gitea-actions[bot] 10ef685ab4 chore(version): pre-release bump to 02.47.69-dev [skip ci] 2026-06-23 18:35:28 +00:00
gitea-actions[bot] 79eaebf8a1 chore(version): auto-bump patch 02.47.68-dev [skip ci] 2026-06-23 18:35:01 +00:00
Jonathan Miller 50beb170e4 chore: update access.xml, config.xml, language for all new features
Universal: Auto Version Bump / Version Bump (push) Successful in 23s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 30s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 24s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 5s
Generic: Project CI / Lint & Validate (pull_request) Successful in 10s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 7s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 12s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Failing after 7s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 37s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 12s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
access.xml: removed stale ticket ACLs, added waflog, impersonate,
  snippets, templates, replacements, conditions actions
config.xml: removed helpdesk/IMAP sections (migrated to CRM), added
  content tools, impersonation settings, updated branding to MokoSuite
language: added all new ACL keys, removed ticket references
2026-06-23 13:28:27 -05:00
gitea-actions[bot] 9418e56dfe chore(version): pre-release bump to 02.47.67-dev [skip ci] 2026-06-23 18:19:04 +00:00
gitea-actions[bot] 157a8a9453 chore(version): pre-release bump to 02.47.66-dev [skip ci] 2026-06-23 18:08:32 +00:00
gitea-actions[bot] 3277ca18c9 chore(version): pre-release bump to 02.47.65-dev [skip ci] 2026-06-23 18:05:58 +00:00
jmiller 4c815e7e81 chore: remove security-audit.yml -- handled by MokoGitea
Universal: Auto Version Bump / Version Bump (push) Successful in 16s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 33s
Generic: Project CI / Lint & Validate (pull_request) Successful in 9s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 7s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 7s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 44s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 39s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 6s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Failing after 7s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 30s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
2026-06-23 18:05:14 +00:00
Jonathan Miller 60a541fec1 feat: Articles Field, Content Templater — complete Regular Labs suite
Universal: Auto Version Bump / Version Bump (push) Successful in 24s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 30s
Generic: Project CI / Lint & Validate (pull_request) Successful in 16s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 59s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 8s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 56s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 7s
Universal: PR Check / Validate PR (pull_request) Failing after 8s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 51s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 3s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 55s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
- Articles Field (#162): custom ListField type for article selection
  in any Joomla form, shows "Title [Category]" options
- Content Templater (#165): {template alias="x"} tags load pre-defined
  article templates from DB, returns introtext+fulltext from JSON
- content_templates table added to install.mysql.sql
- All Regular Labs replacements now implemented:
  #160 conditions + AMM, #161 articles anywhere, #162 articles field,
  #164 conditional content, #165 content templater, #167 email protector,
  #175 rereplacer, #176 snippets, #177 sourcerer, #180 users anywhere,
  #181 cache cleaner
2026-06-23 13:01:32 -05:00
jmiller 2702aea14a chore: remove deploy-manual.yml -- no longer needed
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 6s
Generic: Project CI / Lint & Validate (pull_request) Successful in 1m7s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 1m13s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 16s
Universal: PR Check / Validate PR (pull_request) Failing after 9s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 1m11s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 15s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 1m0s
Universal: Auto Version Bump / Version Bump (push) Successful in 17s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 31s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
2026-06-23 17:59:44 +00:00
gitea-actions[bot] 32cd96c92b chore(version): pre-release bump to 02.47.64-dev [skip ci] 2026-06-23 17:57:48 +00:00
gitea-actions[bot] da7f4578d2 chore(version): auto-bump patch 02.47.63-dev [skip ci] 2026-06-23 17:56:56 +00:00
Jonathan Miller db9c68dc5f feat: Articles Anywhere, Sourcerer, Users Anywhere tag engines
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 7s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Generic: Project CI / Lint & Validate (pull_request) Successful in 16s
Universal: Auto Version Bump / Version Bump (push) Successful in 17s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 18s
Universal: PR Check / Validate PR (pull_request) Failing after 12s
Generic: Repo Health / Access control (pull_request) Successful in 3s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 18s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 48s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 53s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 54s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 20s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
- Articles Anywhere (#161): {article id="42"}[title][introtext]{/article}
  with 18 data tags, date formatting, introtext truncation
- Sourcerer (#177): {source}<?php ... ?>{/source} with forbidden
  function blocklist, PHP execution via eval with output buffering
- Users Anywhere (#180): {user name} for current user, {user id="42"}
  [name][email]{/user} for specific users, email/username masking
- All controlled by params (off by default)
2026-06-23 12:56:39 -05:00
gitea-actions[bot] e513c757b9 chore(version): pre-release bump to 02.47.62-dev [skip ci] 2026-06-23 17:54:05 +00:00
gitea-actions[bot] ce15178dfd chore(version): auto-bump patch 02.47.61-dev [skip ci] 2026-06-23 17:53:41 +00:00
Jonathan Miller 377076e60f style(dashboard): show toggle switch for all configured plugins
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 7s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 7s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 16s
Universal: Auto Version Bump / Version Bump (push) Successful in 19s
Universal: PR Check / Validate PR (pull_request) Failing after 9s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 2s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 18s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 34s
Generic: Project CI / Lint & Validate (pull_request) Successful in 55s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 1m0s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
Toggle switch shown for any plugin with extension_id (installed).
Protected plugins still show badge only. Unconfigured plugins
show no switch or configure button. Removes configure_only logic.
2026-06-23 12:53:20 -05:00
gitea-actions[bot] ed399998d4 chore(version): pre-release bump to 02.47.60-dev [skip ci] 2026-06-23 17:46:39 +00:00
gitea-actions[bot] 50356f8b05 chore(version): auto-bump patch 02.47.59-dev [skip ci] 2026-06-23 17:46:26 +00:00
Jonathan Miller 65ffa835d9 feat: email protector + snippets engine
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 10s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: Auto Version Bump / Version Bump (push) Successful in 17s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 18s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 38s
Generic: Project CI / Lint & Validate (pull_request) Successful in 39s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 42s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 49s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 43s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
- Email Protector (#167): base64 obfuscation with JS decloaking,
  protects mailto links and plain emails, inject script before </body>
- Snippets (#176): {snippet alias="x" var="val"} tags with DB table,
  variable substitution, nested snippet support (max depth 5)
- Both controlled by params (off by default)
- Snippets table added to install.mysql.sql
2026-06-23 12:46:03 -05:00
gitea-actions[bot] a91d78beff chore(version): pre-release bump to 02.47.58-dev [skip ci] 2026-06-23 17:38:27 +00:00
gitea-actions[bot] 561ea3691a chore(version): auto-bump patch 02.47.57-dev [skip ci] 2026-06-23 17:37:51 +00:00
Jonathan Miller 1fe7c77fbf feat(conditional-content): {show}/{hide} tag processing with conditions engine
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 9s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 8s
Universal: Auto Version Bump / Version Bump (push) Successful in 19s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 14s
Universal: PR Check / Branch Policy (pull_request) Successful in 3s
Universal: PR Check / Validate PR (pull_request) Failing after 8s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 38s
Generic: Project CI / Lint & Validate (pull_request) Successful in 51s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 52s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 47s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 59s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
- processConditionalTags() handles {show}, {hide}, {else} blocks
- Supports condition="alias_or_id" for saved condition sets
- Supports inline rules: access_level, user_group, menu_item, home_page, date, day, url
- Multiple inline rules per tag use AND logic
- Nested tag support (processes innermost first, up to 10 iterations)
- Runs in onContentPrepare (articles) and onAfterRender (final HTML)
- ConditionsHelper: added passByAlias(), resolveAlias(), evaluateInlineRule()
- Implements #164
2026-06-23 12:37:31 -05:00
gitea-actions[bot] 3c94ffeff3 chore(version): pre-release bump to 02.47.56-dev [skip ci] 2026-06-23 17:34:38 +00:00
gitea-actions[bot] 9067dc62f7 chore(version): auto-bump patch 02.47.55-dev [skip ci] 2026-06-23 17:34:11 +00:00
Jonathan Miller 36bfe59115 feat(amm): module filtering via onPrepareModuleList + conditions engine
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 5s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 5s
Generic: Project CI / Lint & Validate (pull_request) Successful in 16s
Universal: PR Check / Branch Policy (pull_request) Successful in 3s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 15s
Universal: PR Check / Validate PR (pull_request) Failing after 9s
Generic: Repo Health / Access control (pull_request) Successful in 3s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: Auto Version Bump / Version Bump (push) Successful in 25s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 1m0s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 54s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 27s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 1m5s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
Frontend modules filtered based on condition sets mapped via
ConditionsHelper::shouldDisplay('com_modules', moduleId).
Modules with no conditions pass through. Graceful skip if tables
don't exist. Implements #160.
2026-06-23 12:33:30 -05:00
gitea-actions[bot] 5b1fe5f806 chore(version): pre-release bump to 02.47.54-dev [skip ci] 2026-06-23 17:32:36 +00:00
gitea-actions[bot] 5855d03ae1 chore(version): auto-bump patch 02.47.53-dev [skip ci] 2026-06-23 17:32:22 +00:00
Jonathan Miller 6090682afd feat(cache): auto-clear Joomla cache on content/extension save
Universal: PR Check / Branch Policy (pull_request) Successful in 3s
Universal: PR Check / Validate PR (pull_request) Failing after 9s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: Auto Version Bump / Version Bump (push) Successful in 17s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 14s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 16s
Generic: Project CI / Lint & Validate (pull_request) Successful in 35s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 35s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 37s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 44s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
- autoClearCache() called from onContentAfterSave and onExtensionAfterSave
- Controlled by auto_clear_cache param (default: off)
- Clears all cache groups via Cache::getInstance()->clean('')
- Silent failure — never breaks save operations
2026-06-23 12:32:01 -05:00
Jonathan Miller ae6719049d feat(conditions): add conditions engine DB schema and evaluation API
- Four tables: conditions, conditions_groups, conditions_rules, conditions_map
- ConditionsHelper with pass(), load(), shouldDisplay(), getConditionsForItem()
- 7 rule types: menu_item, home_page, user_group, access_level, date, day, url
- Hierarchical evaluation: condition → groups (AND/OR) → rules (AND/OR)
- Runtime cache for repeated evaluations within same request
- Foundation for Advanced Module Manager (#160) and Conditional Content (#164)
2026-06-23 12:32:00 -05:00
gitea-actions[bot] 98694e46d6 chore(version): pre-release bump to 02.47.52-dev [skip ci] 2026-06-23 17:30:39 +00:00
gitea-actions[bot] 0a6a4d581c chore(version): auto-bump patch 02.47.51-dev [skip ci] 2026-06-23 17:30:26 +00:00
Jonathan Miller d7efb61207 fix(cpanel): add missing sitename/db_type to helper, pill button group
Universal: PR Check / Branch Policy (pull_request) Successful in 4s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 10s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 17s
Universal: PR Check / Validate PR (pull_request) Failing after 12s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 2s
Universal: Auto Version Bump / Version Bump (push) Successful in 20s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 15s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 40s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 14s
Generic: Project CI / Lint & Validate (pull_request) Successful in 41s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 42s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
- CpanelHelper now returns sitename and db_type for info bar
- Cache module renders as single pill with three joined buttons
  (domain key, cache clear, temp clear)
2026-06-23 12:29:53 -05:00
gitea-actions[bot] 1e081139e6 chore(version): pre-release bump to 02.47.50-dev [skip ci] 2026-06-23 17:01:28 +00:00
gitea-actions[bot] 0f81e227fc chore(version): auto-bump patch 02.47.49-dev [skip ci] 2026-06-23 17:01:09 +00:00
Jonathan Miller 57b48520af feat: guided tours framework + DevTools reset tour toggle
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 9s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 9s
Universal: PR Check / Branch Policy (pull_request) Successful in 3s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 19s
Universal: PR Check / Validate PR (pull_request) Failing after 12s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 2s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 18s
Generic: Project CI / Lint & Validate (pull_request) Successful in 48s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 51s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 54s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 19s
Universal: Auto Version Bump / Version Bump (push) Successful in 14s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
- registerGuidedTours() in script.php postflight registers Welcome and
  Firewall tours via Joomla's #__guidedtours/#__guidedtour_steps tables
- Tours use com_mokosuiteclient.* UIDs, auto-update on package update
- DevTools: reset_tour_prompts one-shot toggle clears all guided tour
  completion flags from #__user_profiles on save
- Language keys added for tour reset field
2026-06-23 11:59:48 -05:00
gitea-actions[bot] bda9ec1192 chore(version): pre-release bump to 02.47.48-dev [skip ci] 2026-06-23 16:48:38 +00:00
gitea-actions[bot] e9af9dc268 chore(version): auto-bump patch 02.47.47-dev [skip ci] 2026-06-23 16:48:18 +00:00
Jonathan Miller d595f23310 fix(cache-module): use Atum header-item structure for status bar items
Universal: PR Check / Branch Policy (pull_request) Successful in 4s
Universal: PR Check / Validate PR (pull_request) Failing after 9s
Generic: Project CI / Lint & Validate (pull_request) Successful in 17s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 14s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 3s
Universal: Auto Version Bump / Version Bump (push) Successful in 21s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 48s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 22s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 58s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 57s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
Each item (domain, cache, temp) wrapped in proper header-item markup
with header-item-icon and header-item-text to match Joomla Atum CSS.
2026-06-23 11:47:46 -05:00
gitea-actions[bot] 0b95419eb6 chore(version): pre-release bump to 02.47.46-dev [skip ci] 2026-06-23 16:47:38 +00:00
gitea-actions[bot] 8a89bc1296 chore(version): auto-bump patch 02.47.45-dev [skip ci] 2026-06-23 16:47:25 +00:00
Jonathan Miller f659c73ffa fix(cache-module): fix AJAX URLs and simplify status bar markup
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Generic: Project CI / Lint & Validate (pull_request) Successful in 10s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 7s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: Auto Version Bump / Version Bump (push) Successful in 10s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 16s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 39s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 37s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 36s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
Task URLs corrected to display.clearCache/display.clearTemp format.
Removed custom CSS in favor of inline Bootstrap utilities.
2026-06-23 11:47:08 -05:00
gitea-actions[bot] 8e3cd85e3d chore(version): pre-release bump to 02.47.44-dev [skip ci] 2026-06-23 16:46:35 +00:00
gitea-actions[bot] 865b769a71 chore(version): auto-bump patch 02.47.43-dev [skip ci] 2026-06-23 16:46:15 +00:00
Jonathan Miller 10c2c4bbc7 style(cpanel): remove dashboard button, shield links based on ACL
Generic: Project CI / Lint & Validate (pull_request) Successful in 17s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 9s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: Auto Version Bump / Version Bump (push) Successful in 21s
Universal: PR Check / Validate PR (pull_request) Failing after 10s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 16s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 15s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 21s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 48s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 46s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 55s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
Shield icon links to dashboard only if user has core.manage permission
on com_mokosuiteclient. Otherwise renders as static icon.
2026-06-23 11:45:50 -05:00
gitea-actions[bot] b8cd65c45c chore(version): pre-release bump to 02.47.42-dev [skip ci] 2026-06-23 16:44:41 +00:00
gitea-actions[bot] f86d598610 chore(version): auto-bump patch 02.47.41-dev [skip ci] 2026-06-23 16:44:21 +00:00
Jonathan Miller 06c618dd50 style(cpanel): simplify to single info line with clickable shield
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 9s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Generic: Project CI / Lint & Validate (pull_request) Successful in 18s
Universal: Auto Version Bump / Version Bump (push) Successful in 22s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 12s
Universal: PR Check / Validate PR (pull_request) Failing after 11s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 16s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 22s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 58s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 1m7s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 1m5s
Generic: Project CI / Tests (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Single row: shield link, site name, badges, IP, dashboard button.
Removed collapsible body, plugin list, health stats, cache button.
2026-06-23 11:43:53 -05:00
gitea-actions[bot] 56fc3dc065 chore(version): auto-bump patch 02.47.40-dev [skip ci] 2026-06-23 16:41:26 +00:00
Jonathan Miller 8fa87ef1d7 style: label all info bar badges with title + version in both views
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 8s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Generic: Project CI / Lint & Validate (pull_request) Successful in 17s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 16s
Universal: Auto Version Bump / Version Bump (push) Successful in 18s
Universal: PR Check / Validate PR (pull_request) Failing after 8s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 12s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 47s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 50s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 48s
Generic: Project CI / Tests (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
MokoSuite 02.47.xx | Joomla 6.1.1 | PHP 8.4.20 | mysql
2026-06-23 11:41:02 -05:00
gitea-actions[bot] f1cee7268d chore(version): pre-release bump to 02.47.39-dev [skip ci] 2026-06-23 16:28:59 +00:00
gitea-actions[bot] 7c9c81b2a4 chore(version): auto-bump patch 02.47.38-dev [skip ci] 2026-06-23 16:28:40 +00:00
Jonathan Miller c79a76c9d7 style: unify dashboard and cpanel info bar to same inline badge layout
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 6s
Universal: Auto Version Bump / Version Bump (push) Successful in 12s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 12s
Universal: PR Check / Branch Policy (pull_request) Successful in 3s
Universal: PR Check / Validate PR (pull_request) Failing after 8s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 29s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 46s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Project CI / Lint & Validate (pull_request) Successful in 53s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 56s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 59s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 41s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
Both now use identical structure: shield icon, site name, version badge,
PIN badge, Joomla/PHP/DB badges, debug/offline flags, IP with globe.
Dashboard button restored on cpanel toggle row.
2026-06-23 11:28:27 -05:00
gitea-actions[bot] 08d6140f2a chore(version): pre-release bump to 02.47.37-dev [skip ci] 2026-06-23 16:25:54 +00:00
gitea-actions[bot] 69127e5749 chore(version): pre-release bump to 02.47.36-dev [skip ci] 2026-06-23 16:25:15 +00:00
gitea-actions[bot] f0cf2122f4 chore(version): auto-bump patch 02.47.35-dev [skip ci] 2026-06-23 16:24:49 +00:00
Jonathan Miller d8712c1247 style: add shield icon to dashboard info bar and cpanel module header
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 10s
Universal: Auto Version Bump / Version Bump (push) Successful in 15s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 19s
Universal: PR Check / Branch Policy (pull_request) Successful in 3s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 30s
Universal: PR Check / Validate PR (pull_request) Failing after 8s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 47s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Project CI / Lint & Validate (pull_request) Successful in 55s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 56s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 57s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 39s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
2026-06-23 11:24:35 -05:00
gitea-actions[bot] f4b1059f95 chore(version): pre-release bump to 02.47.34-dev [skip ci] 2026-06-23 16:21:03 +00:00
gitea-actions[bot] 1d3ea606c5 chore(version): auto-bump patch 02.47.33-dev [skip ci] 2026-06-23 16:20:43 +00:00
Jonathan Miller 9d3ec28504 style(cpanel): mirror dashboard info strip in cpanel module header
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 7s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: Auto Version Bump / Version Bump (push) Successful in 15s
Generic: Project CI / Lint & Validate (pull_request) Successful in 15s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 14s
Universal: PR Check / Validate PR (pull_request) Failing after 9s
Generic: Repo Health / Access control (pull_request) Successful in 3s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 17s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 47s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 33s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 1m0s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 1m3s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
Shows site name, MokoSuite version, Support PIN, Joomla/PHP/DB badges,
debug/offline flags, IP, and dashboard link in a single info row.
Collapse toggle moved below with plugin count summary.
2026-06-23 11:20:26 -05:00
gitea-actions[bot] 1c7452f360 chore(version): pre-release bump to 02.47.32-dev [skip ci] 2026-06-23 16:16:16 +00:00
gitea-actions[bot] 46cfd53052 chore(version): auto-bump patch 02.47.31-dev [skip ci] 2026-06-23 16:15:52 +00:00
Jonathan Miller 0456f467c7 feat(dashboard): add heartbeat send button next to Support PIN
Generic: Project CI / Lint & Validate (pull_request) Failing after 2s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 5s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 11s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 3s
Universal: Auto Version Bump / Version Bump (push) Successful in 16s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 46s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 28s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 51s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 54s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 53s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
Upload icon button beside the PIN badge triggers sendHeartbeat AJAX
call to HQ, which includes the health token (HQ derives the PIN).
2026-06-23 11:15:34 -05:00
gitea-actions[bot] aa9f18525e chore(version): pre-release bump to 02.47.30-dev [skip ci] 2026-06-23 16:12:31 +00:00
gitea-actions[bot] 4ccb916895 chore(version): auto-bump patch 02.47.29-dev [skip ci] 2026-06-23 16:12:03 +00:00
Jonathan Miller fe74ea89a5 style(dashboard): remove ext version bar, 3-column plugin cards
Universal: PR Check / Branch Policy (pull_request) Successful in 3s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 9s
Universal: Auto Version Bump / Version Bump (push) Successful in 22s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 13s
Universal: PR Check / Validate PR (pull_request) Failing after 8s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 4s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 31s
Generic: Project CI / Lint & Validate (pull_request) Successful in 1m3s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 1m6s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 1m10s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 1m7s
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
- Removed extension version bar (versions already shown on each card)
- Plugin cards now 3 per row (col-lg-4) except core category (full width)
2026-06-23 11:11:33 -05:00
gitea-actions[bot] da78796cc1 chore(version): pre-release bump to 02.47.28-dev [skip ci] 2026-06-23 15:55:50 +00:00
gitea-actions[bot] 247c560510 chore(version): auto-bump patch 02.47.27-dev [skip ci] 2026-06-23 15:55:31 +00:00
Jonathan Miller 3390c76719 fix(devtools): use com_content component param for hit suppression
Universal: Auto Version Bump / Version Bump (push) Successful in 20s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 29s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 7s
Generic: Project CI / Lint & Validate (pull_request) Successful in 49s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 10s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 51s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 2s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 1m7s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 45s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 1m2s
Generic: Project CI / Tests (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
record_hits is a com_content parameter checked via
ComponentHelper::getParams(), not a global config key.
2026-06-23 10:55:04 -05:00
gitea-actions[bot] 5d5a7dcdbf chore(version): pre-release bump to 02.47.26-dev [skip ci] 2026-06-23 15:51:17 +00:00
gitea-actions[bot] 76e9624ddf chore(version): auto-bump patch 02.47.25-dev [skip ci] 2026-06-23 15:50:52 +00:00
Jonathan Miller 6f7549fa7a fix: address PR review findings — security, performance, cleanup
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 10s
Universal: Auto Version Bump / Version Bump (push) Successful in 15s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 15s
Universal: PR Check / Branch Policy (pull_request) Successful in 3s
Universal: PR Check / Validate PR (pull_request) Failing after 7s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 29s
Generic: Project CI / Lint & Validate (pull_request) Successful in 51s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 52s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 52s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 1m1s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 41s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
- togglePlugin: restrict scope to mokosuiteclient plugins only (was any plugin)
- DevTools: replace full-table hits reset on every request with config toggle
- CurrentIpField: prefer REMOTE_ADDR over spoofable X-Forwarded-For
- SQL: explicit (int) cast on $days interpolation in chart queries
- Heartbeat: enable SSL peer verification (was disabled)
- script.php: remove orphaned docblock
2026-06-23 10:50:37 -05:00
gitea-actions[bot] 91dd1e1eb5 chore(version): pre-release bump to 02.47.24-dev [skip ci] 2026-06-23 15:48:16 +00:00
gitea-actions[bot] 28a4a8cd1b chore(version): auto-bump patch 02.47.23-dev [skip ci] 2026-06-23 15:47:50 +00:00
Jonathan Miller dcaaf007cf fix(dashboard): translate COM_ACTIONLOGS_DISABLED stored in ip_address column
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 7s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 8s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 4s
Universal: Auto Version Bump / Version Bump (push) Successful in 15s
Generic: Project CI / Lint & Validate (pull_request) Successful in 43s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 41s
Generic: Repo Health / Access control (pull_request) Successful in 4s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 46s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 50s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 30s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 55s
Generic: Project CI / Tests (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
Joomla stores the literal string 'COM_ACTIONLOGS_DISABLED' in the
action_logs ip_address column when IP logging is turned off. Show
'IP logging off' instead of the raw language key.
2026-06-23 10:47:06 -05:00
gitea-actions[bot] 39837737c5 chore(version): pre-release bump to 02.47.22-dev [skip ci] 2026-06-23 14:07:38 +00:00
gitea-actions[bot] 2a6f5e2d96 chore(version): auto-bump patch 02.47.21-dev [skip ci] 2026-06-23 14:07:26 +00:00
Jonathan Miller 9118eb1fb5 fix(lang): add COM_ACTIONLOGS_DISABLED fallback translation
Universal: Auto Version Bump / Version Bump (push) Successful in 14s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 14s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 34s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Defines the Joomla core key in our own language file so it renders
properly even when the core language file is missing or corrupt.
2026-06-23 09:07:05 -05:00
gitea-actions[bot] a295f44c57 chore(version): pre-release bump to 02.47.20-dev [skip ci] 2026-06-23 13:20:31 +00:00
gitea-actions[bot] daaf0a73f6 chore(version): pre-release bump to 02.47.19-dev [skip ci] 2026-06-23 13:20:05 +00:00
gitea-actions[bot] af6165d800 chore(version): auto-bump patch 02.47.18-dev [skip ci] 2026-06-23 13:19:46 +00:00
Jonathan Miller 4c4d98cc9f fix(dashboard): require action logs, enable on install, show alert if disabled
Universal: Auto Version Bump / Version Bump (push) Successful in 14s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 25s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 1m37s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
- Install script enables actionlog/joomla and system/actionlogs plugins
- Dashboard shows alert banner with enable link when action logs disabled
- Reverted conditional hiding of UI (action logs is a hard requirement)
2026-06-23 08:19:27 -05:00
Jonathan Miller cfc70ac712 fix(dashboard): handle disabled action logs gracefully
- Check ComponentHelper::isEnabled('com_actionlogs') before rendering
  login chart, View Logs button, and recent logins table
- Show helpful warning when action logs disabled instead of raw
  COM_ACTIONLOGS_DISABLED language key
2026-06-23 08:19:27 -05:00
gitea-actions[bot] e4558c1642 chore(version): pre-release bump to 02.47.17-dev [skip ci] 2026-06-23 13:05:30 +00:00
gitea-actions[bot] 7e73343b4f chore(version): auto-bump patch 02.47.16-dev [skip ci] 2026-06-23 13:05:19 +00:00
Jonathan Miller 29bf75051f style(dashboard): use Bootstrap grid columns for extension version bar
Universal: Auto Version Bump / Version Bump (push) Successful in 14s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 16s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 1m16s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Dynamically calculates col-N from extension count (12/count) so items
spread evenly across the full width as horizontal cells, not stacked.
Removed custom flex CSS in favour of Bootstrap row/g-0.
2026-06-23 08:05:02 -05:00
gitea-actions[bot] cca6ae3326 chore(version): pre-release bump to 02.47.15-dev [skip ci] 2026-06-23 12:50:14 +00:00
gitea-actions[bot] d0fc3bdfb1 chore(version): pre-release bump to 02.47.14-dev [skip ci] 2026-06-23 12:50:01 +00:00
gitea-actions[bot] 50c3b621a3 chore(version): auto-bump patch 02.47.13-dev [skip ci] 2026-06-23 12:49:52 +00:00
Jonathan Miller 0aeaea208f feat(dashboard): show frontend/backend app badges on recent logins, full-width ext bar
Universal: Auto Version Bump / Version Bump (push) Successful in 8s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 11s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 52s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
- Recent logins table now parses action log message JSON to display
  Admin/Site badge indicating where each login occurred
- Login query uses exact match on LOGGED_IN key (excludes logout events)
- Login limit increased from 5 to 10
- Info bar reverted from stacked column to horizontal row layout
- Extension version bar uses flex: 1 1 0 for full-width auto-sized cells
- Updated CHANGELOG
2026-06-23 07:47:43 -05:00
gitea-actions[bot] 95e9e618aa chore(version): pre-release bump to 02.47.12-dev [skip ci] 2026-06-23 03:22:01 +00:00
gitea-actions[bot] 112e2810bd chore(version): pre-release bump to 02.47.11-dev [skip ci] 2026-06-23 00:39:25 +00:00
gitea-actions[bot] 4088815485 chore(version): auto-bump patch 02.47.10-dev [skip ci] 2026-06-23 00:39:12 +00:00
Jonathan Miller 328acb462b style(dashboard): full-width info bar with stacked labels and auto-sizing
Universal: Auto Version Bump / Version Bump (push) Successful in 11s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 18s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 33s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
- Items distribute evenly across full width via justify-content: space-between
- Labels stack above values (flex-direction: column) for cleaner layout
- Smaller label text (0.7rem), consistent badge sizing
- Debug/Offline badges wrapped in info-items for consistent spacing
- MokoSuiteClient → MokoSuite in version label
2026-06-22 19:38:55 -05:00
gitea-actions[bot] ee27f0a3b2 chore(version): pre-release bump to 02.47.09-dev [skip ci] 2026-06-22 14:18:38 +00:00
gitea-actions[bot] e70539f817 chore(version): pre-release bump to 02.47.08-dev [skip ci] 2026-06-22 00:35:51 +00:00
gitea-actions[bot] 4c39c583c0 chore(version): pre-release bump to 02.47.07-dev [skip ci] 2026-06-22 00:21:17 +00:00
gitea-actions[bot] 72da5ca1b5 chore(version): auto-bump patch 02.47.06-dev [skip ci] 2026-06-22 00:21:03 +00:00
Jonathan Miller 97670dbd54 style: display MokoSuite instead of MokoSuiteClient everywhere
Universal: Auto Version Bump / Version Bump (push) Successful in 10s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 18s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 36s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
2026-06-21 19:20:45 -05:00
gitea-actions[bot] 4e1b9b8044 chore(version): pre-release bump to 02.47.05-dev [skip ci] 2026-06-21 23:48:15 +00:00
gitea-actions[bot] 220e52fb71 chore(version): pre-release bump to 02.47.04-dev [skip ci] 2026-06-21 23:45:27 +00:00
gitea-actions[bot] c4735a73e8 chore(version): pre-release bump to 02.47.03-dev [skip ci] 2026-06-21 23:32:26 +00:00
gitea-actions[bot] d430e083e4 chore(version): pre-release bump to 02.47.02-dev [skip ci] 2026-06-21 23:31:58 +00:00
Jonathan Miller 52ad2f2b37 docs: update changelog and README for v02.47 release cycle
Universal: Auto Version Bump / Version Bump (push) Successful in 18s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 16s
2026-06-21 18:27:24 -05:00
gitea-actions[bot] 0308df3b53 chore(version): pre-release bump to 02.47.01-dev [skip ci] 2026-06-21 23:26:05 +00:00
Jonathan Miller 21df82dc59 chore: remove ticket guided tour and support menu, rename aliases tab
Universal: Auto Version Bump / Version Bump (push) Successful in 13s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 29s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 41s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
- Removed helpdesk guided tour (tickets moved to MokoSuiteCRM)
- setupSupportMenuItem returns early (no ticket menu)
- Renamed tab: Mirror Domains & Staging Environments
2026-06-21 18:15:59 -05:00
gitea-actions[bot] 9ad828c248 chore(version): pre-release bump to 02.47.00-dev [skip ci] 2026-06-21 23:13:05 +00:00
gitea-actions[bot] 15e891dca2 chore(version): auto-bump patch 02.46.99-dev [skip ci] 2026-06-21 23:12:45 +00:00
Jonathan Miller 6ee0f08f42 fix: undefined $pluginDir in reinstallBrokenPlugins Step 1
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 52s
Universal: Auto Version Bump / Version Bump (push) Successful in 16s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 25s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
2026-06-21 18:04:54 -05:00
gitea-actions[bot] d0ff29aed2 chore(version): pre-release bump to 02.46.98-dev [skip ci] 2026-06-21 23:02:06 +00:00
gitea-actions[bot] 6186eec2ca chore(version): pre-release bump to 02.46.97-dev [skip ci] 2026-06-21 23:01:25 +00:00
gitea-actions[bot] 4566071d74 chore(version): auto-bump patch 02.46.96-dev [skip ci] 2026-06-21 23:01:03 +00:00
Jonathan Miller 4a8570f7a3 feat(devtools): Domain Aliases & Staging — repeatable subform table
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 9s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 14s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 7s
Generic: Project CI / Lint & Validate (pull_request) Successful in 1m1s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 55s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 1m7s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 1m8s
Universal: Auto Version Bump / Version Bump (push) Successful in 22s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 1m3s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 26s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
Renamed from "Dev Domain" to "Domain Aliases & Staging". Now a
repeatable table (subform) supporting multiple domain aliases, each
with: domain, offline bypass, robots directive, and label.

Core plugin reads all aliases and matches current host against the
list. Auto-includes dev.{primary_domain} when no aliases configured.
2026-06-21 17:59:21 -05:00
gitea-actions[bot] 756e8b664b chore(version): pre-release bump to 02.46.95-dev [skip ci] 2026-06-21 22:51:49 +00:00
gitea-actions[bot] a8224bce93 chore(version): auto-bump patch 02.46.94-dev [skip ci] 2026-06-21 22:51:13 +00:00
Jonathan Miller 711b89ea03 fix(install): two-step plugin reinstall — extract files then create DB records
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 5s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: Auto Version Bump / Version Bump (push) Successful in 11s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 10s
Generic: Project CI / Lint & Validate (pull_request) Successful in 12s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 34s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 34s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 39s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 35s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
Step 1: Extract plugin zips to correct directories (always re-extract)
Step 2: For each expected plugin with files but no DB record, INSERT
with all required fields. Set namespace via separate UPDATE (handles
Joomla versions without namespace column).
2026-06-21 17:51:01 -05:00
gitea-actions[bot] 98d7ab3bb3 chore(version): pre-release bump to 02.46.93-dev [skip ci] 2026-06-21 22:43:47 +00:00
gitea-actions[bot] ee4746e8ff chore(version): pre-release bump to 02.46.92-dev [skip ci] 2026-06-21 22:41:46 +00:00
gitea-actions[bot] 6fa3cbbaea chore(version): auto-bump patch 02.46.91-dev [skip ci] 2026-06-21 22:41:31 +00:00
Jonathan Miller 0e2433cf5c fix(install): use Joomla Installer API for plugin reinstall
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 14s
Universal: Auto Version Bump / Version Bump (push) Successful in 23s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 16s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 20s
Universal: PR Check / Validate PR (pull_request) Failing after 7s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 52s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Project CI / Lint & Validate (pull_request) Successful in 56s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 58s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 1m5s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 48s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
Replace raw ZipArchive extract with Joomla\CMS\Installer\Installer::install()
which properly handles namespace registration, extension record creation,
and all internal bookkeeping. Removes manual INSERT from enablePlugin()
since the Installer handles it correctly.
2026-06-21 17:41:09 -05:00
gitea-actions[bot] 59f50867c0 chore(version): pre-release bump to 02.46.90-dev [skip ci] 2026-06-21 22:36:01 +00:00
gitea-actions[bot] 941d49e0ce chore(version): pre-release bump to 02.46.89-dev [skip ci] 2026-06-21 22:33:26 +00:00
gitea-actions[bot] ad7af89228 chore(version): pre-release bump to 02.46.88-dev [skip ci] 2026-06-21 22:30:04 +00:00
gitea-actions[bot] 078caa423b chore(version): auto-bump patch 02.46.87-dev [skip ci] 2026-06-21 22:29:49 +00:00
Jonathan Miller 1583e98cea fix(install): always re-extract plugin zips on update, pretty cpanel labels
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 10s
Generic: Project CI / Lint & Validate (pull_request) Successful in 18s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 19s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 15s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 49s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 1m0s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 1m5s
Universal: Auto Version Bump / Version Bump (push) Successful in 14s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 17s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
- reinstallBrokenPlugins now re-extracts ALL expected plugins on every
  update (removes old dir first) to ensure files stay current
- Cpanel plugin labels: Core Engine, Web Firewall, Tenant Guard,
  Dev Tools, Offline Bypass, GeoIP Lookup, License Manager
2026-06-21 17:26:54 -05:00
gitea-actions[bot] a737ac9106 chore(version): pre-release bump to 02.46.86-dev [skip ci] 2026-06-21 22:22:00 +00:00
gitea-actions[bot] d03269c1ca chore(version): auto-bump patch 02.46.85-dev [skip ci] 2026-06-21 22:21:46 +00:00
Jonathan Miller 29079c10e2 feat(devtools): implement dev domain offline bypass and robots logic
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 7s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Generic: Project CI / Lint & Validate (pull_request) Successful in 16s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 16s
Universal: PR Check / Validate PR (pull_request) Failing after 8s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 2s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 12s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 42s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 47s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 48s
Universal: Auto Version Bump / Version Bump (push) Successful in 12s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
handleSiteAlias() and injectAliasRobots() now read from DevTools
plugin params instead of hardcoding dev.{primary_domain}. Supports
custom domain, configurable offline bypass, and robots directive.
Uses static cache to avoid repeated DB queries per request.
2026-06-21 17:20:19 -05:00
gitea-actions[bot] b433865a6d chore(version): pre-release bump to 02.46.84-dev [skip ci] 2026-06-21 21:41:00 +00:00
gitea-actions[bot] b3cba3ea78 chore(version): pre-release bump to 02.46.83-dev [skip ci] 2026-06-21 21:26:22 +00:00
gitea-actions[bot] 3e79014b97 chore(version): auto-bump patch 02.46.82-dev [skip ci] 2026-06-21 21:26:08 +00:00
Jonathan Miller 62d213027f Merge remote-tracking branch 'origin/dev' into dev
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 8s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 9s
Universal: Auto Version Bump / Version Bump (push) Successful in 16s
Universal: PR Check / Validate PR (pull_request) Failing after 7s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 13s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 19s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 39s
Generic: Project CI / Lint & Validate (pull_request) Successful in 49s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 51s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 53s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
# Conflicts:
#	source/packages/plg_task_mokosuiteclient_tickets/mokosuiteclient_tickets.xml
2026-06-21 16:25:48 -05:00
Jonathan Miller b2d1e4ba23 chore: remove helpdesk/ticket system (migrating to MokoSuiteCRM #67)
- Removed ticket views, models, controllers (ticket, tickets, ticketsettings)
- Removed plg_task_mokosuiteclient_tickets plugin and source
- Removed from package manifest, enablePlugin, protectExtensions
- Removed Helpdesk entry from sidebar menu
- Ticket tables kept in SQL for migration compatibility
- See MokoSuiteClient#233, MokoSuiteCRM#67
2026-06-21 15:50:29 -05:00
gitea-actions[bot] d4c4d1be2d chore(version): pre-release bump to 02.46.81-dev [skip ci] 2026-06-21 20:35:25 +00:00
gitea-actions[bot] 5ec943b90e chore(version): pre-release bump to 02.46.80-dev [skip ci] 2026-06-21 16:59:49 +00:00
gitea-actions[bot] 09553be73b chore(version): auto-bump patch 02.46.79-dev [skip ci] 2026-06-21 16:59:38 +00:00
Jonathan Miller a5dd8e395d style(menu): remove child/parent margin — just pad the wrapper
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 6s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Generic: Project CI / Lint & Validate (pull_request) Successful in 13s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 12s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: PR Check / Validate PR (pull_request) Failing after 7s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 11s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 34s
Universal: Auto Version Bump / Version Bump (push) Successful in 10s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 35s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 38s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 13s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
2026-06-21 11:59:00 -05:00
gitea-actions[bot] fad314eef7 chore(version): pre-release bump to 02.46.78-dev [skip ci] 2026-06-21 16:53:10 +00:00
gitea-actions[bot] 7472866e14 chore(version): auto-bump patch 02.46.77-dev [skip ci] 2026-06-21 16:52:56 +00:00
Jonathan Miller 5ef3279e29 style(menu): add padding-right to sidebar wrapper
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 5s
Universal: Auto Version Bump / Version Bump (push) Successful in 11s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 10s
Generic: Project CI / Lint & Validate (pull_request) Successful in 13s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 2s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 17s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 31s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 32s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 36s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 32s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
2026-06-21 11:52:42 -05:00
gitea-actions[bot] 0f2679d6f1 chore(version): pre-release bump to 02.46.76-dev [skip ci] 2026-06-21 16:50:54 +00:00
gitea-actions[bot] 8746e56860 chore(version): auto-bump patch 02.46.75-dev [skip ci] 2026-06-21 16:50:39 +00:00
Jonathan Miller a198990982 feat(devtools): configurable dev domain with offline bypass
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 6s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 9s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Generic: Repo Health / Access control (pull_request) Successful in 3s
Universal: Auto Version Bump / Version Bump (push) Successful in 17s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 13s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 17s
Generic: Project CI / Lint & Validate (pull_request) Successful in 36s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 36s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 39s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 40s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
- Dev Domain fieldset in DevTools plugin settings
- Custom dev domain or auto-detect as dev.{primary_domain}
- Offline bypass, robots directive per dev domain
- Core plugin reads dev domain from devtools params
- Sidebar CSS: margin child ul instead of individual icons
2026-06-21 11:50:21 -05:00
gitea-actions[bot] 8632068357 chore(version): pre-release bump to 02.46.74-dev [skip ci] 2026-06-21 16:43:58 +00:00
gitea-actions[bot] ac0f4b30bd chore(version): pre-release bump to 02.46.73-dev [skip ci] 2026-06-21 16:43:39 +00:00
gitea-actions[bot] 66c8d9c574 chore(version): auto-bump patch 02.46.72-dev [skip ci] 2026-06-21 16:43:25 +00:00
Jonathan Miller b62fe22244 fix(health): return error on exceptions, fix MokoSuiteBackup detection
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 7s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 7s
Universal: Auto Version Bump / Version Bump (push) Successful in 11s
Universal: PR Check / Validate PR (pull_request) Failing after 7s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 11s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 19s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 37s
Generic: Project CI / Lint & Validate (pull_request) Successful in 38s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 41s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 41s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
- Health check catch blocks now return status:error with message
- MokoSuiteBackup detection returns early and queries correct table
- Added checkMokoSuiteBackup() method for mokosuitebackup_records
2026-06-21 11:43:11 -05:00
gitea-actions[bot] 2d52cd9b05 chore(version): pre-release bump to 02.46.71-dev [skip ci] 2026-06-21 16:33:10 +00:00
gitea-actions[bot] 505da43fc9 chore(version): auto-bump patch 02.46.70-dev [skip ci] 2026-06-21 16:32:47 +00:00
Jonathan Miller c6b1e3dc7b fix: sidebar icon margin, scope orphan deletion to MokoSuiteClient
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 7s
Universal: Auto Version Bump / Version Bump (push) Successful in 19s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 30s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 52s
Generic: Project CI / Lint & Validate (pull_request) Successful in 58s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 58s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 52s
Universal: PR Check / Branch Policy (pull_request) Successful in 3s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 10s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 1s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 51s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
- Zero left margin on sidebar menu icons
- cleanupEmptyElements only deletes MokoSuiteClient orphan rows
2026-06-21 11:32:24 -05:00
gitea-actions[bot] 111e7c3bf3 chore(version): pre-release bump to 02.46.69-dev [skip ci] 2026-06-21 16:20:11 +00:00
gitea-actions[bot] bfe1456208 chore(version): auto-bump patch 02.46.68-dev [skip ci] 2026-06-21 16:19:59 +00:00
Jonathan Miller 83b6933ff5 feat(heartbeat): include dev_domain in heartbeat payload
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 6s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 7s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 2s
Universal: Auto Version Bump / Version Bump (push) Successful in 13s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 14s
Generic: Project CI / Lint & Validate (pull_request) Successful in 34s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 36s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 40s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 38s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
2026-06-21 11:19:46 -05:00
gitea-actions[bot] 6db037f76c chore(version): pre-release bump to 02.46.67-dev [skip ci] 2026-06-21 16:06:41 +00:00
gitea-actions[bot] 68fa3c6c75 chore(version): pre-release bump to 02.46.66-dev [skip ci] 2026-06-21 16:05:42 +00:00
gitea-actions[bot] 53e9037059 chore(version): auto-bump patch 02.46.65-dev [skip ci] 2026-06-21 16:05:29 +00:00
Jonathan Miller 820aca7124 fix(modules): namespace mismatch — cpanel and cache modules not loading
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 6s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 12s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 39s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: Auto Version Bump / Version Bump (push) Successful in 13s
Generic: Project CI / Lint & Validate (pull_request) Successful in 45s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 47s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 48s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 16s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 35s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
Manifest XML namespace didn't match PHP namespace:
- cpanel: MokoSuiteCpanel → MokoSuiteClientCpanel
- cache: MokoSuiteCache → MokoSuiteClientCache

Joomla couldn't find the Dispatcher class so modules silently failed.
2026-06-21 11:04:42 -05:00
gitea-actions[bot] 40b244e6af chore(version): pre-release bump to 02.46.64-dev [skip ci] 2026-06-21 15:58:13 +00:00
gitea-actions[bot] 832b3022ff chore(version): pre-release bump to 02.46.63-dev [skip ci] 2026-06-21 15:56:46 +00:00
gitea-actions[bot] fbe383d543 chore(version): auto-bump patch 02.46.62-dev [skip ci] 2026-06-21 15:56:32 +00:00
Jonathan Miller acef7ac02f feat(firewall): show current IP address in plugin settings
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 5s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 8s
Universal: Auto Version Bump / Version Bump (push) Successful in 12s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 12s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 17s
Generic: Project CI / Lint & Validate (pull_request) Successful in 34s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 33s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 36s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 38s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
Adds CurrentIpField that displays the admin's IP with a copy button,
making it easy to add to the Trusted IPs list. Shown at the top of
the firewall plugin's Network & Session fieldset.
2026-06-21 10:56:14 -05:00
gitea-actions[bot] 772b549423 chore(version): pre-release bump to 02.46.61-dev [skip ci] 2026-06-21 15:16:33 +00:00
gitea-actions[bot] f7b8bd4fab chore(version): pre-release bump to 02.46.60-dev [skip ci] 2026-06-21 15:16:05 +00:00
gitea-actions[bot] c861017ee0 chore(version): auto-bump patch 02.46.59-dev [skip ci] 2026-06-21 15:15:52 +00:00
Jonathan Miller b916e5a254 fix(install): prevent duplicate extension rows, add dedup cleanup
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 5s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 8s
Universal: Auto Version Bump / Version Bump (push) Successful in 12s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 11s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 17s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 34s
Generic: Project CI / Lint & Validate (pull_request) Successful in 32s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 34s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 41s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
- Check row exists before INSERT to prevent duplicates
- Deduplicate existing rows (keep lowest extension_id per element)
2026-06-21 10:15:39 -05:00
gitea-actions[bot] d6a7572067 chore(version): pre-release bump to 02.46.58-dev [skip ci] 2026-06-21 15:11:29 +00:00
gitea-actions[bot] 1f246c3654 chore(version): pre-release bump to 02.46.57-dev [skip ci] 2026-06-21 15:10:53 +00:00
gitea-actions[bot] eaad6f1d9f chore(version): auto-bump patch 02.46.56-dev [skip ci] 2026-06-21 15:10:43 +00:00
Jonathan Miller 0c9af815a6 fix(install): include custom_data and other required fields in extension INSERT
Universal: Auto Version Bump / Version Bump (push) Successful in 9s
Generic: Project CI / Lint & Validate (pull_request) Successful in 8s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 3s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 3s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 13s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Generic: Repo Health / Access control (pull_request) Successful in 3s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 7s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 38s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 29s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 30s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
2026-06-21 10:10:31 -05:00
gitea-actions[bot] ce80f9d195 chore(version): pre-release bump to 02.46.55-dev [skip ci] 2026-06-21 15:02:20 +00:00
gitea-actions[bot] b0b5f700ca chore(version): pre-release bump to 02.46.54-dev [skip ci] 2026-06-21 15:01:49 +00:00
gitea-actions[bot] 8bba6a7214 chore(version): auto-bump patch 02.46.53-dev [skip ci] 2026-06-21 15:01:36 +00:00
Jonathan Miller ac0c4cab81 fix(install): create extension records for plugins missing from DB
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 5s
Universal: Auto Version Bump / Version Bump (push) Successful in 11s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 7s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 17s
Universal: PR Check / Validate PR (pull_request) Failing after 4s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 10s
Generic: Project CI / Lint & Validate (pull_request) Successful in 35s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 37s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 37s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 33s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
enablePlugin now INSERTs a new extension row from the manifest XML
when no row exists (neither by element nor by empty element). This
handles the case where cleanupEmptyElements deleted the orphan rows
but the files were reinstalled from the package zip.
2026-06-21 10:01:23 -05:00
gitea-actions[bot] 9849338857 chore(version): pre-release bump to 02.46.52-dev [skip ci] 2026-06-21 14:55:45 +00:00
gitea-actions[bot] 01e5825ff2 chore(version): pre-release bump to 02.46.51-dev [skip ci] 2026-06-21 14:55:00 +00:00
gitea-actions[bot] 0aab262d7c chore(version): auto-bump patch 02.46.50-dev [skip ci] 2026-06-21 14:54:46 +00:00
Jonathan Miller 978dfdfcf3 fix(install): reinstall broken plugins from package zip in postflight
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 6s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 9s
Generic: Project CI / Lint & Validate (pull_request) Successful in 14s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Universal: Auto Version Bump / Version Bump (push) Successful in 13s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 1s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 17s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 32s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 35s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 37s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 37s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
When Joomla installs plugins with empty element, files go to the
group root. Postflight now:
1. Deletes orphan rows (empty element or display-name-as-element)
2. Cleans stale files from group roots
3. Checks each expected plugin directory exists
4. If missing, extracts the plugin zip from the package source dir

This guarantees all core plugins are correctly installed after every
update, regardless of the MySQL DEFAULT '' issue.
2026-06-21 09:54:28 -05:00
gitea-actions[bot] a639d1f8fb chore(version): pre-release bump to 02.46.49-dev [skip ci] 2026-06-21 14:49:23 +00:00
gitea-actions[bot] 079aa281d8 chore(version): pre-release bump to 02.46.48-dev [skip ci] 2026-06-21 14:19:47 +00:00
gitea-actions[bot] 1765e9f4b3 chore(version): pre-release bump to 02.46.47-dev [skip ci] 2026-06-21 14:06:36 +00:00
gitea-actions[bot] 84705bd2f7 chore(version): pre-release bump to 02.46.46-dev [skip ci] 2026-06-21 14:05:26 +00:00
gitea-actions[bot] ea83c75396 chore(version): auto-bump patch 02.46.45-dev [skip ci] 2026-06-21 14:05:12 +00:00
Jonathan Miller c28ca37c3c fix(install): delete empty-element rows and all stale files cleanly
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 5s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 5s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 7s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: Auto Version Bump / Version Bump (push) Successful in 12s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 11s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 16s
Generic: Project CI / Lint & Validate (pull_request) Successful in 31s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 41s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 39s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
Relocation approach failed — multiple plugins overwrite each other's
files at the group root. Instead, delete empty-element rows and all
stale files/dirs. On the NEXT update, Joomla creates fresh rows and
installs correctly since the orphan rows are gone.
2026-06-21 09:04:57 -05:00
gitea-actions[bot] 14708637b7 chore(version): pre-release bump to 02.46.44-dev [skip ci] 2026-06-21 13:56:15 +00:00
gitea-actions[bot] 59bb6337c9 chore(version): pre-release bump to 02.46.43-dev [skip ci] 2026-06-21 13:55:59 +00:00
gitea-actions[bot] b8abe2569c chore(version): auto-bump patch 02.46.42-dev [skip ci] 2026-06-21 13:55:45 +00:00
Jonathan Miller 679789e267 fix(install): relocate stale plugin files instead of deleting them
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 6s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 8s
Universal: Auto Version Bump / Version Bump (push) Successful in 13s
Universal: PR Check / Validate PR (pull_request) Failing after 7s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 12s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 18s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 35s
Generic: Project CI / Lint & Validate (pull_request) Successful in 39s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 41s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 42s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
When plugins install to the group root due to empty element, postflight
now moves the files to the correct plugin subdirectory and fixes the
element value in the DB. This preserves the plugin files instead of
losing them on every update.
2026-06-21 08:55:30 -05:00
gitea-actions[bot] cb3628b682 chore(version): pre-release bump to 02.46.41-dev [skip ci] 2026-06-21 13:49:07 +00:00
gitea-actions[bot] 9524d1152b chore(version): pre-release bump to 02.46.40-dev [skip ci] 2026-06-21 13:48:14 +00:00
gitea-actions[bot] 568af6905e chore(version): auto-bump patch 02.46.39-dev [skip ci] 2026-06-21 13:48:00 +00:00
Jonathan Miller 5b67751858 fix(install): restore DEFAULT '' in preflight for MySQL strict mode
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 5s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: Auto Version Bump / Version Bump (push) Successful in 11s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 10s
Generic: Project CI / Lint & Validate (pull_request) Successful in 13s
Universal: PR Check / Validate PR (pull_request) Failing after 7s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 2s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 18s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 33s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 33s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 36s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 31s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
Joomla INSERTs extension rows without element before setting it.
MySQL strict mode requires a default value. Preflight sets DEFAULT ''
so the INSERT succeeds, then postflight cleans up the empty rows
and stale files.
2026-06-21 08:47:46 -05:00
gitea-actions[bot] c2cc483eff chore(version): pre-release bump to 02.46.38-dev [skip ci] 2026-06-21 13:46:09 +00:00
gitea-actions[bot] dab90d2633 chore(version): pre-release bump to 02.46.37-dev [skip ci] 2026-06-21 13:45:52 +00:00
gitea-actions[bot] 57906c3aee chore(version): auto-bump patch 02.46.36-dev [skip ci] 2026-06-21 13:45:34 +00:00
Jonathan Miller e9bcee71be fix(install): move empty-element cleanup to postflight, drop ALTER
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 5s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 9s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Universal: Auto Version Bump / Version Bump (push) Successful in 12s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 37s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 21s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 37s
Generic: Project CI / Lint & Validate (pull_request) Successful in 38s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 41s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 40s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
The ALTER TABLE NOT NULL breaks Joomla's package installer on MySQL
strict mode. Instead, clean up empty-element rows and stale files in
postflight AFTER Joomla finishes installing sub-extensions.
2026-06-21 08:45:17 -05:00
gitea-actions[bot] 2348311528 chore(version): pre-release bump to 02.46.35-dev [skip ci] 2026-06-21 13:41:54 +00:00
gitea-actions[bot] 3660835b4f chore(version): pre-release bump to 02.46.34-dev [skip ci] 2026-06-21 13:41:37 +00:00
gitea-actions[bot] 1139cd91d9 chore(version): auto-bump patch 02.46.33-dev [skip ci] 2026-06-21 13:41:23 +00:00
Jonathan Miller 2733508045 fix(install): delete empty-element rows and stale files in preflight
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 7s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 8s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: Auto Version Bump / Version Bump (push) Successful in 14s
Generic: Project CI / Lint & Validate (pull_request) Successful in 13s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 16s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 35s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 40s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 40s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 33s
Generic: Project CI / Tests (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
Previous ALTER TABLE DEFAULT '' created orphaned extension rows with
empty element, causing plugins to install to the group root. Preflight
now deletes these rows and cleans stale services/src/language dirs.
2026-06-21 08:41:07 -05:00
gitea-actions[bot] b8a1b9769a chore(version): pre-release bump to 02.46.32-dev [skip ci] 2026-06-21 06:32:06 +00:00
gitea-actions[bot] 90410c3add chore(version): pre-release bump to 02.46.31-dev [skip ci] 2026-06-21 06:08:43 +00:00
gitea-actions[bot] 28bcf014bc chore(version): pre-release bump to 02.46.30-dev [skip ci] 2026-06-21 05:55:51 +00:00
gitea-actions[bot] 70fb6e04b2 chore(version): pre-release bump to 02.46.29-dev [skip ci] 2026-06-21 05:55:25 +00:00
gitea-actions[bot] f1f9b7eb73 chore(version): auto-bump patch 02.46.28-dev [skip ci] 2026-06-21 05:55:07 +00:00
Jonathan Miller 6af960d1f0 fix(install): revert element column DEFAULT '' on existing sites
Universal: Auto Version Bump / Version Bump (push) Successful in 17s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 6s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 8s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Generic: Project CI / Lint & Validate (pull_request) Successful in 41s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 29s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 46s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 42s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 47s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 42s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
2026-06-21 00:54:49 -05:00
gitea-actions[bot] f7311a8583 chore(version): pre-release bump to 02.46.27-dev [skip ci] 2026-06-21 05:49:47 +00:00
gitea-actions[bot] dcaee3e9ca chore(version): pre-release bump to 02.46.26-dev [skip ci] 2026-06-21 05:48:03 +00:00
gitea-actions[bot] 6704138998 chore(version): auto-bump patch 02.46.25-dev [skip ci] 2026-06-21 05:47:45 +00:00
Jonathan Miller 8bbae58d83 chore(install): remove update server URL migration and ALTER TABLE
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 8s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 9s
Universal: Auto Version Bump / Version Bump (push) Successful in 16s
Universal: PR Check / Validate PR (pull_request) Failing after 7s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 14s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 43s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 29s
Generic: Project CI / Lint & Validate (pull_request) Successful in 49s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 50s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 53s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
- Remove migrateUpdateServerUrls, cleanupStaleUpdateSites,
  fixUpdateRecords, enableUpdateServer calls from postflight
- Remove ALTER TABLE DEFAULT '' from preflight (caused plugin files
  to install to wrong directory)
- Dead method bodies left in file (harmless, never called)
2026-06-21 00:47:26 -05:00
gitea-actions[bot] e3bc5a0f42 chore(version): pre-release bump to 02.46.24-dev [skip ci] 2026-06-21 05:36:29 +00:00
gitea-actions[bot] c0b03ac5f4 chore(version): auto-bump patch 02.46.23-dev [skip ci] 2026-06-21 05:36:15 +00:00
Jonathan Miller 9a8d395cc8 fix(install): remove ALTER TABLE DEFAULT '' that breaks plugin installs
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 6s
Universal: Auto Version Bump / Version Bump (push) Successful in 11s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 9s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 35s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 23s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Project CI / Lint & Validate (pull_request) Successful in 38s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 40s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 43s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 33s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
The preflight ALTER TABLE set element column to DEFAULT '', causing
Joomla to install sub-extension files to plugins/{group}/ root instead
of plugins/{group}/{element}/. This overwrote services/provider.php
across plugins, causing fatal class-not-found errors on every page.
2026-06-21 00:36:00 -05:00
gitea-actions[bot] 2927e7420a chore(version): pre-release bump to 02.46.22-dev [skip ci] 2026-06-21 05:30:44 +00:00
gitea-actions[bot] 1811e080ad chore(version): auto-bump patch 02.46.21-dev [skip ci] 2026-06-21 05:30:29 +00:00
Jonathan Miller d1cc81624f fix(health): add verbose messages to all health checks
Universal: Auto Version Bump / Version Bump (push) Successful in 12s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 26s
Generic: Project CI / Lint & Validate (pull_request) Successful in 33s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 4s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 41s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 36s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 7s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 2s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 11s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 36s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
- Config check: message lists specific issues (Debug ON, Force SSL OFF)
- Security/backup/cron: message explains "Not installed" clearly
- Backup: also checks for MokoSuiteBackup tables, not just Akeeba
- Removed issues array from config — message field replaces it
2026-06-21 00:30:11 -05:00
gitea-actions[bot] 1320a567f8 chore(version): pre-release bump to 02.46.20-dev [skip ci] 2026-06-21 05:07:31 +00:00
gitea-actions[bot] 8d77ca9dd4 chore(version): pre-release bump to 02.46.19-dev [skip ci] 2026-06-21 05:07:09 +00:00
gitea-actions[bot] c31ac0f4bf chore(version): auto-bump patch 02.46.18-dev [skip ci] 2026-06-21 05:06:53 +00:00
Jonathan Miller d97695a858 fix(install): remove backup bridge from package until build is fixed
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 8s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 10s
Universal: PR Check / Validate PR (pull_request) Failing after 8s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 14s
Universal: Auto Version Bump / Version Bump (push) Successful in 14s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 46s
Generic: Project CI / Lint & Validate (pull_request) Successful in 50s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 51s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 53s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 24s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
The backup bridge plugin deploys files to plugins/system/ root instead
of plugins/system/mokosuiteclient_backup/, causing a fatal error on
every page load. Removed from package manifest, enablePlugin, and
protectExtensions until the build pipeline correctly packages it.
2026-06-21 00:06:13 -05:00
gitea-actions[bot] ffbb46f5e8 chore(version): pre-release bump to 02.46.17-dev [skip ci] 2026-06-21 05:01:10 +00:00
gitea-actions[bot] e8dad8541e chore(version): pre-release bump to 02.46.16-dev [skip ci] 2026-06-21 04:59:06 +00:00
gitea-actions[bot] d5cd995a79 chore(version): auto-bump patch 02.46.15-dev [skip ci] 2026-06-21 04:58:53 +00:00
Jonathan Miller ab21d17563 fix(install): skip enablePlugin when plugin files not on disk
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 5s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: Auto Version Bump / Version Bump (push) Successful in 12s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 10s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 22s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 35s
Generic: Project CI / Lint & Validate (pull_request) Successful in 35s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 38s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 40s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 33s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Prevents enabling plugins whose extension record exists in the DB
but whose files were never deployed (e.g. backup bridge when package
build fails). Avoids fatal class-not-found errors on next page load.
2026-06-20 23:58:41 -05:00
gitea-actions[bot] 560035655a chore(version): pre-release bump to 02.46.14-dev [skip ci] 2026-06-21 04:49:35 +00:00
gitea-actions[bot] 3858869b24 chore(version): pre-release bump to 02.46.13-dev [skip ci] 2026-06-21 04:31:52 +00:00
gitea-actions[bot] a053cc8631 chore(version): pre-release bump to 02.46.12-dev [skip ci] 2026-06-21 04:28:22 +00:00
gitea-actions[bot] bfb28a2050 chore(version): auto-bump patch 02.46.11-dev [skip ci] 2026-06-21 04:28:09 +00:00
Jonathan Miller 0067835a17 Merge remote-tracking branch 'origin/dev' into dev
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 7s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 8s
Universal: Auto Version Bump / Version Bump (push) Successful in 13s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 11s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 34s
Generic: Project CI / Lint & Validate (pull_request) Successful in 36s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 21s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 39s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 41s
Generic: Project CI / Tests (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
# Conflicts:
#	source/packages/plg_system_mokosuiteclient_monitor/mokosuiteclient_monitor.xml
2026-06-20 23:27:52 -05:00
Jonathan Miller 62e5cf6fb5 chore: remove retired monitor plugin source files 2026-06-20 23:26:56 -05:00
gitea-actions[bot] e34f52fb23 chore(version): pre-release bump to 02.46.10-dev [skip ci] 2026-06-21 03:15:53 +00:00
gitea-actions[bot] 348aaf1d8b chore(version): pre-release bump to 02.46.09-dev [skip ci] 2026-06-21 03:11:32 +00:00
gitea-actions[bot] b63779a675 chore(version): auto-bump patch 02.46.08-dev [skip ci] 2026-06-21 03:11:19 +00:00
Jonathan Miller aa61834e61 feat(support): show domain as support key in status bar with click-to-copy
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 9s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 13s
Generic: Project CI / Lint & Validate (pull_request) Successful in 16s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: Auto Version Bump / Version Bump (push) Successful in 16s
Universal: PR Check / Validate PR (pull_request) Failing after 7s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 37s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 37s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 19s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 42s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 34s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
Domain is displayed in the status bar next to cache buttons. Click to
copy to clipboard for easy sharing with support agents. HQ looks up
the site by domain.
2026-06-20 22:10:58 -05:00
gitea-actions[bot] 206239ab7d chore(version): pre-release bump to 02.46.07-dev [skip ci] 2026-06-21 03:03:19 +00:00
gitea-actions[bot] d273f2e615 chore(version): auto-bump patch 02.46.06-dev [skip ci] 2026-06-21 03:03:05 +00:00
Jonathan Miller 520422db8c fix(menu): MokoSuiteClient displays as MokoSuite in menu
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 6s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 8s
Universal: Auto Version Bump / Version Bump (push) Successful in 13s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 11s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 22s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 36s
Generic: Project CI / Lint & Validate (pull_request) Successful in 39s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 40s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 42s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
2026-06-20 22:02:48 -05:00
gitea-actions[bot] 035fe6d619 chore(version): pre-release bump to 02.46.05-dev [skip ci] 2026-06-21 02:56:58 +00:00
gitea-actions[bot] 1b316ecc40 chore(version): auto-bump patch 02.46.04-dev [skip ci] 2026-06-21 02:56:39 +00:00
Jonathan Miller 8c21553137 fix(menu): MokoSuiteClient→MokoClient, strip MokoSuite from others
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (push) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (push) Blocked by required conditions
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Blocked by required conditions
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Blocked by required conditions
Joomla: Extension CI / PHPStan Analysis (pull_request) Blocked by required conditions
Joomla: Extension CI / Build RC Pre-Release (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Blocked by required conditions
Platform: moko-platform CI / CI Summary (pull_request) Blocked by required conditions
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Universal: PR Check / Report Issues (pull_request) Blocked by required conditions
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 8s
Generic: Project CI / Lint & Validate (pull_request) Successful in 15s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: Auto Version Bump / Version Bump (push) Successful in 15s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 14s
Universal: PR Check / Validate PR (pull_request) Failing after 7s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 28s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 45s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 47s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 49s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 44s
Generic: Project CI / Tests (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
- HQ and Client keep "Moko" prefix: MokoHQ, MokoClient
- All other extensions drop MokoSuite entirely: Backup, OpenGraph, etc.
- Component menu title changed to MokoClient
2026-06-20 21:56:20 -05:00
Jonathan Miller 76d9fdd944 fix(menu): pin Client below HQ, strip MokoSuite prefix from titles
Menu order: HQ first, Client second, then alphabetical.
Display titles have "MokoSuite" prefix removed for cleaner sidebar.
2026-06-20 21:56:19 -05:00
gitea-actions[bot] d03c479aa4 chore(version): pre-release bump to 02.46.03-dev [skip ci] 2026-06-21 02:19:01 +00:00
gitea-actions[bot] 09153a04c4 chore(version): pre-release bump to 02.46.02-dev [skip ci] 2026-06-21 02:17:55 +00:00
gitea-actions[bot] b6f4b1f505 chore(version): auto-bump patch 02.46.01-dev [skip ci] 2026-06-21 02:17:41 +00:00
Jonathan Miller 7b5231d7f7 Merge remote-tracking branch 'origin/dev' into dev
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (push) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (push) Blocked by required conditions
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Blocked by required conditions
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Blocked by required conditions
Joomla: Extension CI / PHPStan Analysis (pull_request) Blocked by required conditions
Joomla: Extension CI / Build RC Pre-Release (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Blocked by required conditions
Platform: moko-platform CI / CI Summary (pull_request) Blocked by required conditions
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Universal: PR Check / Report Issues (pull_request) Blocked by required conditions
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 6s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 8s
Universal: PR Check / Validate PR (pull_request) Failing after 7s
Universal: Auto Version Bump / Version Bump (push) Successful in 14s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 12s
Generic: Project CI / Lint & Validate (pull_request) Successful in 37s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 37s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 21s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 38s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 41s
Generic: Project CI / Tests (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
2026-06-20 21:17:22 -05:00
Jonathan Miller 56bdcf66ec chore(version): bump to 02.46.00 (above stable 02.45.00)
Dev version must be higher than stable for Joomla updater to show it.
2026-06-20 21:14:49 -05:00
gitea-actions[bot] 29d17dee8f chore(version): pre-release bump to 02.44.09-dev [skip ci] 2026-06-21 02:01:55 +00:00
gitea-actions[bot] d030a5d886 chore(version): pre-release bump to 02.44.08-dev [skip ci] 2026-06-21 01:39:20 +00:00
gitea-actions[bot] 3f0d45438c chore(version): auto-bump patch 02.44.07-dev [skip ci] 2026-06-21 01:39:05 +00:00
Jonathan Miller 64a8504794 feat(support-pin): daily-rotating PIN via HMAC(token, date)
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (push) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (push) Blocked by required conditions
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Blocked by required conditions
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Blocked by required conditions
Joomla: Extension CI / PHPStan Analysis (pull_request) Blocked by required conditions
Joomla: Extension CI / Build RC Pre-Release (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Blocked by required conditions
Platform: moko-platform CI / CI Summary (pull_request) Blocked by required conditions
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Universal: PR Check / Report Issues (pull_request) Blocked by required conditions
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 6s
Universal: PR Check / Branch Policy (pull_request) Successful in 3s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 11s
Universal: Auto Version Bump / Version Bump (push) Successful in 12s
Generic: Project CI / Lint & Validate (pull_request) Successful in 14s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 22s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 36s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 36s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 39s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 35s
Generic: Project CI / Tests (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
PIN is derived from HMAC-SHA256(health_api_token, YYYY-MM-DD) so both
client and HQ compute the same value independently. Rotates at UTC
midnight. Shown on cpanel module header and component dashboard.
2026-06-20 20:38:51 -05:00
gitea-actions[bot] 9e22a4c49c chore(version): pre-release bump to 02.44.06-dev [skip ci] 2026-06-21 01:31:32 +00:00
gitea-actions[bot] 1ab721cbe3 chore(version): auto-bump patch 02.44.05-dev [skip ci] 2026-06-21 01:31:15 +00:00
Jonathan Miller 6bb1b43195 feat: MokoGitea LicenseValidator — core DRM enforcement, cache table, task scheduler
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (push) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (push) Blocked by required conditions
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Blocked by required conditions
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Blocked by required conditions
Joomla: Extension CI / PHPStan Analysis (pull_request) Blocked by required conditions
Joomla: Extension CI / Build RC Pre-Release (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Blocked by required conditions
Platform: moko-platform CI / CI Summary (pull_request) Blocked by required conditions
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Universal: PR Check / Report Issues (pull_request) Blocked by required conditions
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 7s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 13s
Universal: Auto Version Bump / Version Bump (push) Successful in 16s
Generic: Project CI / Lint & Validate (pull_request) Successful in 16s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Failing after 7s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 25s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 42s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 46s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 50s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 41s
Generic: Project CI / Tests (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
2026-06-20 20:30:57 -05:00
gitea-actions[bot] 5a5a5713d6 chore(version): auto-bump patch 02.44.04-dev [skip ci] 2026-06-21 00:39:06 +00:00
Jonathan Miller e55acc464a Merge remote-tracking branch 'origin/dev' into rc
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (push) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (push) Blocked by required conditions
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Blocked by required conditions
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Blocked by required conditions
Joomla: Extension CI / PHPStan Analysis (pull_request) Blocked by required conditions
Joomla: Extension CI / Build RC Pre-Release (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Blocked by required conditions
Platform: moko-platform CI / CI Summary (pull_request) Blocked by required conditions
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Universal: PR Check / Report Issues (pull_request) Blocked by required conditions
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 5s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 8s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 35s
Generic: Project CI / Lint & Validate (pull_request) Successful in 35s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 1s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 36s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 38s
Universal: Auto Version Bump / Version Bump (push) Successful in 12s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Failing after 9s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 32s
Generic: Project CI / Tests (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
2026-06-20 19:38:22 -05:00
Jonathan Miller 6ed0a9f221 Merge remote-tracking branch 'origin/rc' into rc 2026-06-20 19:38:21 -05:00
Jonathan Miller 072297a75d fix(cpanel): always start collapsed, remove setting
Cpanel module is always collapsed by default. Removed the collapsed
toggle from module settings since it should not be configurable.
2026-06-20 19:37:36 -05:00
gitea-actions[bot] c0adfe41dd chore(version): auto-bump patch 02.44.03-dev [skip ci] 2026-06-21 00:15:31 +00:00
Jonathan Miller 579b0f13d8 Merge remote-tracking branch 'origin/dev' into rc
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Blocked by required conditions
Platform: moko-platform CI / CI Summary (pull_request) Blocked by required conditions
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Universal: PR Check / Report Issues (pull_request) Blocked by required conditions
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 6s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 8s
Universal: PR Check / Validate PR (pull_request) Failing after 7s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: Auto Version Bump / Version Bump (push) Successful in 13s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 12s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Failing after 13s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 40s
Generic: Project CI / Lint & Validate (pull_request) Successful in 42s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 45s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 46s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
2026-06-20 19:15:05 -05:00
gitea-actions[bot] 2b7913f6e1 chore(version): auto-bump patch 02.44.03-rc [skip ci] 2026-06-21 00:14:51 +00:00
Jonathan Miller 07482df7b9 Merge remote-tracking branch 'origin/rc' into rc
Universal: Auto Version Bump / Version Bump (push) Successful in 8s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Failing after 9s
2026-06-20 19:14:37 -05:00
Jonathan Miller 61f96cba64 fix(menu): pin com_mokosuitehq at top of sidebar menu
The element name is com_mokosuitehq not com_mokosuiteclienthq.
The sort logic was checking the wrong name so HQ was never pinned.
2026-06-20 19:12:59 -05:00
Jonathan Miller 71f5d161e9 style(menu): simplify sidebar child item indent 2026-06-20 19:05:38 -05:00
gitea-actions[bot] 2db043412f chore(version): auto-bump patch 02.44.02-dev [skip ci] 2026-06-20 23:55:31 +00:00
Jonathan Miller c913f12621 Merge remote-tracking branch 'origin/dev' into rc
Generic: Project CI / Lint & Validate (pull_request) Failing after 3s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 6s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 7s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Universal: Auto Version Bump / Version Bump (push) Successful in 12s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Failing after 11s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 35s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 37s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 42s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 39s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
2026-06-20 18:55:13 -05:00
gitea-actions[bot] 772c40bb56 chore(version): auto-bump patch 02.44.02-rc [skip ci] 2026-06-20 23:54:29 +00:00
Jonathan Miller 49cc5becf6 fix(heartbeat): show success/error notification to admin on install/update
Universal: Auto Version Bump / Version Bump (push) Successful in 8s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Failing after 8s
Both install-time and runtime heartbeat now enqueue visible messages
for all outcomes — success, HTTP error, and connection failure — so
the admin always knows whether the heartbeat registered.
2026-06-20 18:54:17 -05:00
gitea-actions[bot] 738c878067 chore(version): auto-bump patch 02.44.01-dev [skip ci] 2026-06-20 23:37:52 +00:00
gitea-actions[bot] aa5f3ab06a chore(version): auto-bump patch 02.44.01-rc [skip ci] 2026-06-20 23:34:46 +00:00
Jonathan Miller 9326e2d11a fix(heartbeat): rotate RSA keys, fix backup bridge StatusHelper path
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 6s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 9s
Universal: Auto Version Bump / Version Bump (push) Successful in 13s
Generic: Project CI / Lint & Validate (pull_request) Successful in 13s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Failing after 10s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 31s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 30s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 33s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 29s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
- Replace broken RSA key pair (had Windows \r\n line endings in PEM)
  with fresh Unix-style keys that pass OpenSSL verify
- Fix backup bridge: use correct Helper\BackupStatusHelper path and
  getStatusSummary() method per MokoSuite convention
- Align fallback query output with StatusHelper return format
  (latest/totals structure instead of flat keys)
2026-06-20 18:34:13 -05:00
jmiller b78987733c chore: sync repo-health.yml from Template-Generic [skip ci]
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Branch Cleanup / Delete merged branch (pull_request) Failing after 2s
Universal: Build & Release / Promote to RC (pull_request) Has been skipped
Universal: Build & Release / Build & Release Pipeline (pull_request) Successful in 19s
Universal: Workflow Sync Trigger / Sync workflows to live repos (pull_request) Failing after 2m22s
2026-06-20 18:06:02 -05:00
jmiller 585b02811e chore: sync rc-revert.yml from Template-Generic [skip ci] 2026-06-20 18:06:01 -05:00
jmiller 3abece1399 chore: sync pr-check.yml from Template-Generic [skip ci] 2026-06-20 18:06:01 -05:00
jmiller 55b4b54908 chore: sync cleanup.yml from Template-Generic [skip ci] 2026-06-20 18:06:01 -05:00
jmiller b5b382000e ci: sync security-audit.yml from Template-Joomla [skip ci] 2026-06-20 18:06:00 -05:00
jmiller 452913f2d8 ci: sync repo-health.yml from Template-Joomla [skip ci] 2026-06-20 18:06:00 -05:00
jmiller 250bfb06f8 ci: sync rc-revert.yml from Template-Joomla [skip ci] 2026-06-20 18:05:59 -05:00
jmiller 5c4e59b9ac ci: sync pr-check.yml from Template-Joomla [skip ci] 2026-06-20 18:05:59 -05:00
jmiller d85c36fe3b ci: sync issue-branch.yml from Template-Joomla [skip ci] 2026-06-20 18:05:59 -05:00
jmiller 0482407013 ci: sync cleanup.yml from Template-Joomla [skip ci] 2026-06-20 18:05:58 -05:00
jmiller a3a6fdba4d chore: sync issue-branch.yml from Template-Generic [skip ci] 2026-06-20 18:05:58 -05:00
jmiller 4074e08107 chore: sync ci-generic.yml from Template-Generic [skip ci] 2026-06-20 18:05:58 -05:00
jmiller 96b5930761 ci: sync ci-generic.yml from Template-Joomla [skip ci] 2026-06-20 18:05:57 -05:00
jmiller 30e91810c7 ci: sync cascade-dev.yml from Template-Joomla [skip ci] 2026-06-20 18:05:57 -05:00
jmiller b6b412de84 ci: sync branch-cleanup.yml from Template-Joomla [skip ci] 2026-06-20 18:05:56 -05:00
jmiller 50a3056f1e ci: sync auto-release.yml from Template-Joomla [skip ci] 2026-06-20 18:05:56 -05:00
gitea-actions[bot] 7ba6e2e709 chore: promote changelog [Unreleased] → [02.44.00] 2026-06-20 18:05:56 -05:00
gitea-actions[bot] e1e65b77b5 chore(release): build 02.44.00 [skip ci] 2026-06-20 18:05:55 -05:00
jmiller 75bddcd688 chore: sync workflow-sync-trigger.yml from Template-Generic [skip ci] 2026-06-20 18:05:54 -05:00
jmiller 928bfbe8ff chore: sync issue-branch.yml from Template-Generic [skip ci] 2026-06-20 18:05:53 -05:00
gitea-actions[bot] db299f70a5 chore: promote changelog [Unreleased] → [02.43.00] 2026-06-20 18:05:53 -05:00
gitea-actions[bot] b64c6f57f6 chore(release): build 02.43.00 [skip ci] 2026-06-20 18:05:52 -05:00
jmiller db9d33b46d ci: sync ci-generic.yml from Template-Joomla [skip ci] 2026-06-20 18:05:50 -05:00
gitea-actions[bot] 17438477f9 chore: promote changelog [Unreleased] → [02.42.00] 2026-06-20 18:05:50 -05:00
gitea-actions[bot] 970f362378 chore(release): build 02.42.00 [skip ci] 2026-06-20 18:05:49 -05:00
jmiller 350b3c5f29 ci: sync cascade-dev.yml from Template-Joomla [skip ci] 2026-06-20 18:05:48 -05:00
jmiller 045f7fbb31 ci: sync branch-cleanup.yml from Template-Joomla [skip ci] 2026-06-20 18:05:48 -05:00
jmiller 5fa639acd1 ci: sync auto-release.yml from Template-Joomla [skip ci] 2026-06-20 18:05:47 -05:00
gitea-actions[bot] 5ae2b7590d chore(version): auto-bump patch 02.41.02-rc [skip ci] 2026-06-20 22:54:48 +00:00
Jonathan Miller 0e03837ec9 fix(heartbeat): align signature headers with HQ expectations
Universal: Auto Version Bump / Version Bump (push) Successful in 8s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Failing after 8s
Rename X-MokoSuiteClient-Signature/Timestamp to X-MokoSuite-Signature/
Timestamp to match what HeartbeatController reads as HTTP_X_MOKOSUITE_*.
2026-06-20 17:53:54 -05:00
Jonathan Miller 7510c9f018 fix(heartbeat): correct API route from mokosuiteclienthq to mokosuitehq
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 7s
Generic: Project CI / Lint & Validate (pull_request) Successful in 17s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 7s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Failing after 7s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Branch Cleanup / Delete merged branch (pull_request) Failing after 2s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 13s
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 53s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 53s
Universal: Auto Version Bump / Version Bump (push) Successful in 12s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Failing after 10s
Universal: Build & Release / Promote to RC (pull_request) Has been skipped
Universal: Build & Release / Build & Release Pipeline (pull_request) Successful in 20s
Universal: Workflow Sync Trigger / Sync workflows to live repos (pull_request) Failing after 5m50s
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
The HQ component is com_mokosuitehq, not com_mokosuiteclienthq.
The heartbeat endpoint was returning 404 because the route prefix
was wrong.
2026-06-20 15:52:01 -05:00
Jonathan Miller 62a5828634 Merge remote-tracking branch 'origin/rc' into rc
Universal: Auto Version Bump / Version Bump (push) Successful in 8s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Failing after 8s
2026-06-20 15:31:58 -05:00
Jonathan Miller 617f9e7b3e Merge remote-tracking branch 'origin/main' into rc 2026-06-20 15:19:57 -05:00
gitea-actions[bot] 55df3a8c7c chore(version): auto-bump patch 02.41.01-rc [skip ci] 2026-06-20 20:04:37 +00:00
Jonathan Miller 0dcd27cece fix: update heartbeat URL from waas.dev to suite.dev.mokoconsulting.tech
Universal: Auto Version Bump / Version Bump (push) Successful in 40s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Failing after 23s
Domain was renamed — heartbeat was silently failing because the old
hostname no longer resolves.
2026-06-20 15:03:49 -05:00
jmiller 7f3c2b1021 ci: sync auto-bump.yml from Template-Joomla [skip ci] 2026-06-20 19:59:07 +00:00
jmiller d56f1485fc ci: sync ci-generic.yml from Template-Joomla [skip ci] 2026-06-20 19:05:58 +00:00
gitea-actions[bot] 13bccc041a chore: promote changelog [Unreleased] → [02.42.00]
Generic: Project CI / Lint & Validate (push) Successful in 9s
Generic: Project CI / Tests (push) Has been cancelled
2026-06-20 19:05:27 +00:00
gitea-actions[bot] cb50f0360c chore(release): build 02.42.00 [skip ci] 2026-06-20 19:05:21 +00:00
jmiller 0f92612188 ci: sync cascade-dev.yml from Template-Joomla [skip ci] 2026-06-20 19:03:17 +00:00
jmiller f971d10344 ci: sync branch-cleanup.yml from Template-Joomla [skip ci] 2026-06-20 19:02:44 +00:00
jmiller 119cf4575d ci: sync auto-release.yml from Template-Joomla [skip ci] 2026-06-20 19:01:03 +00:00
jmiller 81415b07ed ci: sync auto-bump.yml from Template-Joomla [skip ci] 2026-06-20 18:53:49 +00:00
jmiller a6f8b25c33 ci: sync pre-release workflow from Template-Joomla
Generic: Project CI / Lint & Validate (push) Successful in 14s
Generic: Project CI / Tests (push) Has been cancelled
2026-06-20 18:49:28 +00:00
jmiller ac99f85732 ci: add Joomla metadata validation workflow for PRs
Generic: Project CI / Lint & Validate (push) Successful in 12s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 35s
Generic: Project CI / Tests (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
2026-06-20 18:39:06 +00:00
jmiller 1fa3cb80be Merge pull request 'fix(install): enable ticket/offline plugins, consolidate monitor into core' (#218) from rc into main
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Failing after 17s
Generic: Project CI / Lint & Validate (push) Successful in 13s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 6s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Generic: Project CI / Lint & Validate (pull_request) Successful in 14s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 12s
Universal: PR Check / Validate PR (pull_request) Failing after 8s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 39s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 48s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 52s
Universal: Auto Version Bump / Version Bump (push) Has been skipped
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
Generic: Project CI / Tests (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
2026-06-20 17:25:53 +00:00
Jonathan Miller 1d7ea1a2cc Merge remote-tracking branch 'origin/main' into rc
Universal: Auto Version Bump / Version Bump (push) Failing after 12s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Failing after 14s
Universal: Build & Release / Promote to RC (pull_request) Has been skipped
Universal: Build & Release / Build & Release Pipeline (pull_request) Failing after 16s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 5s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 5s
Generic: Project CI / Lint & Validate (pull_request) Successful in 12s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 6s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 4s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Branch Cleanup / Delete merged branch (pull_request) Successful in 1s
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 29s
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
2026-06-20 12:24:59 -05:00
jmiller bd5bd8476c fix: rename moko-platform to mokocli + changelog promotion in workflows
Generic: Project CI / Lint & Validate (push) Successful in 27s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 34s
Generic: Project CI / Tests (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
2026-06-20 17:15:51 +00:00
jmiller 61b4963e2d fix: rename moko-platform to mokocli + changelog promotion in workflows
Generic: Project CI / Lint & Validate (push) Successful in 10s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 32s
Generic: Project CI / Tests (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
2026-06-20 17:15:50 +00:00
jmiller 21168193e1 fix: rename moko-platform to mokocli + changelog promotion in workflows
Generic: Project CI / Lint & Validate (push) Successful in 32s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 37s
Generic: Project CI / Tests (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
2026-06-20 17:15:50 +00:00
jmiller cfc2778d95 fix: rename moko-platform to mokocli + changelog promotion in workflows
Generic: Project CI / Lint & Validate (push) Successful in 10s
Generic: Repo Health / Access control (push) Successful in 2s
Generic: Repo Health / Site Health (push) Has been skipped
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 38s
Generic: Project CI / Tests (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
2026-06-20 17:15:49 +00:00
jmiller 8365093fc3 fix: rename moko-platform to mokocli + changelog promotion in workflows
Generic: Project CI / Lint & Validate (push) Successful in 10s
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 2s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 37s
Generic: Project CI / Tests (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
2026-06-20 17:15:48 +00:00
jmiller 8a2b59865f fix: rename moko-platform to mokocli + changelog promotion in workflows
Generic: Project CI / Lint & Validate (push) Successful in 10s
Generic: Repo Health / Access control (push) Successful in 1s
Generic: Repo Health / Site Health (push) Has been skipped
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 32s
Generic: Project CI / Tests (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
2026-06-20 17:15:48 +00:00
Jonathan Miller 7e6699479f fix(install): enable and protect backup bridge plugin on install
Generic: Repo Health / Access control (push) Successful in 1s
Generic: Repo Health / Site Health (push) Has been skipped
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 4s
Universal: Auto Version Bump / Version Bump (push) Failing after 10s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 7s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || 'development' }}) (pull_request_target) Failing after 13s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Project CI / Lint & Validate (pull_request) Successful in 49s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 47s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 49s
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
Add mokosuiteclient_backup to enablePlugin() and protectExtensions()
lists so the backup bridge plugin is enabled on install/update and
cannot be accidentally disabled by admins.
2026-06-20 12:15:14 -05:00
Jonathan Miller bc60161e16 Merge remote-tracking branch 'origin/dev' into rc
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 4s
Generic: Repo Health / Access control (push) Successful in 1s
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Project CI / Lint & Validate (push) Successful in 12s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 7s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: Auto Version Bump / Version Bump (push) Failing after 11s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || 'development' }}) (pull_request_target) Failing after 11s
Generic: Project CI / Lint & Validate (pull_request) Successful in 39s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 33s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 41s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 44s
Generic: Project CI / Tests (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
# Conflicts:
#	source/packages/plg_task_mokosuiteclientdemo/mokosuiteclientdemo.xml
#	source/packages/plg_task_mokosuiteclientsync/mokosuiteclientsync.xml
2026-06-20 11:59:38 -05:00
Jonathan Miller fb52d3ed53 fix(heartbeat): add diagnostic logging to all bail-out points
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 6s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 6s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Universal: Auto Version Bump / Version Bump (push) Failing after 10s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || 'development' }}) (pull_request_target) Failing after 9s
Generic: Project CI / Lint & Validate (pull_request) Successful in 27s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 29s
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
Log reason when sendHeartbeat() exits early: missing params, empty
health token, or unconfigured base URL. Helps diagnose why heartbeat
doesn't reach MokoSuiteClientHQ after install/update.
2026-06-20 11:54:24 -05:00
Jonathan Miller f8c70f2bef fix(install): migrate monitor params before retiring the plugin
Generic: Repo Health / Access control (push) Successful in 1s
Generic: Repo Health / Site Health (push) Has been skipped
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 4s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 5s
Universal: Auto Version Bump / Version Bump (push) Failing after 7s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 5s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || 'development' }}) (pull_request_target) Failing after 9s
Universal: PR Check / Validate PR (pull_request) Failing after 3s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Project CI / Lint & Validate (pull_request) Successful in 25s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 27s
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
Move migrateMonitorParams() before removeRetiredExtensions() so the
monitor plugin's params (base_url, signing_key) are copied to the
core plugin before the monitor row is deleted from #__extensions.
2026-06-20 11:50:53 -05:00
Jonathan Miller f1d483aa38 fix(heartbeat): add error logging, fix params persistence race
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 7s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 6s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: PR Check / Validate PR (pull_request) Failing after 4s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 49s
Generic: Project CI / Lint & Validate (pull_request) Successful in 50s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 53s
Universal: Auto Version Bump / Version Bump (push) Failing after 8s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || 'development' }}) (pull_request_target) Failing after 7s
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
- Add Log::add() to empty catch blocks in sendHeartbeat(), checkHeartbeat(),
  and fetchLocalHealth() so failures are diagnosable
- Add curl_error() check and non-2xx logging to script.php sendHeartbeat()
- Replace $extension->store() with targeted DB update in checkHeartbeat()
  to avoid overwriting params modified by migrateMonitorParams()
2026-06-20 11:40:17 -05:00
gitea-actions[bot] 99f0901fd2 chore(release): build 02.41.00-rc [skip ci] 2026-06-20 16:38:27 +00:00
Jonathan Miller 6dcacfb6cc Merge remote-tracking branch 'origin/main' into rc
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 2s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 8s
Generic: Project CI / Lint & Validate (pull_request) Successful in 19s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 11s
Universal: PR Check / Validate PR (pull_request) Failing after 11s
Generic: Repo Health / Access control (pull_request) Successful in 3s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 59s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 49s
Universal: Auto Version Bump / Version Bump (push) Failing after 6s
Universal: Build & Release / Promote to RC (pull_request) Successful in 12s
Universal: Build & Release / Build & Release Pipeline (pull_request) Has been skipped
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || 'development' }}) (pull_request_target) Failing after 9s
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
# Conflicts:
#	.mokogitea/manifest.xml
#	src/packages/com_mokowaas/mokowaas.xml
#	src/packages/plg_system_mokowaas/Extension/MokoWaaS.php
#	src/packages/plg_system_mokowaas/Field/AllowedIpsField.php
#	src/packages/plg_system_mokowaas/Field/CurrentIpField.php
#	src/packages/plg_system_mokowaas/Field/DemoTaskInfoField.php
#	src/packages/plg_system_mokowaas/Field/NextResetField.php
#	src/packages/plg_system_mokowaas/Field/SnapshotTablesField.php
#	src/packages/plg_system_mokowaas/mokowaas.xml
2026-06-20 10:59:08 -05:00
Jonathan Miller 72134bba28 fix(install): enable ticket/offline plugins, consolidate monitor into core
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Universal: Auto Version Bump / Version Bump (push) Successful in 10s
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
- enablePlugin() handles empty element columns with fallback match by name
- Retire monitor plugin: migrate config (base_url, signing_key) to core
- Runtime heartbeat moved from monitor plugin to core plugin
- DisplayController heartbeat reads from core plugin params
- ensureAdminModule() direct DB update for existing modules (fixes
  checked_out blocking, cpanel access level 6→3, menu ordering -1)
- Add missing ticket automation language strings (IMAP, autoclose)
- Remove monitor from cpanel plugin grid
2026-06-20 10:33:01 -05:00
gitea-actions[bot] 29c58a9400 chore(release): build 02.35.00 [skip ci] 2026-06-19 07:15:04 +00:00
jmiller cddfbe5256 Merge pull request 'fix: remove deprecated .mokogitea/manifest.xml' (#217) from fix into main
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 2s
Generic: Project CI / Lint & Validate (push) Successful in 37s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 41s
Generic: Project CI / Tests (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
2026-06-19 07:08:57 +00:00
Jonathan Miller d692db4a69 fix: remove deprecated .mokogitea/manifest.xml — metadata managed via API
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 2s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 5s
Generic: Project CI / Lint & Validate (pull_request) Successful in 11s
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 5s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 9s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 46s
Branch Cleanup / Delete merged branch (pull_request) Failing after 2s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || 'development' }}) (pull_request_target) Failing after 8s
Universal: Build & Release / Promote to RC (pull_request) Has been skipped
Universal: Build & Release / Build & Release Pipeline (pull_request) Successful in 8s
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
2026-06-19 02:04:36 -05:00
jmiller 888f37c334 fix(ci): detect rebuild by branch name not version suffix [skip ci] 2026-06-19 01:51:59 +00:00
jmiller 87d62f00e3 fix(ci): detect rebuild by branch name not version suffix [skip ci] 2026-06-19 01:51:34 +00:00
Jonathan Miller c1696bce41 fix(ci): detect rebuild by branch name not version suffix [skip ci] 2026-06-18 20:35:27 -05:00
gitea-actions[bot] 17d66fcf1e chore(version): pre-release bump to 02.40.00-rc [skip ci] 2026-06-19 01:14:34 +00:00
jmiller 74361a4124 ci: patch bump on same-branch rebuilds, minor only on elevation [skip ci] 2026-06-19 00:40:39 +00:00
jmiller ab163dfe06 ci: patch bump on same-branch rebuilds, minor only on elevation [skip ci] 2026-06-19 00:18:33 +00:00
jmiller 6592b5459c ci: patch bump on same-branch rebuilds, minor only on elevation [skip ci] 2026-06-19 00:18:01 +00:00
Jonathan Miller 30d9e1a108 ci: patch bump on same-branch rebuilds, minor only on elevation [skip ci]
RC rebuilds on the rc branch now get patch bumps (02.37.00-rc →
02.37.01-rc) instead of minor bumps. Minor bumps only happen on
branch elevations (dev→rc, rc→stable).
2026-06-18 19:13:32 -05:00
gitea-actions[bot] fab6572777 chore(version): pre-release bump to 02.39.00-rc [skip ci] 2026-06-19 00:11:34 +00:00
Jonathan Miller bf30c3db5b fix(api): type-safe update, filtered pagination, status sync, int cast assign
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 2s
Universal: Auto Version Bump / Version Bump (push) Successful in 8s
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
- API update() now uses getInt/getString instead of raw input
- API update() syncs status/status_id and priority/priority_id
- API update() returns 404 if ticket not found
- Pagination total count now uses filtered query (was unfiltered)
- AutomationEngine assign action casts value to int
2026-06-18 19:09:42 -05:00
Jonathan Miller 134b9b3693 fix(security+reliability): address PR review — ACL guards, error logging, path traversal
Generic: Repo Health / Access control (push) Successful in 2s
Generic: Repo Health / Site Health (push) Has been skipped
Universal: Auto Version Bump / Version Bump (push) Successful in 9s
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
Security:
- Add return after all jsonForbidden() calls (13 methods) to prevent
  ACL bypass if $app->close() fails to terminate
- Add throw after requireAuth() in REST API controller (same pattern)
- Add path traversal guard to AttachmentService::getAbsolutePath()
  using realpath + prefix check

Error handling:
- Log install notification email failures instead of empty catch
- Log DB errors in getUserEmail(), getNotificationConfig(),
  getComponentConfig() instead of silent fallbacks
- Log PHP upload error codes in AttachmentService
- Check Folder::create() return value before upload loop
- Fix searchKb() missing return on short query + log DB errors
- Fix ntfy push to capture curl_error() on connection failure
- Upgrade AutomationEngine inner catch to LOG_ERROR with rule ID
2026-06-18 19:05:57 -05:00
gitea-actions[bot] ccb76132a5 chore(version): pre-release bump to 02.38.00-rc [skip ci] 2026-06-18 20:52:35 +00:00
Jonathan Miller c8a267eed0 chore: remove legacy src/ directory (pre-rename MokoWaaS code) [skip ci] 2026-06-18 15:50:39 -05:00
Jonathan Miller 6c1ab6607b fix: rename installer class Pkg_Mokosuite → Pkg_Mokosuiteclient [skip ci] 2026-06-18 15:09:03 -05:00
Jonathan Miller c2c2f40147 fix: set EXTENSION_NAME=mokosuiteclient in Makefile for updates.xml [skip ci] 2026-06-18 14:57:56 -05:00
gitea-actions[bot] bd39fb487c chore(version): pre-release bump to 02.37.00-rc [skip ci] 2026-06-18 17:54:58 +00:00
Jonathan Miller 2e00512741 fix: rename all language keys MOKOSUITE→MOKOSUITECLIENT, auto-enable monitor plugin
Generic: Repo Health / Access control (push) Successful in 1s
Generic: Repo Health / Site Health (push) Has been skipped
Universal: Auto Version Bump / Version Bump (push) Successful in 7s
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
- XML manifests used old PLG_SYSTEM_MOKOSUITE_ / MOD_MOKOSUITE_ / COM_MOKOSUITE_
  prefixes that didn't match the INI files (PLG_SYSTEM_MOKOSUITECLIENT_ etc.),
  causing untranslated labels in admin UI
- Also fixed PLG_TASK_MOKOSUITEDEMO/SYNC and DBIP language keys
- Added mokosuiteclient_monitor to auto-enable list in package install script
  so heartbeat registration works on fresh install
2026-06-18 12:47:50 -05:00
Jonathan Miller 823d2e4f0e ci: add changelog extraction to promote-rc job in auto-release [skip ci] 2026-06-18 12:15:32 -05:00
gitea-actions[bot] 42d4f6e553 chore(version): pre-release bump to 02.36.00-rc [skip ci] 2026-06-18 15:45:07 +00:00
Jonathan Miller b8dfd500e4 fix: swap demo/sync plugin manifests — contents were in wrong files
Generic: Repo Health / Access control (push) Successful in 1s
Generic: Repo Health / Site Health (push) Has been skipped
Universal: Auto Version Bump / Version Bump (push) Successful in 7s
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
2026-06-18 10:44:46 -05:00
gitea-actions[bot] ca37dc9cbd chore(release): build 02.35.00-rc [skip ci] 2026-06-18 15:00:02 +00:00
jmiller f22c8d8575 ci: deploy full pre-release workflow from mokoplatform [skip ci] 2026-06-18 13:47:53 +00:00
jmiller b89ae8cef5 revert: re-enable auto-bump on dev push [skip ci] 2026-06-17 04:46:08 +00:00
jmiller 2ce9847ac5 ci: disable auto-bump on push to dev [skip ci] 2026-06-16 18:21:12 +00:00
145 changed files with 5817 additions and 14526 deletions
+1 -2
View File
@@ -38,7 +38,7 @@ Joomla **package** (`pkg_mokosuiteclient`) with 17 sub-extensions:
### Component (`com_mokosuiteclient`)
- Admin dashboard with plugin management, WAF charts, extension catalog
- Helpdesk ticketing system
- Content tools: snippets, templates, replacements, conditions, articles anywhere, users anywhere
- REST API controllers
### Modules
@@ -50,7 +50,6 @@ Joomla **package** (`pkg_mokosuiteclient`) with 17 sub-extensions:
### Task Plugins
- `plg_task_mokosuiteclientdemo` — scheduled demo site reset
- `plg_task_mokosuiteclientsync` — scheduled content sync
- `plg_task_mokosuiteclient_tickets` — ticket automation
### Update Server
-26
View File
@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Moko Platform Repository Manifest
See: https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home
-->
<moko-platform xmlns="https://standards.mokoconsulting.tech/moko-platform/1.0" schema-version="1.0">
<identity>
<name>MokoSuiteClient</name>
<display-name>Package - MokoSuiteClient</display-name>
<org>MokoConsulting</org>
<description>White-label identity, security hardening, and tenant restriction layer for Suite-managed Joomla environments</description>
<version>02.34.84</version>
<license spdx="GPL-3.0-or-later">GNU General Public License v3</license>
</identity>
<governance>
<platform>joomla</platform>
<standards-version>05.00.00</standards-version>
<standards-source>https://git.mokoconsulting.tech/MokoConsulting/moko-platform</standards-source>
<last-synced>2026-05-28T20:00:00+00:00</last-synced>
</governance>
<build>
<language>PHP</language>
<package-type>package</package-type>
<entry-point>source/</entry-point>
</build>
</moko-platform>
+66 -66
View File
@@ -1,66 +1,66 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: mokoplatform.Release
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform
# PATH: /.mokogitea/workflows/auto-bump.yml
# VERSION: 09.02.00
# BRIEF: Auto patch-bump version on every push to dev (skips merge commits)
name: "Universal: Auto Version Bump"
on:
push:
branches:
- dev
- rc
- 'feature/**'
- 'patch/**'
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
permissions:
contents: write
jobs:
bump:
name: Version Bump
runs-on: release
if: >-
!contains(github.event.head_commit.message, '[skip ci]') &&
!contains(github.event.head_commit.message, '[skip bump]') &&
!startsWith(github.event.head_commit.message, 'Merge pull request')
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
token: ${{ secrets.MOKOGITEA_TOKEN }}
fetch-depth: 1
- name: Setup mokoplatform tools
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
if [ -d "/opt/mokoplatform/cli" ]; then
echo "MOKO_CLI=/opt/mokoplatform/cli" >> "$GITHUB_ENV"
else
git clone --depth 1 --branch main --quiet \
"https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/MokoConsulting/mokoplatform.git" \
/tmp/mokoplatform-api
cd /tmp/mokoplatform-api && composer install --no-dev --no-interaction --quiet
echo "MOKO_CLI=/tmp/mokoplatform-api/cli" >> "$GITHUB_ENV"
fi
- name: Bump version
run: |
php ${MOKO_CLI}/version_auto_bump.php \
--path . --branch "${GITHUB_REF_NAME}" \
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
--repo-url "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: mokocli.Release
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
# PATH: /.mokogitea/workflows/auto-bump.yml
# VERSION: 09.02.00
# BRIEF: Auto patch-bump version on every push to dev (skips merge commits)
name: "Universal: Auto Version Bump"
on:
push:
branches:
- dev
- rc
- 'feature/**'
- 'patch/**'
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
permissions:
contents: write
jobs:
bump:
name: Version Bump
runs-on: release
if: >-
!contains(github.event.head_commit.message, '[skip ci]') &&
!contains(github.event.head_commit.message, '[skip bump]') &&
!startsWith(github.event.head_commit.message, 'Merge pull request')
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
token: ${{ secrets.MOKOGITEA_TOKEN }}
fetch-depth: 1
- name: Setup mokocli tools
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
if [ -d "/opt/mokocli/cli" ]; then
echo "MOKO_CLI=/opt/mokocli/cli" >> "$GITHUB_ENV"
else
git clone --depth 1 --branch main --quiet \
"https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/MokoConsulting/mokocli.git" \
/tmp/mokocli
cd /tmp/mokocli && composer install --no-dev --no-interaction --quiet
echo "MOKO_CLI=/tmp/mokocli/cli" >> "$GITHUB_ENV"
fi
- name: Bump version
run: |
php ${MOKO_CLI}/version_auto_bump.php \
--path . --branch "${GITHUB_REF_NAME}" \
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
--repo-url "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
+65 -34
View File
@@ -4,8 +4,8 @@
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.Release
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/moko-platform
# INGROUP: mokocli.Release
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/mokocli
# PATH: /templates/workflows/universal/auto-release.yml.template
# VERSION: 05.00.00
# BRIEF: Universal build & release detects platform from manifest.xml
@@ -66,25 +66,25 @@ jobs:
token: ${{ secrets.MOKOGITEA_TOKEN }}
fetch-depth: 1
- name: Setup moko-platform tools
- name: Setup mokocli tools
env:
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
run: |
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
if [ -f /opt/mokocli/cli/version_bump.php ] && [ -f /opt/mokocli/vendor/autoload.php ]; then
echo Using pre-installed /opt/mokocli
echo MOKO_CLI=/opt/mokocli/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
rm -rf /tmp/mokocli
CLONE_URL=https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/mokocli.git
git clone --depth 1 --branch main --quiet $CLONE_URL /tmp/mokocli
cd /tmp/mokocli
composer install --no-dev --no-interaction --quiet
echo MOKO_CLI=/tmp/moko-platform-api/cli >> $GITHUB_ENV
echo MOKO_CLI=/tmp/mokocli/cli >> $GITHUB_ENV
fi
- name: Rename branch to rc
@@ -112,16 +112,19 @@ jobs:
- name: Update RC release notes from CHANGELOG.md
run: |
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
# Extract [Unreleased] section from changelog
NOTES=""
if [ -f "CHANGELOG.md" ]; then
NOTES=$(awk '/^## \[Unreleased\]/{found=1; next} /^## \[/{if(found) exit} found{print}' CHANGELOG.md)
[ -z "$NOTES" ] && NOTES="Release candidate"
else
NOTES="Release candidate"
fi
[ -z "$NOTES" ] && NOTES="Release candidate"
RELEASE_ID=$(curl -sf -H "Authorization: token ${{ secrets.MOKOGITEA_TOKEN }}" \
"${API_BASE}/releases/tags/release-candidate" | python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
# Find the RC release and update its body
RELEASE_ID=$(curl -sf -H "Authorization: token ${TOKEN}" \
"${API_BASE}/releases/tags/release-candidate" \
| python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
if [ -n "$RELEASE_ID" ]; then
python3 -c "
@@ -132,7 +135,7 @@ jobs:
'${API_BASE}/releases/${RELEASE_ID}',
data=payload, method='PATCH',
headers={
'Authorization': 'token ${{ secrets.MOKOGITEA_TOKEN }}',
'Authorization': 'token ${TOKEN}',
'Content-Type': 'application/json'
})
urllib.request.urlopen(req)
@@ -180,26 +183,26 @@ jobs:
fi
echo "No conflict markers found"
- name: Setup moko-platform tools
- name: Setup mokocli tools
env:
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_MIRROR_TOKEN }}"}}'
run: |
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
if [ -f /opt/mokocli/cli/version_bump.php ] && [ -f /opt/mokocli/vendor/autoload.php ]; then
echo Using pre-installed /opt/mokocli
echo MOKO_CLI=/opt/mokocli/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
rm -rf /tmp/mokocli
CLONE_URL=https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/mokocli.git
git clone --depth 1 --branch main --quiet $CLONE_URL /tmp/mokocli
cd /tmp/mokocli
composer install --no-dev --no-interaction --quiet
echo MOKO_CLI=/tmp/moko-platform-api/cli >> $GITHUB_ENV
echo MOKO_CLI=/tmp/mokocli/cli >> $GITHUB_ENV
fi
- name: "Determine version bump level"
@@ -225,22 +228,32 @@ jobs:
--path . --stability stable ${BUMP_FLAG} --branch main \
--token "${{ secrets.MOKOGITEA_TOKEN }}"
- name: Update release notes from CHANGELOG.md
- name: Update release notes and promote changelog
run: |
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
# Get the stable release info (version and ID)
RELEASE_JSON=$(curl -sf -H "Authorization: token ${TOKEN}" \
"${API_BASE}/releases/tags/stable" 2>/dev/null || echo '{}')
RELEASE_ID=$(python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))" <<< "$RELEASE_JSON" 2>/dev/null || true)
# Extract version from release name (e.g. "06.17.00" or "v06.17.00")
VERSION=$(python3 -c "
import json, sys, re
r = json.load(sys.stdin)
name = r.get('name', '')
m = re.search(r'(\d+\.\d+\.\d+)', name)
print(m.group(1) if m else '')
" <<< "$RELEASE_JSON" 2>/dev/null || true)
# Extract [Unreleased] section from changelog
NOTES=""
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
[ -z "$NOTES" ] && NOTES="Stable release"
# 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
@@ -250,7 +263,7 @@ jobs:
'${API_BASE}/releases/${RELEASE_ID}',
data=payload, method='PATCH',
headers={
'Authorization': 'token ${{ secrets.MOKOGITEA_TOKEN }}',
'Authorization': 'token ${TOKEN}',
'Content-Type': 'application/json'
})
urllib.request.urlopen(req)
@@ -258,6 +271,24 @@ jobs:
echo "Release notes updated from CHANGELOG.md"
fi
# Promote [Unreleased] → [version] in CHANGELOG.md and reset
if [ -n "$VERSION" ] && [ -f "CHANGELOG.md" ]; then
DATE=$(date +%Y-%m-%d)
python3 -c "
import sys
version, date = sys.argv[1], sys.argv[2]
content = open('CHANGELOG.md').read()
old = '## [Unreleased]'
new = f'## [Unreleased]\n\n## [{version}] --- {date}'
content = content.replace(old, new, 1)
open('CHANGELOG.md', 'w').write(content)
" "$VERSION" "$DATE"
git add CHANGELOG.md
git commit -m "chore: promote changelog [Unreleased] → [${VERSION}]" || true
git push origin main || true
echo "Changelog promoted: [Unreleased] → [${VERSION}]"
fi
# -- STEP 9: Mirror to GitHub (stable only) --------------------------------
- name: "Step 9: Mirror release to GitHub"
if: >-
+1 -1
View File
@@ -5,7 +5,7 @@
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.Universal
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
# PATH: /.mokogitea/workflows/branch-cleanup.yml
# VERSION: 01.00.00
# BRIEF: Delete feature branches after PR merge
-7
View File
@@ -13,13 +13,6 @@
name: "Generic: Project CI"
on:
push:
branches:
- main
- dev
- dev/**
- rc/**
- version/**
pull_request:
branches:
- main
-439
View File
@@ -1,439 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.CI
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
# PATH: /.gitea/workflows/ci-platform.yml
# VERSION: 09.23.00
# BRIEF: moko-platform CI — the standards engine validates itself
#
# +========================================================================+
# | MOKO-PLATFORM CI |
# +========================================================================+
# | |
# | This is NOT a generic CI workflow. This is the self-validation |
# | pipeline for the central moko-platform enterprise engine. |
# | |
# | It dogfoods every tool the platform ships to governed repos: |
# | |
# | Gate 1 — Code Quality phpcs (PSR-12), phpstan (L5), psalm |
# | Gate 2 — Unit Tests phpunit with coverage threshold |
# | Gate 3 — Self-Health bin/moko health against its own repo |
# | Gate 4 — Governance Checks headers, secrets, structure, versions |
# | Gate 5 — Template Lint validate workflow templates parse clean |
# | |
# | If it doesn't pass its own checks, it can't enforce them. |
# | |
# +========================================================================+
name: "Platform: moko-platform CI"
on:
push:
branches:
- main
- dev
- dev/**
- rc/**
paths-ignore:
- '**.md'
- 'wiki/**'
- '.gitea/ISSUE_TEMPLATE/**'
pull_request:
branches:
- main
- dev
- dev/**
- rc/**
workflow_dispatch:
inputs:
full_suite:
description: 'Run full validation suite (including slow checks)'
required: false
default: 'true'
type: boolean
concurrency:
group: ci-platform-${{ github.repository }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
PHP_VERSION: '8.2'
jobs:
# ═══════════════════════════════════════════════════════════════════════
# Gate 1 — Code Quality
# ═══════════════════════════════════════════════════════════════════════
code-quality:
name: "Gate 1: Code Quality"
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup PHP ${{ env.PHP_VERSION }}
run: |
sudo add-apt-repository -y ppa:ondrej/php >/dev/null 2>&1
sudo apt-get update -qq
sudo apt-get install -y -qq php${{ env.PHP_VERSION }}-cli php${{ env.PHP_VERSION }}-mbstring \
php${{ env.PHP_VERSION }}-xml php${{ env.PHP_VERSION }}-curl php${{ env.PHP_VERSION }}-zip \
php${{ env.PHP_VERSION }}-intl composer >/dev/null 2>&1
php -v
- name: Install Composer dependencies
run: |
composer install --no-interaction --prefer-dist
echo "Dependencies installed: $(composer show | wc -l) packages"
- name: "PHP Syntax Check"
run: |
ERRORS=0
CHECKED=0
while IFS= read -r -d '' file; do
CHECKED=$((CHECKED + 1))
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 lib/ validate/ automation/ cli/ src/ deploy/ -name "*.php" -print0 2>/dev/null)
{
echo "### PHP Syntax"
echo "Checked ${CHECKED} files — ${ERRORS} error(s)"
} >> $GITHUB_STEP_SUMMARY
[ "$ERRORS" -eq 0 ] || exit 1
- name: "PHPCS (PSR-12)"
run: |
vendor/bin/phpcs --standard=phpcs.xml --report=summary --warning-severity=0 lib/ validate/ automation/ 2>&1 || {
echo "::error::PHPCS found coding standard violations"
echo "### PHPCS" >> $GITHUB_STEP_SUMMARY
echo "Coding standard violations detected. Run \`composer phpcs\` locally." >> $GITHUB_STEP_SUMMARY
exit 1
}
echo "### PHPCS" >> $GITHUB_STEP_SUMMARY
echo "PSR-12 compliance: passed" >> $GITHUB_STEP_SUMMARY
- name: "PHPStan (Level 6)"
run: |
vendor/bin/phpstan analyse -c phpstan.neon --no-progress --memory-limit=512M --error-format=github 2>&1 || {
echo "::error::PHPStan found type errors"
echo "### PHPStan" >> $GITHUB_STEP_SUMMARY
echo "Static analysis errors detected. Run \`composer phpstan\` locally." >> $GITHUB_STEP_SUMMARY
exit 1
}
echo "### PHPStan" >> $GITHUB_STEP_SUMMARY
echo "Static analysis (level 6): passed" >> $GITHUB_STEP_SUMMARY
- name: "Psalm"
continue-on-error: true
run: |
if [ -f "psalm.xml" ]; then
vendor/bin/psalm --config=psalm.xml --no-progress --output-format=github 2>&1 || {
echo "### Psalm" >> $GITHUB_STEP_SUMMARY
echo "Psalm found issues (advisory — not blocking)." >> $GITHUB_STEP_SUMMARY
}
fi
# ═══════════════════════════════════════════════════════════════════════
# Gate 2 — Unit Tests
# ═══════════════════════════════════════════════════════════════════════
tests:
name: "Gate 2: Unit Tests"
runs-on: ubuntu-latest
timeout-minutes: 15
needs: code-quality
strategy:
matrix:
php: ['8.1', '8.2', '8.3']
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup PHP ${{ matrix.php }}
run: |
sudo add-apt-repository -y ppa:ondrej/php >/dev/null 2>&1
sudo apt-get update -qq
sudo apt-get install -y -qq php${{ matrix.php }}-cli php${{ matrix.php }}-mbstring \
php${{ matrix.php }}-xml php${{ matrix.php }}-curl php${{ matrix.php }}-zip \
php${{ matrix.php }}-intl composer >/dev/null 2>&1
php -v
- name: Install dependencies
run: composer install --no-interaction --prefer-dist
- name: "PHPUnit (PHP ${{ matrix.php }})"
run: |
vendor/bin/phpunit --testdox 2>&1 || {
echo "::error::PHPUnit tests failed"
echo "### PHPUnit (PHP ${{ matrix.php }})" >> $GITHUB_STEP_SUMMARY
echo "Tests failed. Run \`vendor/bin/phpunit --testdox\` locally." >> $GITHUB_STEP_SUMMARY
exit 1
}
echo "### PHPUnit (PHP ${{ matrix.php }})" >> $GITHUB_STEP_SUMMARY
echo "All tests passed." >> $GITHUB_STEP_SUMMARY
# ═══════════════════════════════════════════════════════════════════════
# Gate 3 — Self-Health (Dogfood)
# ═══════════════════════════════════════════════════════════════════════
self-health:
name: "Gate 3: Self-Health Check"
runs-on: ubuntu-latest
timeout-minutes: 10
needs: code-quality
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup PHP
run: |
sudo add-apt-repository -y ppa:ondrej/php >/dev/null 2>&1
sudo apt-get update -qq
sudo apt-get install -y -qq php${{ env.PHP_VERSION }}-cli php${{ env.PHP_VERSION }}-mbstring \
php${{ env.PHP_VERSION }}-xml php${{ env.PHP_VERSION }}-curl php${{ env.PHP_VERSION }}-zip \
composer >/dev/null 2>&1
- name: Install dependencies
run: composer install --no-interaction --prefer-dist
- name: "Run bin/moko health against self"
run: |
php bin/moko health -- --path . --json > /tmp/health-report.json 2>&1 || true
SCORE=$(cat /tmp/health-report.json | python3 -c "import sys,json; print(json.load(sys.stdin).get('percentage', 0))" 2>/dev/null || echo "0")
LEVEL=$(cat /tmp/health-report.json | python3 -c "import sys,json; print(json.load(sys.stdin).get('level', 'unknown'))" 2>/dev/null || echo "unknown")
{
echo "### Self-Health Report"
echo ""
echo "| Metric | Value |"
echo "|---|---|"
echo "| Score | ${SCORE}% |"
echo "| Level | ${LEVEL} |"
echo ""
echo "The platform must pass its own health check to enforce it on others."
} >> $GITHUB_STEP_SUMMARY
# Platform must score at least 80%
python3 -c "exit(0 if float('${SCORE}') >= 80.0 else 1)" || {
echo "::error::Self-health score ${SCORE}% is below 80% threshold"
exit 1
}
# ═══════════════════════════════════════════════════════════════════════
# Gate 4 — Governance Checks
# ═══════════════════════════════════════════════════════════════════════
governance:
name: "Gate 4: Governance"
runs-on: ubuntu-latest
timeout-minutes: 10
needs: code-quality
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup PHP
run: |
sudo add-apt-repository -y ppa:ondrej/php >/dev/null 2>&1
sudo apt-get update -qq
sudo apt-get install -y -qq php${{ env.PHP_VERSION }}-cli php${{ env.PHP_VERSION }}-mbstring \
php${{ env.PHP_VERSION }}-xml php${{ env.PHP_VERSION }}-curl composer >/dev/null 2>&1
- name: Install dependencies
run: composer install --no-interaction --prefer-dist
- name: "License headers (SPDX)"
run: |
MISSING=0
CHECKED=0
while IFS= read -r -d '' file; do
CHECKED=$((CHECKED + 1))
if ! head -n 20 "$file" | grep -q "SPDX-License-Identifier:"; then
echo "::warning file=${file}::Missing SPDX header"
MISSING=$((MISSING + 1))
fi
done < <(find lib/ validate/ cli/ src/ automation/ deploy/ -name "*.php" -print0 2>/dev/null)
{
echo "### License Headers"
echo "Checked ${CHECKED} files — ${MISSING} missing SPDX headers"
} >> $GITHUB_STEP_SUMMARY
# Advisory — warn but don't fail (yet)
[ "$MISSING" -eq 0 ] || echo "::warning::${MISSING} files missing SPDX license headers"
- name: "Secret detection"
run: |
FOUND=0
# Check for common secret patterns in source files
while IFS= read -r -d '' file; do
if grep -qEi '(password|secret|token|apikey|api_key)\s*[:=]\s*["\x27][^\s]{8,}' "$file" 2>/dev/null; then
echo "::error file=${file}::Potential hardcoded secret detected"
FOUND=$((FOUND + 1))
fi
done < <(find lib/ validate/ cli/ src/ automation/ deploy/ -name "*.php" -print0 2>/dev/null)
{
echo "### Secret Detection"
if [ "$FOUND" -eq 0 ]; then
echo "No hardcoded secrets detected."
else
echo "${FOUND} potential secrets found."
fi
} >> $GITHUB_STEP_SUMMARY
[ "$FOUND" -eq 0 ] || exit 1
- name: "Version consistency"
run: |
# Extract version from composer.json
COMPOSER_VER=$(python3 -c "import json; print(json.load(open('composer.json'))['version'])")
# Extract version from README.md
README_VER=$(sed -n 's/.*VERSION:[[:space:]]*\([0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\).*/\1/p' README.md 2>/dev/null | head -1)
{
echo "### Version Consistency"
echo "| Source | Version |"
echo "|---|---|"
echo "| composer.json | ${COMPOSER_VER} |"
echo "| README.md | ${README_VER:-not found} |"
} >> $GITHUB_STEP_SUMMARY
if [ -n "$README_VER" ] && [ "$COMPOSER_VER" != "$README_VER" ]; then
echo "::warning::Version mismatch: composer.json=${COMPOSER_VER} vs README.md=${README_VER}"
fi
# ═══════════════════════════════════════════════════════════════════════
# Gate 5 — Template Integrity
# ═══════════════════════════════════════════════════════════════════════
templates:
name: "Gate 5: Template Integrity"
runs-on: ubuntu-latest
timeout-minutes: 10
needs: code-quality
if: github.event_name != 'push' || github.event.inputs.full_suite != 'false'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: "Validate workflow templates"
run: |
ERRORS=0
CHECKED=0
# Check all YAML workflow templates parse cleanly
while IFS= read -r -d '' file; do
CHECKED=$((CHECKED + 1))
if ! python3 -c "import yaml; yaml.safe_load(open('${file}'))" 2>/dev/null; then
echo "::error file=${file}::Invalid YAML"
ERRORS=$((ERRORS + 1))
fi
done < <(find templates/workflows/ -name "*.yml" -o -name "*.yaml" 2>/dev/null | tr '\n' '\0')
# Also check the live workflows
while IFS= read -r -d '' file; do
CHECKED=$((CHECKED + 1))
if ! python3 -c "import yaml; yaml.safe_load(open('${file}'))" 2>/dev/null; then
echo "::error file=${file}::Invalid YAML"
ERRORS=$((ERRORS + 1))
fi
done < <(find .mokogitea/workflows/ -name "*.yml" -o -name "*.yaml" 2>/dev/null | tr '\n' '\0')
{
echo "### Template Integrity"
echo "Validated ${CHECKED} YAML files — ${ERRORS} parse errors"
} >> $GITHUB_STEP_SUMMARY
[ "$ERRORS" -eq 0 ] || exit 1
- name: "Validate gitignore templates"
run: |
TEMPLATES=0
for GI in templates/configs/gitignore templates/configs/gitignore.dolibarr templates/configs/.gitignore.joomla; do
if [ -f "$GI" ]; then
TEMPLATES=$((TEMPLATES + 1))
# Verify required entries
for REQUIRED in ".claude/" "TODO.md" "*.min.css" "*.min.js" "wiki/"; do
if ! grep -q "$REQUIRED" "$GI"; then
echo "::error file=${GI}::Missing required entry: ${REQUIRED}"
fi
done
fi
done
echo "### Gitignore Templates" >> $GITHUB_STEP_SUMMARY
echo "Validated ${TEMPLATES} gitignore templates." >> $GITHUB_STEP_SUMMARY
- name: "Validate PHP validation scripts"
run: |
ERRORS=0
CHECKED=0
while IFS= read -r -d '' file; do
CHECKED=$((CHECKED + 1))
if ! php -l "$file" 2>&1 | grep -q "No syntax errors"; then
echo "::error file=${file}::Validation script has syntax error"
ERRORS=$((ERRORS + 1))
fi
done < <(find validate/ -name "*.php" -print0 2>/dev/null)
{
echo "### Validation Scripts"
echo "Checked ${CHECKED} scripts — ${ERRORS} syntax errors"
} >> $GITHUB_STEP_SUMMARY
[ "$ERRORS" -eq 0 ] || { echo "::error::Validation scripts must be error-free"; exit 1; }
# ═══════════════════════════════════════════════════════════════════════
# Summary
# ═══════════════════════════════════════════════════════════════════════
summary:
name: "CI Summary"
runs-on: ubuntu-latest
needs: [code-quality, tests, self-health, governance, templates]
if: always()
steps:
- name: Check gate results
run: |
{
echo "# moko-platform CI"
echo ""
echo "| Gate | Job | Status |"
echo "|---|---|---|"
echo "| 1 | Code Quality | ${{ needs.code-quality.result }} |"
echo "| 2 | Unit Tests | ${{ needs.tests.result }} |"
echo "| 3 | Self-Health | ${{ needs.self-health.result }} |"
echo "| 4 | Governance | ${{ needs.governance.result }} |"
echo "| 5 | Templates | ${{ needs.templates.result }} |"
echo ""
echo "> *The standards engine must pass its own standards.*"
} >> $GITHUB_STEP_SUMMARY
# Fail if any required gate failed
if [ "${{ needs.code-quality.result }}" = "failure" ] || \
[ "${{ needs.tests.result }}" = "failure" ] || \
[ "${{ needs.self-health.result }}" = "failure" ] || \
[ "${{ needs.governance.result }}" = "failure" ] || \
[ "${{ needs.templates.result }}" = "failure" ]; then
echo "::error::One or more CI gates failed"
exit 1
fi
-126
View File
@@ -1,126 +0,0 @@
# 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
+1 -1
View File
@@ -5,7 +5,7 @@
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.Automation
# VERSION: 02.34.84
# VERSION: 02.48.24
# BRIEF: Auto-create feature branch when an issue is opened
name: "Universal: Issue Branch"
+2 -2
View File
@@ -4,8 +4,8 @@
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.CI
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/moko-platform
# INGROUP: mokocli.CI
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/mokocli
# PATH: /templates/workflows/universal/pr-check.yml.template
# VERSION: 09.23.00
# BRIEF: PR gate — branch policy + code validation before merge
@@ -0,0 +1,71 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: mokocli.Validation
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
# PATH: /templates/workflows/joomla/pr-metadata-check.yml.template
# VERSION: 01.00.00
# BRIEF: Validate MokoGitea metadata matches Joomla extension manifest on PRs
name: "Joomla: Metadata Validation"
on:
pull_request:
types: [opened, synchronize, reopened, converted_to_draft, ready_for_review]
permissions:
contents: read
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:
validate-metadata:
name: "Validate Joomla Metadata"
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup mokocli tools
env:
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
run: |
if [ -f /opt/mokocli/cli/joomla_metadata_validate.php ] && [ -f /opt/mokocli/vendor/autoload.php ]; then
echo Using pre-installed /opt/mokocli
echo MOKO_CLI=/opt/mokocli/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/mokocli
CLONE_URL=https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/mokocli.git
git clone --depth 1 --branch main --quiet $CLONE_URL /tmp/mokocli
cd /tmp/mokocli && composer install --no-dev --no-interaction --quiet
echo MOKO_CLI=/tmp/mokocli/cli >> $GITHUB_ENV
fi
- name: Validate metadata against Joomla manifest
env:
GITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
run: |
php ${MOKO_CLI}/joomla_metadata_validate.php \
--path . \
--token "${GITEA_TOKEN}" \
--org "${GITEA_ORG}" \
--repo "${GITEA_REPO}" \
--api-base "${GITEA_URL}/api/v1" \
--ci
if [ $? -ne 0 ]; then
echo "::error::Joomla metadata mismatch — update delivery will fail. Run 'php cli/joomla_metadata_validate.php' locally to see details."
exit 1
fi
+36 -27
View File
@@ -4,23 +4,26 @@
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: mokoplatform.Release
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform
# INGROUP: mokocli.Release
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
# PATH: /templates/workflows/universal/pre-release.yml.template
# VERSION: 05.01.00
# BRIEF: Manual pre-release -- builds dev/alpha/beta/rc packages from any branch
# BRIEF: Auto pre-release on push to dev/alpha/beta/rc branches
name: "Universal: Pre-Release"
on:
pull_request:
types: [closed]
push:
branches:
- dev
pull_request_target:
types: [synchronize, opened, reopened]
branches:
- main
- 'fix/**'
- 'patch/**'
- 'hotfix/**'
- 'bugfix/**'
- 'chore/**'
- alpha
- beta
- rc
workflow_dispatch:
inputs:
stability:
@@ -43,12 +46,11 @@ env:
jobs:
build:
name: "Build Pre-Release (${{ inputs.stability || 'development' }})"
name: "Build Pre-Release (${{ inputs.stability || github.ref_name }})"
runs-on: release
if: >-
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'pull_request' && github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'dev') ||
(github.event_name == 'pull_request_target' && github.event.pull_request.base.ref == 'main')
github.event_name == 'push'
steps:
- name: Checkout
@@ -56,40 +58,47 @@ jobs:
with:
fetch-depth: 0
token: ${{ secrets.MOKOGITEA_TOKEN }}
ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || '' }}
ref: ${{ github.ref_name }}
- name: Setup mokoplatform tools
- name: Setup mokocli tools
env:
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
run: |
# Use pre-installed /opt/mokoplatform if available (updated by cron every 6h)
if [ -f /opt/mokoplatform/cli/version_bump.php ] && [ -f /opt/mokoplatform/cli/manifest_element.php ] && [ -f /opt/mokoplatform/vendor/autoload.php ]; then
echo Using pre-installed /opt/mokoplatform
echo MOKO_CLI=/opt/mokoplatform/cli >> $GITHUB_ENV
# Use pre-installed /opt/mokocli if available (updated by cron every 6h)
if [ -f /opt/mokocli/cli/version_bump.php ] && [ -f /opt/mokocli/cli/manifest_element.php ] && [ -f /opt/mokocli/vendor/autoload.php ]; then
echo Using pre-installed /opt/mokocli
echo MOKO_CLI=/opt/mokocli/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/mokoplatform-api
CLONE_URL=https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/mokoplatform.git
git clone --depth 1 --branch main --quiet $CLONE_URL /tmp/mokoplatform-api
cd /tmp/mokoplatform-api && composer install --no-dev --no-interaction --quiet
echo MOKO_CLI=/tmp/mokoplatform-api/cli >> $GITHUB_ENV
rm -rf /tmp/mokocli
CLONE_URL=https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/mokocli.git
git clone --depth 1 --branch main --quiet $CLONE_URL /tmp/mokocli
cd /tmp/mokocli && composer install --no-dev --no-interaction --quiet
echo MOKO_CLI=/tmp/mokocli/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: RC for PRs targeting main, else use input or default to development
if [ "${{ github.event_name }}" = "pull_request_target" ] && [ "${{ github.event.pull_request.base.ref }}" = "main" ]; then
STABILITY="release-candidate"
# 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
@@ -164,7 +173,7 @@ jobs:
php ${MOKO_CLI}/release_create.php \
--path . --version "$VERSION" --tag "$TAG" \
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
--repo "${GITEA_REPO}" --branch dev --prerelease
--repo "${GITEA_REPO}" --branch "${{ github.ref_name }}" --prerelease
- name: Update release notes from CHANGELOG.md
run: |
+4 -3
View File
@@ -7,8 +7,8 @@
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.Validation
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/moko-platform
# INGROUP: mokocli.Validation
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/mokocli
# PATH: /templates/workflows/joomla/repo_health.yml.template
# VERSION: 09.23.00
# BRIEF: Enforces repository guardrails by validating scripts governance, tooling availability, and core repository health artifacts.
@@ -33,7 +33,8 @@ on:
- scripts
- repo
pull_request:
push:
branches:
- main
permissions:
contents: read
-82
View File
@@ -1,82 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.Security
# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards
# PATH: /.gitea/workflows/security-audit.yml
# VERSION: 01.00.00
# BRIEF: Dependency vulnerability scanning for composer and npm packages
name: "Universal: Security Audit"
on:
schedule:
- cron: '0 6 * * 1' # Weekly on Monday at 06:00 UTC
pull_request:
branches:
- main
paths:
- 'composer.json'
- 'composer.lock'
- 'package.json'
- 'package-lock.json'
workflow_dispatch:
permissions:
contents: read
env:
NTFY_URL: ${{ vars.NTFY_URL || 'https://ntfy.mokoconsulting.tech' }}
NTFY_TOPIC: ${{ vars.NTFY_TOPIC || 'gitea-security' }}
jobs:
audit:
name: Dependency Audit
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Composer audit
if: hashFiles('composer.lock') != ''
run: |
echo "=== Composer Security Audit ==="
if ! command -v composer &> /dev/null; then
sudo apt-get update -qq
sudo apt-get install -y -qq php-cli composer >/dev/null 2>&1
fi
composer audit --format=plain 2>&1 | tee /tmp/composer-audit.txt
RESULT=$?
if [ $RESULT -ne 0 ]; then
echo "::warning::Composer vulnerabilities found"
echo "composer_vulnerable=true" >> "$GITHUB_ENV"
else
echo "No known vulnerabilities in composer dependencies"
fi
- name: NPM audit
if: hashFiles('package-lock.json') != ''
run: |
echo "=== NPM Security Audit ==="
npm audit --production 2>&1 | tee /tmp/npm-audit.txt || true
if npm audit --production 2>&1 | grep -q "found 0 vulnerabilities"; then
echo "No known vulnerabilities in npm dependencies"
else
echo "::warning::NPM vulnerabilities found"
echo "npm_vulnerable=true" >> "$GITHUB_ENV"
fi
- name: Notify on vulnerabilities
if: env.composer_vulnerable == 'true' || env.npm_vulnerable == 'true'
run: |
REPO="${{ github.event.repository.name }}"
curl -sS \
-H "Title: ${REPO} has vulnerable dependencies" \
-H "Tags: lock,warning" \
-H "Priority: high" \
-d "Security audit found vulnerabilities. Review dependency updates." \
"${NTFY_URL}/${NTFY_TOPIC}" || true
@@ -0,0 +1,73 @@
# 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/mokoplatform
# PATH: /.mokogitea/workflows/workflow-sync-trigger.yml
# VERSION: 01.01.00
# BRIEF: Trigger workflow sync to live repos when a PR is merged to main
name: "Universal: Workflow Sync Trigger"
on:
pull_request:
types: [closed]
branches:
- main
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
sync:
name: Sync workflows to live repos
runs-on: ubuntu-latest
if: >-
github.event.pull_request.merged == true &&
!contains(github.event.pull_request.title, '[skip sync]')
steps:
- name: Determine platform from repo name
id: platform
run: |
REPO="${{ github.event.repository.name }}"
case "$REPO" in
Template-Joomla) PLATFORM="joomla" ;;
Template-Dolibarr) PLATFORM="dolibarr" ;;
Template-Go) PLATFORM="go" ;;
Template-MCP) PLATFORM="mcp" ;;
Template-Generic) PLATFORM="" ;;
*) PLATFORM="" ;;
esac
echo "platform=$PLATFORM" >> "$GITHUB_OUTPUT"
echo "Platform: ${PLATFORM:-all}"
- name: Clone mokoplatform
env:
MOKOGITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
run: |
GITEA_URL="${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}"
git clone --depth 1 "${GITEA_URL}/MokoConsulting/mokoplatform.git" /tmp/mokoplatform
- name: Install dependencies
run: |
cd /tmp/mokoplatform
composer install --no-dev --no-interaction --quiet 2>/dev/null || true
- name: Run workflow sync
env:
MOKOGITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
run: |
ARGS="--token ${MOKOGITEA_TOKEN}"
ARGS="${ARGS} --org ${{ vars.GITEA_ORG || github.repository_owner }}"
ARGS="${ARGS} --phase repos"
PLATFORM="${{ steps.platform.outputs.platform }}"
if [ -n "$PLATFORM" ]; then
ARGS="${ARGS} --platform-filter ${PLATFORM}"
fi
php /tmp/mokoplatform/cli/workflow_sync.php ${ARGS}
+50 -179
View File
@@ -14,196 +14,67 @@
INGROUP: MokoSuiteClient.Documentation
REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
PATH: ./CHANGELOG.md
VERSION: 02.34.84
VERSION: 02.48.24
BRIEF: Version history using `Keep a Changelog`
-->
# Changelog
## [Unreleased]
### Changed
- **Full rename: MokoSuite → MokoSuiteClient** — repo, all Joomla element names (com_mokosuiteclient, plg_system_mokosuiteclient, mod_mokosuiteclient_*, etc.), PHP classes, language files, folder structure, and manifest references. This is the client tracker for the MokoSuite platform.
### Added
- RSA-signed heartbeat authentication — private key in monitor plugin manifest, public key on MokoSuiteClientHQ
- Monitor plugin base_url set via manifest (hidden from admin UI), propagated via update server
- Send Heartbeat button on health token field for manual heartbeat testing
- Font Awesome 7 loaded in admin backend — picks up MokoOnyx Kit code if present, falls back to bundled FA7 Free or FA6 CDN
- MokoWaaS → MokoSuiteClient database table migration in install script (create new, copy data, drop old)
- MokoWaaS → MokoSuiteClient extension param migration — copies params from all old mokowaas plugins/modules/component, then removes old entries and filesystem remnants
- Ticket contact linking — optional FK to Joomla contact records with display in list and detail views
- Multi-assignee tickets — junction table supports multiple users and user groups per ticket
- Customizable ticket statuses — admin-configurable lookup table replaces hardcoded ENUM (title, color, is_closed flag)
- Customizable ticket priorities — admin-configurable lookup table with weight and color
- Joomla custom fields integration for tickets (context: com_mokosuiteclient.ticket) with field groups assignable per category
- MokoWaaS/MokoWaaSHQ migration bridge repos with updates.xml redirecting existing installs to MokoSuiteClient/HQ
- Pre-release workflow triggers on push to dev/alpha/beta/rc branches (deployed to all 11 repos)
- **Mirror Domains & Staging** — repeatable subform table in DevTools plugin for configuring domain aliases with per-alias offline bypass, robots directive, and labels
- **Daily Support PIN** — HMAC-SHA256 rotating PIN shown on cpanel module, component dashboard, and HQ site cards
- **Support PIN in status bar** — cache/temp module now shows PIN request button instead of domain; click to request, click again to copy
- **Frontend link in status bar** — cache/temp module now has 4 buttons: Site (frontend link), PIN, Cache, Temp
- **Help buttons** — all admin views link to Gitea wiki pages via toolbar help button
- **Support PIN in heartbeat** — core system plugin includes current PIN in heartbeat payload to HQ
- **HQ config sync** — client stores HQ-configured `support_pin_hours` from heartbeat response, PIN TTL now configurable from HQ
### Changed
- **Support PIN UI unified** — `SupportPinHelper::renderBadge()` and `renderScript()` replace 3 separate inline implementations (dashboard, cpanel module, cache module) with click-to-copy on all PIN badges
- Admin sidebar menu module now loads component-local language files (fixes untranslated keys for MokoSuiteCross and other components)
- Support PIN TTL is now configurable via HQ global options instead of hardcoded 72 hours
- Removed MokoSuiteHQ from extension catalog (internal app, not for client sites)
- **SupportPinHelper** — shared helper centralises PIN generation across dashboard, cpanel module, cache module, and AJAX controller
- **Current IP display** — firewall plugin settings show admin's IP with copy button
- **Heartbeat monitor** — consolidated into core plugin from retired monitor plugin, with diagnostic logging on all bail-out points
- **Backup bridge plugin** — discovers MokoSuiteBackup's BackupStatusHelper and sends status in heartbeat payloads
- **Activity log** — blockchain-style hash chain for tamper detection in MokoSuiteHQ
- **Dev domain in heartbeat** — client sends dev alias to HQ for display on dashboard
- **Login app badges** — recent logins table shows Admin/Site badge parsed from Joomla action log message JSON
### Changed
- **Plugin install** — self-healing: extracts plugin zips from package on every update, creates missing extension records with namespace
- **Menu naming** — MokoSuiteClient displays as "MokoSuite", MokoSuiteHQ as "MokoHQ", others stripped of prefix
- **Menu ordering** — HQ first, MokoSuite second, others alphabetical
- **Cpanel module** — always starts collapsed, access level 3 (Special), pretty plugin badge labels
- **Module namespaces** — fixed cpanel (MokoSuiteCpanel → MokoSuiteClientCpanel) and cache (MokoSuiteCache → MokoSuiteClientCache)
- **Health checks** — return status:error on exceptions instead of false status:ok; MokoSuiteBackup detection queries correct table
- **Heartbeat** — correct URL (suite.dev), correct API route (mokosuitehq), correct headers (X-MokoSuite-*), fresh RSA key pair
- **Date formats** — all templates use Joomla locale-aware DATE_FORMAT_LC2/LC4
- **Domains** — updated from waas.dev to suite.dev.mokoconsulting.tech throughout
- **Dashboard info bar** — reverted stacked layout; info items back to horizontal row
- **Extension version bar** — full-width auto-sized strip with equal-width cells and border separators
- **Recent logins** — exact match on LOGGED_IN key (excludes logout noise), limit increased to 10
### Removed
- PerfectPublisher webservices plugin (no longer needed)
- **Helpdesk/tickets** — migrated to MokoSuiteCRM (issue #67)
- **Monitor plugin** — retired, config consolidated into core plugin
- **Backup bridge** — temporarily removed from package manifest (build pipeline issue)
- **Update server migration** — removed migrateUpdateServerUrls, cleanupStaleUpdateSites, fixUpdateRecords, enableUpdateServer calls
### Fixed
- Download key lost on update: cleanupStaleUpdateSites used old /raw/branch/main/ URL format, deleting the manifest-registered update site that held the key
- Health endpoint cron check SQL error — orphan `setQuery(getQuery(true), 0, 5)` produced bare `LIMIT 5`, returning 503 for all health polls
- License plugin missing `src/` and `language/` directories causing install failure
- PIN generation inconsistency — controller used `floor(now/TTL)` while display used `floor(requestedAt/TTL)`
- Plugin files installing to group root instead of element subdirectory (ALTER TABLE DEFAULT '' + empty element cleanup)
- Orphan extension rows with empty element or display-name-as-element
- Module not publishing (ensureAdminModule direct DB update bypasses checked_out)
- RSA key pair had Windows line endings causing signature verification failure
- Heartbeat connection failing due to wrong domain, route, and header names
## [02.35.00] - 2026-06-06
## [02.44.00] --- 2026-06-20
### Added
- Core plugin stripped to heartbeat-only config (~5,500 lines removed)
- Extension catalog (catalog.xml) with update server discovery (#186)
- Download key preservation across Joomla updates (#187)
- Remote login endpoint for MokoSuiteClientHQ auto-login
- Provision reset API for new client setup (hits, versions, tokens)
- Setup required banner after provision reset
- Support verification PIN (MOKO-XXXX-XXXX)
- mod_mokosuiteclient_categories — auto-category tree menu (#184)
- Cache/temp split button in status bar
- Dashboard version tiles for component and modules
- Monitor plugin sends full health payload to MokoSuiteClientHQ
- Firewall: block_frontend_superuser, own trusted_ip_entry.xml
- DevTools: reset download keys toggle
## [02.42.00] --- 2026-06-20
### Changed
- Renamed src/ to source/ (#188)
- Service classes relocated to owning plugins
- API controller execute() signatures fixed (#183)
- Joomla 5/6 event compatibility in DevTools and Monitor
- Dead placeholder resolver removed from install script
### Fixed
- Firewall subform paths after core cleanup
- Missing Security Headers language strings
## [02.34.00] - 2026-06-04
### Added
- Database Tools view — table status, optimize, repair, session purge (#127)
- Cache Cleanup view — directory size reporting and one-click cleanup (#128)
- mod_mokosuiteclient_cache — one-click cache cleaner button in admin status bar (replaces Regular Labs Cache Cleaner)
- mod_mokosuiteclient_menu — collapsible admin sidebar menu using native MetisMenu classes (like Community Builder)
- SSL certificate expiry monitoring in cpanel module (#148)
- MokoSuiteClient-specific update badge (blue) separate from other updates in cpanel module
- migrateUpdateServerUrls() — rewrites all Moko extension update server URLs to clean /updates.xml on install/update
- fixMenuIcons() — sets menu_icon params on submenu items (Joomla only renders img on level 1)
- setupCacheModule() — registers cache cleaner module in status bar position on install
- Component config.xml for Joomla Options modal (#149)
- preflight() ALTER for #__extensions.element default (MySQL strict mode fix)
- Retire MokoJoomTOS, MokoATS-Automation, MokoDPCalendarAPI, MokoGalleryCalendar on install
- MokoJoomTOS settings auto-migrate to mokosuiteclient_offline before removal
- dev-release and pre-release workflows with changelog extraction into release notes
- RC pre-release consolidates dev patches into clean minor version bump
### Changed
- Move security hardening methods (protectPlugin, ensureProtectedFlag, isOurExtension) from core plugin to firewall plugin (#155)
- Admin menu module uses native Joomla MetisMenu CSS classes
- Helpdesk icon changed to fa-handshake-angle, .htaccess to fa-solid fa-file-code
- clearCache purges all cache files recursively (replaces Regular Labs Cache Cleaner behavior)
- License key warning moved from every-page onAfterRoute to package postflight only
- Update server URL changed to dynamic MokoGitea feed
- Component manifest adds `<languages>` for global language dir deployment
- Privacy and WAF Log added to component manifest submenu
- MokoOnyx template removed from package manifest (separate repo/release)
### Removed
- Static updates.xml — MokoGitea generates update feed dynamically from releases
- update-server.yml workflow — replaced by pre-release.yml
### Fixed
- Tickets list showing raw `<em>Unassigned</em>` HTML instead of italic text
- Cache cleaner CSRF failure — token now sent as POST FormData
- Admin menu icons missing for Helpdesk and .htaccess Maker
- Firewall install error "Field 'element' doesn't have a default value" (MySQL strict mode)
## [02.32] - 2026-06-02
### Added
- Admin control panel dashboard in com_mokosuiteclient with site info bar, feature plugin grid, and quick actions
- Feature plugin architecture — MokoSuiteClient features split into toggleable plugins managed from the dashboard
- plg_system_mokosuiteclient_firewall — HTTPS enforcement, trusted IPs, session timeout, upload restrictions, password policy
- plg_system_mokosuiteclient_tenant — Installer, sysinfo, config, template, and menu restrictions for non-master users
- plg_system_mokosuiteclient_devtools — Dev mode, hit counter reset, content version cleanup
- plg_system_mokosuiteclient_monitor — Grafana heartbeat integration and health monitoring
- MokoSuiteClientHelper utility class for shared master-user detection across feature plugins
- AJAX plugin toggle — enable/disable feature plugins directly from the dashboard
- Clear cache quick action on dashboard
- Static updates.xml for update server (licensing system deferred)
- Automatic param migration from core plugin to feature plugins on upgrade
### Changed
- com_mokosuiteclient upgraded from API-only to full admin component with dashboard views
- Package manifest updated with 4 new feature plugin entries (10 extensions total)
- Update server URL changed to static raw file endpoint
- Core plugin slimmed — security, tenant, devtools, and monitor features extracted to dedicated plugins
### Removed
- License key validation (licensing system not ready — will return in future release)
- Dynamic MokoGitea update feed dependency (replaced with static updates.xml)
## [02.31] - 2026-06-01
### Added
- License key support via Joomla's native Update Sites download key system (dlid)
- Update server URL migrated from static XML to MokoGitea's dynamic update feed endpoint
- Legacy static update site URLs auto-migrated to dynamic endpoint on install/update
- Persistent admin warning when no license key is configured in Update Sites
- Daily heartbeat validation of license key against MokoGitea — warns if key is invalid or expired
- Stale/duplicate update site cleanup on install/update (removes old static URL entries and orphaned records)
- Content sync rewritten — bulk MokoSuiteClient API endpoints (syncclear + syncpush) replace per-item Joomla API calls
- Sync task per-instance config: target URL, health token, content type checkboxes (articles, categories, menus, modules)
- Bulk sync completes in under 5 seconds (clear + push in 2-3 HTTP requests)
- Asset table and nested set tree repair after sync push on target site
- Enhanced dev mode: disables caching, enables Joomla + MokoOnyx debug, suppresses hit recording, shows offline on primary domain
- Dev mode off: clears content versions, resets hits, disables debug, takes site online
- Hardcoded dev alias (dev.{primary_domain}) with noindex/nofollow — bypasses offline mode for development
- Primary domain auto-detected on first config save
### Changed
- Branding, master user, support URL, and admin colors are now hardcoded (no longer configurable)
- Master user enforcement is always active (toggle removed)
- Diagnostics + maintenance merged into default config tab
- Emergency access moved to Security tab
- Content sync configuration moved from system plugin to individual scheduled task instances
### Removed
- Static `updates.xml` — update feed is now generated dynamically by MokoGitea from git releases
- Basic branding config tab (brand name, company name, support URL)
- Visual branding config tab (colors, icon, custom CSS)
- Suite Access config tab (master user toggle, master email)
- Content Sync config tab (targets now in scheduled tasks)
- Site Aliases config tab (hardcoded to dev.{primary_domain})
- File sync (images/, files/, media/) — sync is API/DB content only
## [02.29] - 2026-05-31
### Added
- `allow_extension_updates` param — separate update rights from installer restrictions; tenants can update extensions by default even when the installer is restricted
- Hardcoded master usernames — multiple privileged users supported with identical access
### Fixed
- Emergency access IP whitelist: empty `allowed_ips` now permits all IPs (was blocking everyone)
- Emergency access reads `allowed_ips` from plugin params instead of global config
- `plg_task_mokosuiteclientsync` — Joomla Scheduled Task plugin for automatic content sync to remote sites
- Community Builder tables added to demo reset safe table list
- API endpoint `POST /api/index.php/v1/mokosuiteclient/install` — install extensions from a remote ZIP URL
- Demo Mode with configurable warning banner on frontend when enabled
- Demo banner countdown now shows weeks/days/months for longer intervals instead of raw hours
- `DemoResetService` — baseline snapshot and restore for DB tables + media files
- API endpoints `POST /?mokosuiteclient=reset` and `POST /?mokosuiteclient=snapshot` (query-string)
- REST endpoints `POST /api/v1/mokosuiteclient/reset` and `GET/POST /api/v1/mokosuiteclient/snapshot`
- `plg_task_mokosuiteclientdemo` — Joomla Scheduled Task plugin for automatic demo site reset
- Admin toggles: Take Snapshot Now and Restore Baseline Now in plugin config
- Content Sync: one-way push of articles, categories, menus, and modules to remote MokoSuiteClient sites
- Content Sync: API endpoints `POST /?mokosuiteclient=sync` (sender) and `POST /?mokosuiteclient=sync-receive` (receiver)
- Content Sync: REST endpoints `POST /api/v1/mokosuiteclient/sync` and `POST /api/v1/mokosuiteclient/sync-receive`
- Content Sync: configurable sync targets with URL + API token in plugin settings
- Package installer: protect all MokoSuiteClient extensions (not just system plugin) and ensure update server stays enabled
- Package installer: clean up legacy `mokosuiteclientbrand` extension entries and files on install/update
- API endpoint `GET /?mokosuiteclient=extensions` and `GET /api/v1/mokosuiteclient/extensions` — list installed extensions with version, status, and update server info
## [02.20] --- 2026-05-28
## [02.42.00] --- 2026-06-20
+1 -1
View File
@@ -14,7 +14,7 @@
DEFGROUP: Joomla.Plugin
INGROUP: MokoSuiteClient.Documentation
REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
VERSION: 02.34.84
VERSION: 02.48.24
PATH: ./CODE_OF_CONDUCT.md
BRIEF: Reference + packaging repo for Moko Consulting Developer GPT Other Default
-->
+1 -1
View File
@@ -19,7 +19,7 @@
DEFGROUP: mokoconsulting-tech.MokoSuiteClientBrand
INGROUP: MokoStandards.Governance
REPO: https://github.com/mokoconsulting-tech/MokoSuiteClientBrand
VERSION: 02.34.84
VERSION: 02.48.24
PATH: /GOVERNANCE.md
BRIEF: Project governance rules, roles, and decision process for MokoSuiteClientBrand
-->
+1 -1
View File
@@ -15,7 +15,7 @@
INGROUP: MokoSuiteClient.Documentation
REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
PATH: ./LICENSE.md
VERSION: 02.34.84
VERSION: 02.48.24
BRIEF: Project license (GPL-3.0-or-later)
-->
GNU GENERAL PUBLIC LICENSE
+3 -3
View File
@@ -12,10 +12,10 @@
# ==============================================================================
# Extension Configuration
EXTENSION_NAME := mokoexample
EXTENSION_TYPE := module
EXTENSION_NAME := mokosuiteclient
EXTENSION_TYPE := package
# Options: module, plugin, component, package, template
EXTENSION_VERSION := 1.0.0
EXTENSION_VERSION := 02.35.00
# Module Configuration (for modules only)
MODULE_TYPE := site
+32 -9
View File
@@ -9,7 +9,7 @@
DEFGROUP: Joomla.Plugin
INGROUP: MokoSuiteClient
REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteClient
VERSION: 02.34.84
VERSION: 02.48.24
PATH: /README.md
BRIEF: MokoSuiteClient platform plugin for Joomla
-->
@@ -21,17 +21,40 @@
[![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)
MokoSuiteClient is a Joomla 5.x / 6.x system plugin package that provides white-label branding, security hardening, tenant restrictions, health monitoring, and multi-domain management for the MokoSuiteClient platform.
MokoSuiteClient is the Joomla 5.x / 6.x client-facing tracker and identity layer for the MokoSuite platform. It provides security hardening, health monitoring, privacy compliance, multi-domain management, and integration with MokoSuiteHQ for centralized site management.
## Features
- **White-Label Branding** — configurable brand name, company, support URL, colors, favicon, custom CSS
- **Tenant Restrictions** — master user enforcement, installer/sysinfo/config/template access control
- **Health Monitoring** — 16 diagnostic checks via `/?mokosuiteclient=health` with Grafana auto-provisioning
- **Site Aliases** — per-alias offline mode, robots directives, backend redirect, canonical URLs
- **Remote API** — 6 endpoints (health, install, update, cache, backup, info)
- **Security Hardening** — HTTPS enforcement, session timeouts, password policy, upload restrictions
- **Plugin Protection** — protected status, hidden from non-master users, disable/uninstall blocked
### Core
- **Admin Dashboard** — site info, plugin status, quick actions, support PIN
- **Health Monitoring** — 15 diagnostic checks via `/?mokosuiteclient=health`
- **Heartbeat** — RSA-signed registration with MokoSuiteHQ, daily support PIN rotation
- **Extension Catalog** — browse and install Moko Consulting extensions
### Security (Firewall Plugin)
- **Web Application Firewall** — SQL injection, XSS, RFI, directory traversal shields
- **Security Headers** — X-Frame-Options, CSP, HSTS, Referrer-Policy, Permissions-Policy
- **IP Management** — trusted IPs, blocklist, auto-ban on WAF threshold
- **Password Policy** — min length, uppercase, number, special character requirements
- **Access Control** — admin secret URL, frontend super user block, upload restrictions
### Privacy Guard
- **GDPR Compliance** — data subject requests, consent logging, retention policies
- **User Data** — export, anonymize, or delete user data on request
### DevTools
- **Development Mode** — debug, cache disable, hit suppression
- **Mirror Domains & Staging** — repeatable table of domain aliases with offline bypass and robots directives
- **Maintenance** — reset hits, delete versions, reset download keys
### Multi-Domain
- **Site Aliases** — per-alias offline mode, robots directives, canonical URLs
- **Offline Bypass** — TOS, privacy policy, and support pages remain accessible when site is offline
### Integration
- **MokoSuiteHQ** — heartbeat, health data, backup status, activity logging
- **MokoSuiteBackup** — bridge plugin discovers BackupStatusHelper for heartbeat payloads
- **Joomla** — guided tours, action logging, custom fields, scheduled tasks
## Requirements
+1 -1
View File
@@ -23,7 +23,7 @@ DEFGROUP: [PROJECT_NAME]
INGROUP: [PROJECT_NAME].Documentation
REPO: [REPOSITORY_URL]
PATH: /SECURITY.md
VERSION: 02.34.84
VERSION: 02.48.24
BRIEF: Security vulnerability reporting and handling policy
-->
+2 -2
View File
@@ -11,13 +11,13 @@
INGROUP: MokoSuiteClient.Build
REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
FILE: build-guide.md
VERSION: 02.34.84
VERSION: 02.48.24
PATH: /docs/guides/
BRIEF: Build and packaging guide for the MokoSuiteClient system plugin
NOTE: Defines environment setup, repository layout, packaging rules, and release preparation
-->
# MokoSuiteClient Build Guide (VERSION: 02.34.84)
# MokoSuiteClient Build Guide (VERSION: 02.48.24)
## 1. Purpose
+2 -2
View File
@@ -10,13 +10,13 @@
DEFGROUP: Joomla.Plugin
INGROUP: MokoSuiteClient.Guides
REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
VERSION: 02.34.84
VERSION: 02.48.24
PATH: /docs/guides/configuration-guide.md
BRIEF: Configuration guide for the MokoSuiteClient system plugin
NOTE: Defines plugin parameters, expected behaviors, and recommended defaults
-->
# MokoSuiteClient Configuration Guide (VERSION: 02.34.84)
# MokoSuiteClient Configuration Guide (VERSION: 02.48.24)
## 1. Objective
+2 -2
View File
@@ -10,13 +10,13 @@
DEFGROUP: Joomla.Plugin
INGROUP: MokoSuiteClient.Guides
REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
VERSION: 02.34.84
VERSION: 02.48.24
PATH: /docs/guides/installation-guide.md
BRIEF: Installation guide for the MokoSuiteClient system plugin
NOTE: First document in the guide set
-->
# MokoSuiteClient Installation Guide (VERSION: 02.34.84)
# MokoSuiteClient Installation Guide (VERSION: 02.48.24)
## Introduction
+2 -2
View File
@@ -10,13 +10,13 @@
DEFGROUP: Joomla.Plugin
INGROUP: MokoSuiteClient.Guides
REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
VERSION: 02.34.84
VERSION: 02.48.24
PATH: /docs/guides/operations-guide.md
BRIEF: Operational guide for administering and managing the MokoSuiteClient system plugin
NOTE: Defines lifecycle, responsibilities, and operational behaviors
-->
# MokoSuiteClient Operations Guide (VERSION: 02.34.84)
# MokoSuiteClient Operations Guide (VERSION: 02.48.24)
## Introduction
+2 -2
View File
@@ -10,13 +10,13 @@
DEFGROUP: Joomla.Plugin
INGROUP: MokoSuiteClient.Guides
REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
VERSION: 02.34.84
VERSION: 02.48.24
PATH: /docs/guides/rollback-and-recovery-guide.md
BRIEF: Rollback and recovery guide for restoring stable operation after plugin related incidents
NOTE: Completes the core guide set for Suite plugin governance
-->
# MokoSuiteClient Rollback and Recovery Guide (VERSION: 02.34.84)
# MokoSuiteClient Rollback and Recovery Guide (VERSION: 02.48.24)
## Introduction
+2 -2
View File
@@ -7,13 +7,13 @@
DEFGROUP: Joomla.Plugin
INGROUP: MokoSuiteClient.Guides
REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
VERSION: 02.34.84
VERSION: 02.48.24
PATH: /docs/guides/testing-guide.md
BRIEF: Testing guide for MokoSuiteClient v02.01.08
NOTE: Covers manual test procedures for language overrides, install/uninstall, and configuration
-->
# MokoSuiteClient Testing Guide (VERSION: 02.34.84)
# MokoSuiteClient Testing Guide (VERSION: 02.48.24)
## 1. Prerequisites
+2 -2
View File
@@ -10,13 +10,13 @@
DEFGROUP: Joomla.Plugin
INGROUP: MokoSuiteClient.Guides
REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
VERSION: 02.34.84
VERSION: 02.48.24
PATH: /docs/guides/troubleshooting-guide.md
BRIEF: Troubleshooting guide for diagnosing and resolving issues related to the MokoSuiteClient plugin
NOTE: Designed for administrators and Suite operations teams
-->
# MokoSuiteClient Troubleshooting Guide (VERSION: 02.34.84)
# MokoSuiteClient Troubleshooting Guide (VERSION: 02.48.24)
## Introduction
+2 -2
View File
@@ -10,13 +10,13 @@
DEFGROUP: Joomla.Plugin
INGROUP: MokoSuiteClient.Guides
REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
VERSION: 02.34.84
VERSION: 02.48.24
PATH: /docs/guides/upgrade-and-versioning-guide.md
BRIEF: Guide for updating, versioning, and maintaining the MokoSuiteClient plugin
NOTE: Defines release flow, version rules, and upgrade validation
-->
# MokoSuiteClient Upgrade and Versioning Guide (VERSION: 02.34.84)
# MokoSuiteClient Upgrade and Versioning Guide (VERSION: 02.48.24)
## Introduction
+2 -2
View File
@@ -10,13 +10,13 @@
DEFGROUP: Joomla.Plugin
INGROUP: MokoSuiteClient.Documentation
REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
VERSION: 02.34.84
VERSION: 02.48.24
PATH: /docs/index.md
BRIEF: Master index of all documentation for the MokoSuiteClient plugin
NOTE: Automatically maintained index for all guide canvases
-->
# MokoSuiteClient Documentation Index (VERSION: 02.34.84)
# MokoSuiteClient Documentation Index (VERSION: 02.48.24)
## Introduction
+2 -2
View File
@@ -11,12 +11,12 @@
INGROUP: MokoSuiteClient
REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
PATH: /docs/plugin-basic.md
VERSION: 02.34.84
VERSION: 02.48.24
BRIEF: Baseline documentation for the MokoSuiteClient system plugin
NOTE: Foundational reference for internal and external stakeholders
-->
# MokoSuiteClient Plugin Overview (VERSION: 02.34.84)
# MokoSuiteClient Plugin Overview (VERSION: 02.48.24)
## Introduction
+1 -1
View File
@@ -10,7 +10,7 @@ DEFGROUP: MokoSuiteClient.Documentation
INGROUP: MokoStandards.Templates
REPO: https://github.com/mokoconsulting-tech/MokoSuiteClient
PATH: /docs/update-server.md
VERSION: 02.34.84
VERSION: 02.48.24
BRIEF: How this extension's Joomla update server file (update.xml) is managed
-->
@@ -1,15 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<access component="com_mokosuiteclient">
<section name="component">
<!-- Core Joomla ACL -->
<action name="core.admin" title="JACTION_ADMIN" description="JACTION_ADMIN_COMPONENT_DESC" />
<action name="core.manage" title="JACTION_MANAGE" description="JACTION_MANAGE_COMPONENT_DESC" />
<!-- Dashboard & UI -->
<action name="mokosuiteclient.dashboard" title="COM_MOKOSUITECLIENT_ACL_DASHBOARD" description="COM_MOKOSUITECLIENT_ACL_DASHBOARD_DESC" />
<action name="mokosuiteclient.extensions" title="COM_MOKOSUITECLIENT_ACL_EXTENSIONS" description="COM_MOKOSUITECLIENT_ACL_EXTENSIONS_DESC" />
<action name="mokosuiteclient.htaccess" title="COM_MOKOSUITECLIENT_ACL_HTACCESS" description="COM_MOKOSUITECLIENT_ACL_HTACCESS_DESC" />
<action name="mokosuiteclient.tickets" title="COM_MOKOSUITECLIENT_ACL_TICKETS" description="COM_MOKOSUITECLIENT_ACL_TICKETS_DESC" />
<action name="mokosuiteclient.tickets.create" title="COM_MOKOSUITECLIENT_ACL_TICKETS_CREATE" description="COM_MOKOSUITECLIENT_ACL_TICKETS_CREATE_DESC" />
<action name="mokosuiteclient.tickets.assign" title="COM_MOKOSUITECLIENT_ACL_TICKETS_ASSIGN" description="COM_MOKOSUITECLIENT_ACL_TICKETS_ASSIGN_DESC" />
<action name="mokosuiteclient.plugins.toggle" title="COM_MOKOSUITECLIENT_ACL_PLUGINS_TOGGLE" description="COM_MOKOSUITECLIENT_ACL_PLUGINS_TOGGLE_DESC" />
<action name="mokosuiteclient.cache" title="COM_MOKOSUITECLIENT_ACL_CACHE" description="COM_MOKOSUITECLIENT_ACL_CACHE_DESC" />
<!-- Server Config -->
<action name="mokosuiteclient.htaccess" title="COM_MOKOSUITECLIENT_ACL_HTACCESS" description="COM_MOKOSUITECLIENT_ACL_HTACCESS_DESC" />
<!-- Security -->
<action name="mokosuiteclient.security.waflog" title="COM_MOKOSUITECLIENT_ACL_WAFLOG" description="COM_MOKOSUITECLIENT_ACL_WAFLOG_DESC" />
<action name="mokosuiteclient.security.impersonate" title="COM_MOKOSUITECLIENT_ACL_IMPERSONATE" description="COM_MOKOSUITECLIENT_ACL_IMPERSONATE_DESC" />
<!-- Content Tools -->
<action name="mokosuiteclient.snippets.manage" title="COM_MOKOSUITECLIENT_ACL_SNIPPETS" description="COM_MOKOSUITECLIENT_ACL_SNIPPETS_DESC" />
<action name="mokosuiteclient.templates.manage" title="COM_MOKOSUITECLIENT_ACL_TEMPLATES" description="COM_MOKOSUITECLIENT_ACL_TEMPLATES_DESC" />
<action name="mokosuiteclient.replacements.manage" title="COM_MOKOSUITECLIENT_ACL_REPLACEMENTS" description="COM_MOKOSUITECLIENT_ACL_REPLACEMENTS_DESC" />
<action name="mokosuiteclient.conditions.manage" title="COM_MOKOSUITECLIENT_ACL_CONDITIONS" description="COM_MOKOSUITECLIENT_ACL_CONDITIONS_DESC" />
<!-- Extensions & Catalog -->
<action name="mokosuiteclient.extensions" title="COM_MOKOSUITECLIENT_ACL_EXTENSIONS" description="COM_MOKOSUITECLIENT_ACL_EXTENSIONS_DESC" />
</section>
</access>
@@ -1,122 +1,210 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Extension catalog for MokoSuiteClient Extension Manager.
Each entry points to the extension's own updates.xml. The installer
resolves the latest version and download URL at runtime, respecting
the site's configured update channel (dev/stable).
To add an extension: copy an <extension> block and fill in the fields.
MokoSuite Extension Catalog
Each entry points to the extension's updates.xml on the main branch.
The installer resolves the latest version and download URL at runtime,
respecting the site's configured update channel (stable/dev) from
Joomla's com_installer params.
-->
<catalog>
<!-- ═══════════════════════════════════════════════════════════════════
Platform (Layer 0)
═══════════════════════════════════════════════════════════════════ -->
<extension>
<name>MokoSuiteClient</name>
<element>pkg_mokosuiteclient</element>
<type>package</type>
<description>Admin dashboard, security firewall, tenant restrictions, health monitoring, and REST API.</description>
<description>Admin dashboard, security firewall, tenant restrictions, health monitoring, content tools, and REST API.</description>
<icon>icon-shield-alt</icon>
<category>Platform</category>
<article>https://mokoconsulting.tech/support/products/mokosuiteclient-platform</article>
<protected>true</protected>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteClient/raw/branch/dev/updates.xml</updateserver>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteClient/raw/branch/main/updates.xml</updateserver>
</extension>
<extension>
<name>MokoSuiteClientHQ</name>
<element>pkg_mokosuiteclienthq</element>
<type>package</type>
<description>Centralized control panel for managing all MokoSuiteClient client installations.</description>
<icon>icon-tachometer-alt</icon>
<category>Platform</category>
<article>https://mokoconsulting.tech/support/products/mokosuiteclient-base</article>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteClientHQ/raw/branch/dev/updates.xml</updateserver>
</extension>
<extension>
<name>MokoOnyx</name>
<element>mokoonyx</element>
<type>template</type>
<description>Modern Joomla site template with dark mode, custom layouts, and MokoSuiteClient integration.</description>
<icon>icon-paint-brush</icon>
<category>Templates</category>
<article>https://mokoconsulting.tech/support/products/mokoonyx-template</article>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoOnyx/raw/branch/dev/updates.xml</updateserver>
</extension>
<extension>
<name>MokoJoomOpenGraph</name>
<element>pkg_mokoog</element>
<type>package</type>
<description>Open Graph, Twitter Card, and social sharing meta tags for articles, categories, and pages.</description>
<icon>icon-share-alt</icon>
<category>SEO</category>
<article>https://mokoconsulting.tech/support/products/mokojoomopengraph</article>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoJoomOpenGraph/raw/branch/dev/updates.xml</updateserver>
</extension>
<extension>
<name>MokoSuiteClientBackup</name>
<element>pkg_mokojoombackup</element>
<name>MokoSuiteBackup</name>
<element>pkg_mokosuitebackup</element>
<type>package</type>
<description>Full-site backup and restore for Joomla — database, files, and configuration.</description>
<icon>icon-archive</icon>
<category>Tools</category>
<article>https://mokoconsulting.tech/support/products/mokosuiteclientbackup</article>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteClientBackup/raw/branch/dev/updates.xml</updateserver>
<category>Platform</category>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteBackup/raw/branch/main/updates.xml</updateserver>
</extension>
<!-- ═══════════════════════════════════════════════════════════════════
Business Suite (Layers 1-4)
═══════════════════════════════════════════════════════════════════ -->
<extension>
<name>MokoSuiteCRM</name>
<element>pkg_mokosuitecrm</element>
<type>package</type>
<description>Layer 1 — Contacts, deals pipeline, activities, e-signature, email integration, helpdesk.</description>
<icon>icon-address-book</icon>
<category>Business</category>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteCRM/raw/branch/main/updates.xml</updateserver>
</extension>
<extension>
<name>MokoSuiteERP</name>
<element>pkg_mokosuiteerp</element>
<type>package</type>
<description>Layer 2 — Products, orders, invoicing, inventory, warehouses, accounting, payments.</description>
<icon>icon-briefcase</icon>
<category>Business</category>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteERP/raw/branch/main/updates.xml</updateserver>
</extension>
<extension>
<name>MokoSuiteShop</name>
<element>pkg_mokosuiteshop</element>
<type>package</type>
<description>Layer 3 — Product catalog, shopping cart, checkout, coupons. Requires MokoSuiteERP.</description>
<icon>icon-shopping-cart</icon>
<category>Business</category>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteShop/raw/branch/main/updates.xml</updateserver>
</extension>
<extension>
<name>MokoSuitePOS</name>
<element>pkg_mokosuitepos</element>
<type>package</type>
<description>Layer 3 — Touch-screen POS, multi-terminal, cash register, receipt printing.</description>
<icon>icon-calculator</icon>
<category>Business</category>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoSuitePOS/raw/branch/main/updates.xml</updateserver>
</extension>
<extension>
<name>MokoSuiteMRP</name>
<element>pkg_mokosuitemrp</element>
<type>package</type>
<description>Layer 3 — BOM, manufacturing orders, workstation management, production scheduling.</description>
<icon>icon-cog</icon>
<category>Business</category>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteMRP/raw/branch/main/updates.xml</updateserver>
</extension>
<extension>
<name>MokoSuiteHRM</name>
<element>pkg_mokosuitehrm</element>
<type>package</type>
<description>Layer 3 — Human Resource Management: employees, leave, expenses, payroll, recruiting.</description>
<icon>icon-users</icon>
<category>Business</category>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteHRM/raw/branch/main/updates.xml</updateserver>
</extension>
<extension>
<name>MokoSuiteRestaurant</name>
<element>pkg_mokosuiterestaurant</element>
<type>package</type>
<description>Layer 4 — Floor plan, table management, kitchen display, split bills, online ordering.</description>
<icon>icon-utensils</icon>
<category>Industry</category>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteRestaurant/raw/branch/main/updates.xml</updateserver>
</extension>
<extension>
<name>MokoSuiteChild</name>
<element>pkg_mokosuitechild</element>
<type>package</type>
<description>Layer 2 — Child Care Management: enrollment, attendance, billing, parent portal.</description>
<icon>icon-child</icon>
<category>Industry</category>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteChild/raw/branch/main/updates.xml</updateserver>
</extension>
<extension>
<name>MokoSuiteNPO</name>
<element>pkg_mokosuitenpo</element>
<type>package</type>
<description>Nonprofit management: donors, donations, campaigns, grants, volunteers, events.</description>
<icon>icon-heart</icon>
<category>Industry</category>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteNPO/raw/branch/main/updates.xml</updateserver>
</extension>
<extension>
<name>MokoSuiteField</name>
<element>pkg_mokosuitefield</element>
<type>package</type>
<description>Field Service — dispatch, work orders, scheduling, mobile tech, plumbing/HVAC.</description>
<icon>icon-wrench</icon>
<category>Industry</category>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteField/raw/branch/main/updates.xml</updateserver>
</extension>
<extension>
<name>MokoSuiteCreate</name>
<element>pkg_mokosuitecreate</element>
<type>package</type>
<description>Layer 2 — Creative Agency: projects, tasks, timesheets, client proofing.</description>
<icon>icon-paint-brush</icon>
<category>Industry</category>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteCreate/raw/branch/main/updates.xml</updateserver>
</extension>
<!-- ═══════════════════════════════════════════════════════════════════
Content & Community
═══════════════════════════════════════════════════════════════════ -->
<extension>
<name>MokoSuiteForms</name>
<element>pkg_mokosuiteforms</element>
<type>package</type>
<description>Form builder — custom forms, submissions, notifications, and data exports.</description>
<icon>icon-list-alt</icon>
<category>Content</category>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteForms/raw/branch/main/updates.xml</updateserver>
</extension>
<extension>
<name>MokoSuiteCommunity</name>
<element>pkg_mokosuitecommunity</element>
<type>package</type>
<description>Community profiles, connections, and activity streams for Joomla.</description>
<icon>icon-users</icon>
<category>Content</category>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteCommunity/raw/branch/main/updates.xml</updateserver>
</extension>
<extension>
<name>MokoSuiteCross</name>
<element>pkg_mokosuitecross</element>
<type>package</type>
<description>Cross-posting Joomla content to social media, email marketing, and chat platforms.</description>
<icon>icon-share-alt</icon>
<category>Content</category>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteCross/raw/branch/main/updates.xml</updateserver>
</extension>
<extension>
<name>MokoSuiteOpenGraph</name>
<element>pkg_mokosuiteopengraph</element>
<type>package</type>
<description>Open Graph, Twitter Card, JSON-LD structured data, and social sharing meta tags.</description>
<icon>icon-share-alt</icon>
<category>SEO</category>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteOpenGraph/raw/branch/main/updates.xml</updateserver>
</extension>
<extension>
<name>MokoSuiteStoreLocator</name>
<element>pkg_mokosuitestorelocator</element>
<type>package</type>
<description>Interactive map, location search, and admin management for store locations.</description>
<icon>icon-map-marker-alt</icon>
<category>Content</category>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteStoreLocator/raw/branch/main/updates.xml</updateserver>
</extension>
<!-- ═══════════════════════════════════════════════════════════════════
Standalone Extensions (MokoJoom)
═══════════════════════════════════════════════════════════════════ -->
<extension>
<name>MokoJoomHero</name>
<element>mod_mokojoomhero</element>
<type>module</type>
<description>Random hero image module from a configurable folder.</description>
<description>Hero module — image slideshow, video backgrounds, solid color/gradient, parallax.</description>
<icon>icon-image</icon>
<category>Modules</category>
<article>https://mokoconsulting.tech/support/products/mokojoomhero</article>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/raw/branch/dev/updates.xml</updateserver>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/raw/branch/main/updates.xml</updateserver>
</extension>
<!-- ═══════════════════════════════════════════════════════════════════
Templates
═══════════════════════════════════════════════════════════════════ -->
<extension>
<name>MokoJoomCommunity</name>
<element>pkg_mokojoomcommunity</element>
<type>package</type>
<description>Community Builder integration package with custom fields and user management.</description>
<icon>icon-users</icon>
<category>Community</category>
<article>https://mokoconsulting.tech/support/products/mokojoomcommunity</article>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoJoomCommunity/raw/branch/dev/updates.xml</updateserver>
</extension>
<extension>
<name>MokoJoomCross</name>
<element>plg_system_mokojoomcross</element>
<type>plugin</type>
<description>Cross-extension integration plugin for Joomla component interoperability.</description>
<icon>icon-link</icon>
<category>Plugins</category>
<article>https://mokoconsulting.tech/support/products/mokojoomcross</article>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoJoomCross/raw/branch/dev/updates.xml</updateserver>
</extension>
<extension>
<name>MokoJoomStoreLocator</name>
<element>mod_mokojoomstorelocator</element>
<type>module</type>
<description>Store locator module with Google Maps integration and search.</description>
<icon>icon-map-marker-alt</icon>
<category>Modules</category>
<article>https://mokoconsulting.tech/support/products/mokojoomstorelocator</article>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoJoomStoreLocator/raw/branch/dev/updates.xml</updateserver>
</extension>
<extension>
<name>DPCalendar API</name>
<element>mokodpcalendarapi</element>
<type>plugin</type>
<description>Web Services plugin exposing DPCalendar events and calendars via REST API.</description>
<icon>icon-calendar</icon>
<category>Plugins</category>
<article>https://mokoconsulting.tech/support/products/mokodpcalendarapi</article>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoDPCalendarAPI/raw/branch/dev/updates.xml</updateserver>
</extension>
<extension>
<name>Gallery Calendar</name>
<element>mokogallerycalendar</element>
<type>plugin</type>
<description>JoomGallery and DPCalendar integration — link galleries to events.</description>
<icon>icon-images</icon>
<category>Plugins</category>
<article>https://mokoconsulting.tech/support/products/mokogallerycalendar</article>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoGalleryCalendar/raw/branch/dev/updates.xml</updateserver>
<name>MokoOnyx</name>
<element>mokoonyx</element>
<type>template</type>
<description>Modern Joomla site template with dark mode, custom layouts, and MokoSuite integration.</description>
<icon>icon-paint-brush</icon>
<category>Templates</category>
<updateserver>https://git.mokoconsulting.tech/MokoConsulting/MokoOnyx/raw/branch/main/updates.xml</updateserver>
</extension>
</catalog>
@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<config>
<fieldset name="general" label="General" description="General component settings.">
<field name="brand_name" type="text" default="MokoSuiteClient"
<field name="brand_name" type="text" default="MokoSuite"
label="Brand Name"
description="Displayed in the admin sidebar, dashboard, and emails."
hint="MokoSuiteClient" />
hint="MokoSuite" />
<field name="support_email" type="email" default=""
label="Support Email"
description="Reply-to address for outbound notification emails."
hint="support@example.com" />
</fieldset>
<fieldset name="notifications" label="Email Notifications" description="Configure email recipients for ticket and security notifications.">
<fieldset name="notifications" label="Notifications" description="Email and push notification settings.">
<field name="admin_emails" type="text" default=""
label="Admin Email Addresses"
description="Comma-separated email addresses to receive all notifications."
@@ -31,7 +31,7 @@
<field name="spacer_ntfy" type="spacer" label="Push Notifications (ntfy)" />
<field name="ntfy_enabled" type="radio" default="0"
label="Enable ntfy Push"
description="Send push notifications via ntfy for ticket and security events."
description="Send push notifications via ntfy for security and system events."
class="btn-group btn-group-yesno">
<option value="1">JYES</option>
<option value="0">JNO</option>
@@ -40,13 +40,13 @@
label="ntfy Server URL"
description="Full URL to your ntfy server."
showon="ntfy_enabled:1" />
<field name="ntfy_topic" type="text" default="mokosuiteclient-tickets"
label="Ticket Topic"
description="ntfy topic name for helpdesk ticket notifications."
<field name="ntfy_topic" type="text" default="mokosuite-alerts"
label="Alert Topic"
description="ntfy topic name for general alert notifications."
showon="ntfy_enabled:1" />
<field name="ntfy_security_topic" type="text" default="mokosuiteclient-security"
<field name="ntfy_security_topic" type="text" default="mokosuite-security"
label="Security Topic"
description="ntfy topic name for security alert notifications. Falls back to ticket topic if empty."
description="ntfy topic name for security alerts. Falls back to alert topic if empty."
showon="ntfy_enabled:1" />
<field name="ntfy_token" type="password" default=""
label="ntfy Auth Token"
@@ -54,59 +54,42 @@
showon="ntfy_enabled:1" />
</fieldset>
<fieldset name="helpdesk" label="Helpdesk Settings" description="Default helpdesk behavior.">
<field name="default_category" type="sql" default=""
label="Default Ticket Category"
description="Category assigned to tickets without a selection."
query="SELECT id AS value, title AS text FROM #__mokosuiteclient_ticket_categories WHERE published = 1 ORDER BY ordering" />
<field name="autoclose_days" type="number" default="7"
label="Auto-Close After (days)"
description="Resolved tickets are auto-closed after this many days. 0 = disabled." />
<field name="kb_search_enabled" type="radio" default="1"
label="KB Search on Ticket Forms"
description="Show knowledge base search before ticket submission."
class="btn-group btn-group-yesno">
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field name="satisfaction_enabled" type="radio" default="1"
label="Satisfaction Ratings"
description="Show rating prompt on resolved tickets."
class="btn-group btn-group-yesno">
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field name="max_attachment_size" type="number" default="10"
label="Max Attachment Size (MB)"
description="Maximum upload size per file in megabytes." />
<fieldset name="content_tools" label="Content Tools" description="Settings for content tag engines and replacements.">
<field name="spacer_snippets" type="spacer" label="Snippets" />
<field name="snippets_default_category" type="text" default=""
label="Default Snippet Category"
description="Category assigned to new snippets if none selected." />
<field name="spacer_templates" type="spacer" label="Content Templates" />
<field name="templates_default_category" type="text" default=""
label="Default Template Category"
description="Category assigned to new content templates if none selected." />
<field name="spacer_replacements" type="spacer" label="Replacements" />
<field name="replacements_max_rules" type="number" default="100"
label="Max Active Rules"
description="Maximum number of replacement rules processed per page load. 0 = unlimited." />
</fieldset>
<fieldset name="email_to_ticket" label="Email-to-Ticket (IMAP)" description="Create tickets from incoming emails via IMAP polling.">
<field name="imap_host" type="text" default=""
label="IMAP Server"
description="IMAP hostname (e.g. imap.gmail.com)"
hint="imap.gmail.com" />
<field name="imap_port" type="number" default="993"
label="Port"
description="IMAP port (993 for SSL, 143 for plain)" />
<field name="imap_ssl" type="radio" default="1"
label="Use SSL"
class="btn-group btn-group-yesno">
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field name="imap_user" type="text" default=""
label="Username"
description="IMAP login username or email address." />
<field name="imap_password" type="password" default=""
label="Password"
description="IMAP password or app-specific password." />
<field name="imap_folder" type="text" default="INBOX"
label="Inbox Folder"
description="IMAP folder to poll for new messages." />
<field name="imap_processed_folder" type="text" default="INBOX.Processed"
label="Processed Folder"
description="Move processed emails to this folder. Leave empty to just mark as read." />
<fieldset name="impersonation" label="User Impersonation" description="Skeleton Key — log into the frontend as another user for support.">
<field name="skeleton_key_control_groups" type="usergrouplist" default="8"
label="Groups Allowed to Impersonate"
description="User groups that can log in as another user."
multiple="true"
layout="joomla.form.field.list-fancy-select" />
<field name="skeleton_key_target_groups" type="usergrouplist" default="2"
label="Groups That Can Be Impersonated"
description="User groups whose accounts can be accessed via impersonation."
multiple="true"
layout="joomla.form.field.list-fancy-select" />
<field name="skeleton_key_blocked_groups" type="usergrouplist" default="7,8"
label="Groups That Cannot Be Impersonated"
description="User groups protected from impersonation (overrides target groups)."
multiple="true"
layout="joomla.form.field.list-fancy-select" />
<field name="skeleton_key_cookie_lifetime" type="number" default="10"
label="Cookie Lifetime (seconds)"
description="How long the impersonation cookie remains valid. Short values are more secure." />
</fieldset>
<fieldset name="permissions" label="COM_MOKOSUITECLIENT_ACL_TITLE"
@@ -1,8 +1,11 @@
; MokoSuiteClient Admin Dashboard - Language Strings
; MokoSuite Admin Dashboard - Language Strings
; Copyright (C) 2026 Moko Consulting. All rights reserved.
; License: GPL-3.0-or-later
COM_MOKOSUITECLIENT_DASHBOARD_TITLE="MokoSuiteClient Control Panel"
COM_MOKOSUITECLIENT_DASHBOARD_TITLE="MokoSuite Control Panel"
; Joomla core fallback keys
COM_ACTIONLOGS_DISABLED="User Action Logging is disabled. Please enable the &quot;Action Log - Joomla&quot; plugin."
COM_MOKOSUITECLIENT_SITE="Site"
COM_MOKOSUITECLIENT_DATABASE="Database"
COM_MOKOSUITECLIENT_DEBUG_ON="Debug ON"
@@ -20,22 +23,29 @@ COM_MOKOSUITECLIENT_EXTENSIONS_TITLE="Moko Extensions"
COM_MOKOSUITECLIENT_EXTENSIONS_INFO="Install Moko Consulting Joomla packages from the official release server. Updates are handled through Joomla's native System > Update mechanism — each package registers its own update server."
COM_MOKOSUITECLIENT_EXTENSIONS_LINK="Moko Extensions"
COM_MOKOSUITECLIENT_HTACCESS_TITLE=".htaccess Maker"
COM_MOKOSUITECLIENT_TICKETS_TITLE="Helpdesk"
; ACL
COM_MOKOSUITECLIENT_ACL_TITLE="Permissions"
COM_MOKOSUITECLIENT_ACL_DESC="Manage access permissions for MokoSuite component features."
COM_MOKOSUITECLIENT_ACL_DASHBOARD="View Dashboard"
COM_MOKOSUITECLIENT_ACL_DASHBOARD_DESC="Allow viewing the MokoSuiteClient control panel dashboard."
COM_MOKOSUITECLIENT_ACL_DASHBOARD_DESC="Allow viewing the MokoSuite control panel dashboard."
COM_MOKOSUITECLIENT_ACL_EXTENSIONS="Manage Extensions"
COM_MOKOSUITECLIENT_ACL_EXTENSIONS_DESC="Allow installing and uninstalling Moko extensions."
COM_MOKOSUITECLIENT_ACL_HTACCESS="Manage .htaccess"
COM_MOKOSUITECLIENT_ACL_HTACCESS_DESC="Allow editing and saving the .htaccess configuration."
COM_MOKOSUITECLIENT_ACL_TICKETS="View Tickets"
COM_MOKOSUITECLIENT_ACL_TICKETS_DESC="Allow viewing helpdesk tickets."
COM_MOKOSUITECLIENT_ACL_TICKETS_CREATE="Create Tickets"
COM_MOKOSUITECLIENT_ACL_TICKETS_CREATE_DESC="Allow creating new helpdesk tickets."
COM_MOKOSUITECLIENT_ACL_TICKETS_ASSIGN="Assign Tickets"
COM_MOKOSUITECLIENT_ACL_TICKETS_ASSIGN_DESC="Allow assigning tickets to other users."
COM_MOKOSUITECLIENT_ACL_PLUGINS_TOGGLE="Toggle Plugins"
COM_MOKOSUITECLIENT_ACL_PLUGINS_TOGGLE_DESC="Allow enabling and disabling MokoSuiteClient feature plugins."
COM_MOKOSUITECLIENT_ACL_PLUGINS_TOGGLE_DESC="Allow enabling and disabling MokoSuite feature plugins."
COM_MOKOSUITECLIENT_ACL_CACHE="Clear Cache"
COM_MOKOSUITECLIENT_ACL_CACHE_DESC="Allow clearing the Joomla cache from the dashboard."
COM_MOKOSUITECLIENT_ACL_HTACCESS="Manage .htaccess"
COM_MOKOSUITECLIENT_ACL_HTACCESS_DESC="Allow editing and saving the .htaccess and nginx configuration."
COM_MOKOSUITECLIENT_ACL_WAFLOG="View WAF Log"
COM_MOKOSUITECLIENT_ACL_WAFLOG_DESC="Allow viewing the Web Application Firewall activity log."
COM_MOKOSUITECLIENT_ACL_IMPERSONATE="Impersonate Users"
COM_MOKOSUITECLIENT_ACL_IMPERSONATE_DESC="Allow logging into the frontend as another user for support purposes."
COM_MOKOSUITECLIENT_ACL_SNIPPETS="Manage Snippets"
COM_MOKOSUITECLIENT_ACL_SNIPPETS_DESC="Allow creating, editing, and deleting reusable content snippets."
COM_MOKOSUITECLIENT_ACL_TEMPLATES="Manage Content Templates"
COM_MOKOSUITECLIENT_ACL_TEMPLATES_DESC="Allow creating, editing, and deleting article content templates."
COM_MOKOSUITECLIENT_ACL_REPLACEMENTS="Manage Replacements"
COM_MOKOSUITECLIENT_ACL_REPLACEMENTS_DESC="Allow creating, editing, and deleting text replacement rules."
COM_MOKOSUITECLIENT_ACL_CONDITIONS="Manage Conditions"
COM_MOKOSUITECLIENT_ACL_CONDITIONS_DESC="Allow creating, editing, and deleting display condition sets for modules and content."
@@ -2,9 +2,9 @@
; Copyright (C) 2026 Moko Consulting. All rights reserved.
; License: GPL-3.0-or-later
COM_MOKOSUITECLIENT="MokoSuiteClient"
COM_MOKOSUITECLIENT_DESCRIPTION="MokoSuiteClient admin dashboard and REST API. Control panel for managing site features, health monitoring, and remote management."
COM_MOKOSUITECLIENT_DASHBOARD_TITLE="MokoSuiteClient Control Panel"
COM_MOKOSUITECLIENT="MokoSuite"
COM_MOKOSUITECLIENT_DESCRIPTION="MokoSuite admin dashboard and REST API. Control panel for managing site features, health monitoring, and remote management."
COM_MOKOSUITECLIENT_DASHBOARD_TITLE="MokoSuite Control Panel"
COM_MOKOSUITECLIENT_MENU_DASHBOARD="Dashboard"
COM_MOKOSUITECLIENT_MENU_EXTENSIONS="Moko Extensions"
COM_MOKOSUITECLIENT_MENU_PLUGINS="Feature Plugins"
@@ -215,3 +215,138 @@ INSERT IGNORE INTO `#__mokosuiteclient_retention_policies` (`id`, `content_type`
(4, 'inactive_users', 730, 'anonymize', 0, 'Anonymize users inactive for 2 years (disabled by default)'),
(5, 'closed_tickets', 365, 'anonymize', 0, 'Anonymize closed tickets older than 1 year (disabled by default)');
-- ============================================================
-- License Cache — stores MokoGitea validation results
-- ============================================================
CREATE TABLE IF NOT EXISTS `#__mokosuite_license_cache` (
`dlid_hash` CHAR(64) NOT NULL COMMENT 'SHA-256 of DLID (never store raw DLID)',
`response_data` TEXT NOT NULL COMMENT 'JSON validation response from MokoGitea',
`checked_at` DATETIME NOT NULL,
PRIMARY KEY (`dlid_hash`),
KEY `idx_checked` (`checked_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ============================================================
-- Conditions Engine — rule-based display conditions
-- ============================================================
CREATE TABLE IF NOT EXISTS `#__mokosuiteclient_conditions` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`alias` VARCHAR(100) NOT NULL DEFAULT '',
`name` VARCHAR(100) NOT NULL DEFAULT '',
`description` TEXT NOT NULL,
`category` VARCHAR(50) NOT NULL DEFAULT '',
`color` VARCHAR(8) DEFAULT NULL,
`match_all` TINYINT(1) NOT NULL DEFAULT 1,
`published` TINYINT(1) NOT NULL DEFAULT 1,
`hash` VARCHAR(32) NOT NULL DEFAULT '',
`checked_out` INT UNSIGNED DEFAULT NULL,
`checked_out_time` DATETIME DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_published` (`published`),
KEY `idx_alias` (`alias`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `#__mokosuiteclient_conditions_groups` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`condition_id` INT UNSIGNED NOT NULL,
`match_all` TINYINT(1) NOT NULL DEFAULT 1,
`ordering` INT UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
KEY `idx_condition` (`condition_id`),
KEY `idx_ordering` (`condition_id`, `ordering`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `#__mokosuiteclient_conditions_rules` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`group_id` INT UNSIGNED NOT NULL,
`type` VARCHAR(50) NOT NULL DEFAULT '',
`exclude` TINYINT(1) NOT NULL DEFAULT 0,
`params` TEXT NOT NULL,
`ordering` INT UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
KEY `idx_group` (`group_id`),
KEY `idx_type` (`type`),
KEY `idx_ordering` (`group_id`, `ordering`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `#__mokosuiteclient_conditions_map` (
`condition_id` INT UNSIGNED NOT NULL,
`extension` VARCHAR(50) NOT NULL DEFAULT '',
`item_id` INT UNSIGNED NOT NULL DEFAULT 0,
UNIQUE KEY `idx_unique` (`condition_id`, `item_id`, `extension`),
KEY `idx_ext_item` (`extension`, `item_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- Snippets — reusable text/HTML blocks insertable via {snippet}
-- ============================================================
CREATE TABLE IF NOT EXISTS `#__mokosuiteclient_snippets` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`alias` VARCHAR(100) NOT NULL DEFAULT '',
`name` VARCHAR(100) NOT NULL DEFAULT '',
`description` TEXT NOT NULL,
`category` VARCHAR(50) NOT NULL DEFAULT '',
`color` VARCHAR(8) DEFAULT NULL,
`content` MEDIUMTEXT NOT NULL,
`params` TEXT NOT NULL,
`published` TINYINT(1) NOT NULL DEFAULT 0,
`ordering` INT NOT NULL DEFAULT 0,
`checked_out` INT UNSIGNED DEFAULT NULL,
`checked_out_time` DATETIME DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_alias` (`alias`),
KEY `idx_published` (`published`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================================
-- ReReplacer — backend-managed string/regex replacement rules
-- ============================================================
CREATE TABLE IF NOT EXISTS `#__mokosuiteclient_replacements` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(100) NOT NULL DEFAULT '',
`search` TEXT NOT NULL,
`replace_value` TEXT NOT NULL,
`area` VARCHAR(20) NOT NULL DEFAULT 'both',
`regex` TINYINT(1) NOT NULL DEFAULT 0,
`casesensitive` TINYINT(1) NOT NULL DEFAULT 0,
`category` VARCHAR(50) NOT NULL DEFAULT '',
`published` TINYINT(1) NOT NULL DEFAULT 0,
`description` TEXT NOT NULL,
`enable_in_admin` TINYINT(1) NOT NULL DEFAULT 0,
`color` VARCHAR(8) DEFAULT NULL,
`ordering` INT NOT NULL DEFAULT 0,
`checked_out` INT UNSIGNED DEFAULT NULL,
`checked_out_time` DATETIME DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_published` (`published`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Content Templates
--
CREATE TABLE IF NOT EXISTS `#__mokosuiteclient_content_templates` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`alias` VARCHAR(100) NOT NULL DEFAULT '',
`name` VARCHAR(255) NOT NULL DEFAULT '',
`description` TEXT NOT NULL,
`category` VARCHAR(50) NOT NULL DEFAULT '',
`color` VARCHAR(8) DEFAULT NULL,
`template_data` MEDIUMTEXT NOT NULL,
`joomla_category_id` INT NOT NULL DEFAULT 0,
`access` INT UNSIGNED NOT NULL DEFAULT 1,
`published` TINYINT(1) NOT NULL DEFAULT 1,
`ordering` INT NOT NULL DEFAULT 0,
`checked_out` INT UNSIGNED DEFAULT NULL,
`checked_out_time` DATETIME DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_published` (`published`),
KEY `idx_alias` (`alias`),
KEY `idx_category` (`joomla_category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
@@ -0,0 +1 @@
/* 02.47.95 — no schema changes */
@@ -24,19 +24,18 @@ class DisplayController extends BaseController
* ACL map: view name => required permission.
*/
private const VIEW_ACL = [
'dashboard' => 'mokosuiteclient.dashboard',
'extensions' => 'mokosuiteclient.extensions',
'htaccess' => 'mokosuiteclient.htaccess',
'tickets' => 'mokosuiteclient.tickets',
'ticket' => 'mokosuiteclient.tickets',
'privacy' => 'core.admin',
'waflog' => 'core.admin',
'categories' => 'mokosuiteclient.tickets',
'canned' => 'mokosuiteclient.tickets',
'automation' => 'core.admin',
'database' => 'core.admin',
'cleanup' => 'mokosuiteclient.cache',
'ticketsettings' => 'core.admin',
'dashboard' => 'mokosuiteclient.dashboard',
'extensions' => 'mokosuiteclient.extensions',
'htaccess' => 'mokosuiteclient.htaccess',
'privacy' => 'core.admin',
'waflog' => 'mokosuiteclient.security.waflog',
'automation' => 'core.admin',
'database' => 'core.admin',
'cleanup' => 'mokosuiteclient.cache',
'snippets' => 'mokosuiteclient.snippets.manage',
'templates' => 'mokosuiteclient.templates.manage',
'replacements' => 'mokosuiteclient.replacements.manage',
'conditions' => 'mokosuiteclient.conditions.manage',
];
public function display($cachable = false, $urlparams = [])
@@ -90,22 +89,22 @@ class DisplayController extends BaseController
try
{
$monitorPlugin = \Joomla\CMS\Plugin\PluginHelper::getPlugin('system', 'mokosuiteclient_monitor');
$corePlugin = \Joomla\CMS\Plugin\PluginHelper::getPlugin('system', 'mokosuiteclient');
if (!$monitorPlugin)
if (!$corePlugin)
{
$this->jsonResponse(['success' => false, 'message' => 'Monitor plugin not enabled.']);
$this->jsonResponse(['success' => false, 'message' => 'Core plugin not enabled.']);
return;
}
$params = new \Joomla\Registry\Registry($monitorPlugin->params);
$baseUrl = rtrim($params->get('base_url', ''), '/');
$params = new \Joomla\Registry\Registry($corePlugin->params);
$baseUrl = rtrim($params->get('monitor_base_url', ''), '/');
// Fall back to manifest XML default if not yet saved in params
// Fall back to manifest XML default
if (empty($baseUrl))
{
$manifestFile = JPATH_PLUGINS . '/system/mokosuiteclient_monitor/mokosuiteclient_monitor.xml';
$manifestFile = JPATH_PLUGINS . '/system/mokosuiteclient/mokosuiteclient.xml';
if (is_file($manifestFile))
{
@@ -113,7 +112,7 @@ class DisplayController extends BaseController
if ($xml)
{
foreach ($xml->xpath('//field[@name="base_url"]') as $field)
foreach ($xml->xpath('//field[@name="monitor_base_url"]') as $field)
{
$baseUrl = rtrim((string) $field['default'], '/');
break;
@@ -124,14 +123,12 @@ class DisplayController extends BaseController
if (empty($baseUrl))
{
$this->jsonResponse(['success' => false, 'message' => 'MokoSuiteClientHQ URL not configured in monitor plugin.']);
$this->jsonResponse(['success' => false, 'message' => 'MokoSuiteClientHQ URL not configured.']);
return;
}
$corePlugin = \Joomla\CMS\Plugin\PluginHelper::getPlugin('system', 'mokosuiteclient');
$coreParams = new \Joomla\Registry\Registry($corePlugin ? $corePlugin->params : '{}');
$healthToken = $coreParams->get('health_api_token', '');
$healthToken = $params->get('health_api_token', '');
if (empty($healthToken))
{
@@ -144,6 +141,22 @@ class DisplayController extends BaseController
$domain = parse_url($siteUrl, PHP_URL_HOST) ?: '';
$timestamp = time();
// Discover all MokoSuite ecosystem packages for HQ
$mokoPackages = [];
try {
$pkgDb = Factory::getContainer()->get(\Joomla\Database\DatabaseInterface::class);
$pkgQuery = $pkgDb->getQuery(true)
->select([$pkgDb->quoteName('element'), $pkgDb->quoteName('manifest_cache')])
->from($pkgDb->quoteName('#__extensions'))
->where('(' . $pkgDb->quoteName('element') . ' LIKE ' . $pkgDb->quote('pkg_mokosuite%')
. ' OR ' . $pkgDb->quoteName('element') . ' LIKE ' . $pkgDb->quote('pkg_mokojoom%') . ')');
$pkgDb->setQuery($pkgQuery);
foreach ($pkgDb->loadObjectList() ?: [] as $pkg) {
$m = json_decode($pkg->manifest_cache ?? '{}');
$mokoPackages[$pkg->element] = $m->version ?? '';
}
} catch (\Throwable $e) {}
$payload = json_encode([
'token' => $healthToken,
'domain' => $domain,
@@ -152,16 +165,17 @@ class DisplayController extends BaseController
'joomla_version' => (new \Joomla\CMS\Version())->getShortVersion(),
'php_version' => PHP_VERSION,
'timestamp' => $timestamp,
'moko_packages' => $mokoPackages,
], JSON_UNESCAPED_SLASHES);
// RSA sign the request
$headers = ['Content-Type: application/json'];
$signingKeyB64 = $params->get('signing_key', '');
$signingKeyB64 = $params->get('monitor_signing_key', '');
// Fall back to manifest XML default if not yet saved in params
// Fall back to manifest XML default
if (empty($signingKeyB64))
{
$manifestFile = JPATH_PLUGINS . '/system/mokosuiteclient_monitor/mokosuiteclient_monitor.xml';
$manifestFile = JPATH_PLUGINS . '/system/mokosuiteclient/mokosuiteclient.xml';
if (is_file($manifestFile))
{
@@ -169,7 +183,7 @@ class DisplayController extends BaseController
if ($xml)
{
foreach ($xml->xpath('//field[@name="signing_key"]') as $field)
foreach ($xml->xpath('//field[@name="monitor_signing_key"]') as $field)
{
$signingKeyB64 = (string) $field['default'];
break;
@@ -190,13 +204,13 @@ class DisplayController extends BaseController
if (openssl_sign($message, $signature, $privateKey, OPENSSL_ALGO_SHA256))
{
$headers[] = 'X-MokoSuiteClient-Signature: ' . base64_encode($signature);
$headers[] = 'X-MokoSuiteClient-Timestamp: ' . $timestamp;
$headers[] = 'X-MokoSuite-Signature: ' . base64_encode($signature);
$headers[] = 'X-MokoSuite-Timestamp: ' . $timestamp;
}
}
}
$endpoint = $baseUrl . '/api/index.php/v1/mokosuiteclienthq/heartbeat';
$endpoint = $baseUrl . '/api/index.php/v1/mokosuitehq/heartbeat';
$ch = curl_init($endpoint);
curl_setopt_array($ch, [
@@ -206,7 +220,7 @@ class DisplayController extends BaseController
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 15,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYPEER => true,
]);
$response = curl_exec($ch);
@@ -350,75 +364,10 @@ class DisplayController extends BaseController
}
// ==================================================================
// Tickets
// Regular Labs Import
// ==================================================================
public function createTicket()
{
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
if (!$this->checkAcl('mokosuiteclient.tickets.create'))
{
$this->jsonForbidden();
return;
}
$input = Factory::getApplication()->getInput();
$this->jsonResponse($this->getModel('Tickets')->createTicket([
'subject' => $input->getString('subject', ''),
'body' => $input->getRaw('body', ''),
'priority' => $input->getString('priority', 'normal'),
'category_id' => $input->getInt('category_id', 0),
'contact_id' => $input->getInt('contact_id', 0),
'assign_users' => $input->get('assign_users', [], 'ARRAY'),
'assign_groups' => $input->get('assign_groups', [], 'ARRAY'),
'custom_fields' => $input->get('custom_fields', [], 'ARRAY'),
]));
}
public function addTicketReply()
{
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
if (!$this->checkAcl('mokosuiteclient.tickets'))
{
$this->jsonForbidden();
return;
}
$input = Factory::getApplication()->getInput();
$this->jsonResponse($this->getModel('Tickets')->addReply(
$input->getInt('ticket_id', 0),
$input->getRaw('body', ''),
(bool) $input->getInt('is_internal', 0)
));
}
public function updateTicketStatus()
{
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
if (!$this->checkAcl('mokosuiteclient.tickets'))
{
$this->jsonForbidden();
return;
}
$input = Factory::getApplication()->getInput();
$this->jsonResponse($this->getModel('Tickets')->updateStatus(
$input->getInt('ticket_id', 0),
$input->getInt('status', 0)
));
}
// ==================================================================
// Ticket Settings — Status/Priority CRUD
// ==================================================================
public function saveStatus()
public function importRegularLabs()
{
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
@@ -428,106 +377,165 @@ class DisplayController extends BaseController
return;
}
$input = Factory::getApplication()->getInput();
$this->jsonResponse($this->getModel('Tickets')->saveStatus([
'id' => $input->getInt('id', 0),
'title' => $input->getString('title', ''),
'alias' => $input->getString('alias', ''),
'color' => $input->getString('color', 'bg-secondary'),
'is_default' => $input->getInt('is_default', 0),
'is_closed' => $input->getInt('is_closed', 0),
'ordering' => $input->getInt('ordering', 0),
]));
}
public function deleteStatus()
{
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
if (!$this->checkAcl('core.admin'))
{
$this->jsonForbidden();
return;
}
$id = Factory::getApplication()->getInput()->getInt('id', 0);
$this->jsonResponse($this->getModel('Tickets')->deleteStatus($id));
}
public function savePriority()
{
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
if (!$this->checkAcl('core.admin'))
{
$this->jsonForbidden();
return;
}
$input = Factory::getApplication()->getInput();
$this->jsonResponse($this->getModel('Tickets')->savePriority([
'id' => $input->getInt('id', 0),
'title' => $input->getString('title', ''),
'alias' => $input->getString('alias', ''),
'color' => $input->getString('color', 'bg-secondary'),
'is_default' => $input->getInt('is_default', 0),
'ordering' => $input->getInt('ordering', 0),
]));
}
public function deletePriority()
{
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
if (!$this->checkAcl('core.admin'))
{
$this->jsonForbidden();
return;
}
$id = Factory::getApplication()->getInput()->getInt('id', 0);
$this->jsonResponse($this->getModel('Tickets')->deletePriority($id));
}
// ==================================================================
// KB Search
// ==================================================================
public function searchKb()
{
$query = Factory::getApplication()->getInput()->getString('q', '');
if (strlen($query) < 3)
{
$this->jsonResponse(['results' => []]);
}
try
{
$db = Factory::getDbo();
$escaped = $db->quote('%' . $db->escape($query, true) . '%');
$db = Factory::getContainer()->get(\Joomla\Database\DatabaseInterface::class);
$prefix = $db->getPrefix();
$tables = $db->getTableList();
$results = [];
$results = $db->setQuery(
$db->getQuery(true)
->select([$db->quoteName('l.title'), $db->quoteName('l.url'), $db->quoteName('l.description')])
->from($db->quoteName('#__finder_links', 'l'))
->where($db->quoteName('l.published') . ' = 1')
->where('(' . $db->quoteName('l.title') . ' LIKE ' . $escaped
. ' OR ' . $db->quoteName('l.description') . ' LIKE ' . $escaped . ')')
->order($db->quoteName('l.title') . ' ASC')
->setLimit(8)
)->loadObjectList() ?: [];
foreach ($results as $r)
// ── Conditions (4 tables) ──────────────────────────────
if (in_array($prefix . 'conditions', $tables)
&& in_array($prefix . 'mokosuiteclient_conditions', $tables))
{
$r->description = mb_substr(strip_tags($r->description ?? ''), 0, 150);
// Check if already imported
$existing = (int) $db->setQuery("SELECT COUNT(*) FROM " . $db->quoteName('#__mokosuiteclient_conditions'))->loadResult();
if ($existing === 0)
{
// conditions
$db->setQuery("INSERT INTO " . $db->quoteName('#__mokosuiteclient_conditions')
. " (id, alias, name, description, category, color, match_all, published, hash, checked_out, checked_out_time)"
. " SELECT id, alias, name, description, category, color, match_all, published, hash, checked_out, checked_out_time"
. " FROM " . $db->quoteName('#__conditions'))->execute();
$c1 = $db->getAffectedRows();
// conditions_groups
if (in_array($prefix . 'conditions_groups', $tables))
{
$db->setQuery("INSERT INTO " . $db->quoteName('#__mokosuiteclient_conditions_groups')
. " (id, condition_id, match_all, ordering)"
. " SELECT id, condition_id, match_all, ordering"
. " FROM " . $db->quoteName('#__conditions_groups'))->execute();
}
// conditions_rules
if (in_array($prefix . 'conditions_rules', $tables))
{
$db->setQuery("INSERT INTO " . $db->quoteName('#__mokosuiteclient_conditions_rules')
. " (id, group_id, type, exclude, params, ordering)"
. " SELECT id, group_id, type, exclude, params, ordering"
. " FROM " . $db->quoteName('#__conditions_rules'))->execute();
}
// conditions_map
if (in_array($prefix . 'conditions_map', $tables))
{
$db->setQuery("INSERT INTO " . $db->quoteName('#__mokosuiteclient_conditions_map')
. " (condition_id, extension, item_id)"
. " SELECT condition_id, extension, item_id"
. " FROM " . $db->quoteName('#__conditions_map'))->execute();
}
$results['conditions'] = $c1 . ' condition sets imported';
}
else
{
$results['conditions'] = 'skipped (already has data)';
}
}
$this->jsonResponse(['results' => $results]);
// ── Snippets ──────────────────────────────────────────
if (in_array($prefix . 'snippets', $tables)
&& in_array($prefix . 'mokosuiteclient_snippets', $tables))
{
$existing = (int) $db->setQuery("SELECT COUNT(*) FROM " . $db->quoteName('#__mokosuiteclient_snippets'))->loadResult();
if ($existing === 0)
{
$db->setQuery("INSERT INTO " . $db->quoteName('#__mokosuiteclient_snippets')
. " (id, alias, name, description, category, color, content, params, published, ordering, checked_out, checked_out_time)"
. " SELECT id, alias, name, description, category, color, content, params, published, ordering, checked_out, checked_out_time"
. " FROM " . $db->quoteName('#__snippets'))->execute();
$results['snippets'] = $db->getAffectedRows() . ' snippets imported';
}
else
{
$results['snippets'] = 'skipped (already has data)';
}
}
// ── ReReplacer ────────────────────────────────────────
if (in_array($prefix . 'rereplacer', $tables)
&& in_array($prefix . 'mokosuiteclient_replacements', $tables))
{
$existing = (int) $db->setQuery("SELECT COUNT(*) FROM " . $db->quoteName('#__mokosuiteclient_replacements'))->loadResult();
if ($existing === 0)
{
// RL uses 'replace' column, we use 'replace_value'; RL 'area' is text (JSON), we use varchar
$db->setQuery("INSERT INTO " . $db->quoteName('#__mokosuiteclient_replacements')
. " (id, name, search, replace_value, area, published, description, ordering, checked_out, checked_out_time)"
. " SELECT id, name, search, `replace`, 'both', published, description, ordering, checked_out, checked_out_time"
. " FROM " . $db->quoteName('#__rereplacer'))->execute();
$results['replacements'] = $db->getAffectedRows() . ' replacement rules imported';
}
else
{
$results['replacements'] = 'skipped (already has data)';
}
}
// ── Content Templater ─────────────────────────────────
if (in_array($prefix . 'contenttemplater', $tables)
&& in_array($prefix . 'mokosuiteclient_content_templates', $tables))
{
$existing = (int) $db->setQuery("SELECT COUNT(*) FROM " . $db->quoteName('#__mokosuiteclient_content_templates'))->loadResult();
if ($existing === 0)
{
$db->setQuery("INSERT INTO " . $db->quoteName('#__mokosuiteclient_content_templates')
. " (id, name, description, category, color, template_data, published, ordering, checked_out, checked_out_time)"
. " SELECT id, name, description, category, color, content, published, ordering, checked_out, checked_out_time"
. " FROM " . $db->quoteName('#__contenttemplater'))->execute();
$results['templates'] = $db->getAffectedRows() . ' content templates imported';
}
else
{
$results['templates'] = 'skipped (already has data)';
}
}
if (empty($results))
{
$this->jsonResponse(['success' => false, 'message' => 'No Regular Labs data found to import.']);
}
else
{
$summary = implode('; ', array_map(fn($k, $v) => ucfirst($k) . ': ' . $v, array_keys($results), $results));
$this->jsonResponse(['success' => true, 'message' => 'Import complete. ' . $summary]);
}
}
catch (\Throwable $e)
{
$this->jsonResponse(['results' => []]);
$this->jsonResponse(['success' => false, 'message' => 'Import error: ' . $e->getMessage()]);
}
}
// ==================================================================
// Support PIN
// ==================================================================
public function requestPin()
{
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
if (!$this->checkAcl('mokosuiteclient.dashboard'))
{
$this->jsonForbidden();
return;
}
try
{
$db = Factory::getContainer()->get(\Joomla\Database\DatabaseInterface::class);
$result = \Moko\Component\MokoSuiteClient\Administrator\Helper\SupportPinHelper::requestNew($db);
$this->jsonResponse($result);
}
catch (\Throwable $e)
{
$this->jsonResponse(['success' => false, 'message' => 'Error: ' . $e->getMessage()]);
}
}
@@ -568,218 +576,6 @@ class DisplayController extends BaseController
$this->jsonResponse($model->cleanDirectory($dirKey));
}
// ==================================================================
// Helpdesk CRUD (#137, #138, #139)
// ==================================================================
public function saveCategory()
{
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
if (!$this->checkAcl('mokosuiteclient.tickets')) { $this->jsonForbidden(); }
$input = Factory::getApplication()->getInput();
$db = Factory::getDbo();
$id = $input->getInt('id', 0);
$data = (object) [
'title' => $input->getString('title', ''),
'alias' => \Joomla\CMS\Filter\OutputFilter::stringURLSafe($input->getString('title', '')),
'sla_response_minutes' => $input->getInt('sla_response_minutes', 480),
'sla_resolution_minutes' => $input->getInt('sla_resolution_minutes', 2880),
'auto_assign_user' => $input->getInt('auto_assign_user', 0) ?: null,
'published' => $input->getInt('published', 1),
];
if ($id) {
$data->id = $id;
$db->updateObject('#__mokosuiteclient_ticket_categories', $data, 'id');
} else {
$data->ordering = 0;
$db->insertObject('#__mokosuiteclient_ticket_categories', $data, 'id');
}
$this->jsonResponse(['success' => true, 'message' => 'Category saved.', 'id' => (int) $data->id]);
}
public function deleteCategory()
{
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
if (!$this->checkAcl('mokosuiteclient.tickets')) { $this->jsonForbidden(); }
$db = Factory::getDbo();
$db->setQuery($db->getQuery(true)->delete('#__mokosuiteclient_ticket_categories')->where('id = ' . Factory::getApplication()->getInput()->getInt('id', 0)))->execute();
$this->jsonResponse(['success' => true, 'message' => 'Category deleted.']);
}
public function reorderCategory()
{
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
if (!$this->checkAcl('mokosuiteclient.tickets')) { $this->jsonForbidden(); }
$order = json_decode(Factory::getApplication()->getInput()->getRaw('order', '[]'), true);
if (!is_array($order)) { $this->jsonResponse(['success' => false, 'message' => 'Invalid order']); return; }
$db = Factory::getDbo();
foreach ($order as $i => $id) {
$db->setQuery('UPDATE ' . $db->quoteName('#__mokosuiteclient_ticket_categories') . ' SET ordering = ' . (int) $i . ' WHERE id = ' . (int) $id)->execute();
}
$this->jsonResponse(['success' => true, 'message' => 'Order saved.']);
}
public function saveCanned()
{
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
if (!$this->checkAcl('mokosuiteclient.tickets')) { $this->jsonForbidden(); }
$input = Factory::getApplication()->getInput();
$db = Factory::getDbo();
$data = (object) [
'title' => $input->getString('title', ''),
'body' => $input->getRaw('body', ''),
'category_id' => $input->getInt('category_id', 0) ?: null,
'ordering' => 0,
];
$id = $input->getInt('id', 0);
if ($id) { $data->id = $id; $db->updateObject('#__mokosuiteclient_ticket_canned', $data, 'id'); }
else { $db->insertObject('#__mokosuiteclient_ticket_canned', $data, 'id'); }
$this->jsonResponse(['success' => true, 'message' => 'Canned response saved.', 'id' => (int) $data->id]);
}
public function deleteCanned()
{
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
if (!$this->checkAcl('mokosuiteclient.tickets')) { $this->jsonForbidden(); }
$db = Factory::getDbo();
$db->setQuery($db->getQuery(true)->delete('#__mokosuiteclient_ticket_canned')->where('id = ' . Factory::getApplication()->getInput()->getInt('id', 0)))->execute();
$this->jsonResponse(['success' => true, 'message' => 'Canned response deleted.']);
}
public function reorderCanned()
{
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
if (!$this->checkAcl('mokosuiteclient.tickets')) { $this->jsonForbidden(); }
$order = json_decode(Factory::getApplication()->getInput()->getRaw('order', '[]'), true);
if (!is_array($order)) { $this->jsonResponse(['success' => false, 'message' => 'Invalid order']); return; }
$db = Factory::getDbo();
foreach ($order as $i => $id) {
$db->setQuery('UPDATE ' . $db->quoteName('#__mokosuiteclient_ticket_canned') . ' SET ordering = ' . (int) $i . ' WHERE id = ' . (int) $id)->execute();
}
$this->jsonResponse(['success' => true, 'message' => 'Order saved.']);
}
public function uploadAttachment()
{
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
if (!$this->checkAcl('mokosuiteclient.tickets')) { $this->jsonForbidden(); }
$input = Factory::getApplication()->getInput();
$ticketId = $input->getInt('ticket_id', 0);
$replyId = $input->getInt('reply_id', 0) ?: null;
if (!$ticketId) { $this->jsonResponse(['success' => false, 'message' => 'Missing ticket_id']); return; }
$files = $input->files->get('attachments', [], 'raw');
if (empty($files) || empty($files['name'])) { $this->jsonResponse(['success' => false, 'message' => 'No files uploaded']); return; }
$saved = \Moko\Component\MokoSuiteClient\Administrator\Service\AttachmentService::upload($ticketId, $replyId, $files);
$this->jsonResponse(['success' => true, 'message' => count($saved) . ' file(s) uploaded', 'count' => count($saved)]);
}
public function downloadAttachment()
{
if (!$this->checkAcl('mokosuiteclient.tickets')) { $this->jsonForbidden(); }
$id = Factory::getApplication()->getInput()->getInt('id', 0);
$db = Factory::getDbo();
$db->setQuery($db->getQuery(true)->select('*')->from('#__mokosuiteclient_ticket_attachments')->where('id = ' . $id));
$att = $db->loadObject();
if (!$att) { throw new \RuntimeException('Attachment not found', 404); }
$path = \Moko\Component\MokoSuiteClient\Administrator\Service\AttachmentService::getAbsolutePath($att);
if (!file_exists($path)) { throw new \RuntimeException('File not found', 404); }
$app = Factory::getApplication();
$app->setHeader('Content-Type', $att->mimetype ?: 'application/octet-stream');
$safeName = str_replace(['"', "\r", "\n"], '', $att->filename);
$app->setHeader('Content-Disposition', 'attachment; filename="' . $safeName . '"');
$app->setHeader('Content-Length', (string) filesize($path));
$app->sendHeaders();
readfile($path);
$app->close();
}
public function deleteAttachment()
{
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
if (!$this->checkAcl('mokosuiteclient.tickets')) { $this->jsonForbidden(); }
$id = Factory::getApplication()->getInput()->getInt('id', 0);
$ok = \Moko\Component\MokoSuiteClient\Administrator\Service\AttachmentService::delete($id);
$this->jsonResponse(['success' => $ok, 'message' => $ok ? 'Attachment deleted' : 'Not found']);
}
public function rateTicket()
{
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
if (!$this->checkAcl('mokosuiteclient.tickets')) { $this->jsonForbidden(); }
$input = Factory::getApplication()->getInput();
$ticketId = $input->getInt('ticket_id', 0);
$rating = $input->getInt('rating', 0);
$feedback = $input->getString('feedback', '');
if (!$ticketId || $rating < 1 || $rating > 5) {
$this->jsonResponse(['success' => false, 'message' => 'Invalid rating (1-5)']);
return;
}
$db = Factory::getDbo();
$db->setQuery(
'UPDATE ' . $db->quoteName('#__mokosuiteclient_tickets')
. ' SET satisfaction_rating = ' . $rating
. ', satisfaction_feedback = ' . $db->quote($feedback)
. ', satisfaction_rated_at = ' . $db->quote(Factory::getDate()->toSql())
. ' WHERE id = ' . $ticketId
)->execute();
$this->jsonResponse(['success' => true, 'message' => 'Thank you for your feedback!']);
}
public function saveAutomation()
{
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
if (!$this->checkAcl('core.admin')) { $this->jsonForbidden(); }
$input = Factory::getApplication()->getInput();
$db = Factory::getDbo();
$data = (object) [
'title' => $input->getString('title', ''),
'trigger_event' => $input->getString('trigger_event', 'ticket_created'),
'conditions' => $input->getRaw('conditions', '[]'),
'actions' => $input->getRaw('actions', '[]'),
'behavior' => $input->getString('behavior', 'append'),
'enabled' => 1,
'ordering' => 0,
];
$id = $input->getInt('id', 0);
if ($id) { $data->id = $id; $db->updateObject('#__mokosuiteclient_ticket_automation', $data, 'id'); }
else { $db->insertObject('#__mokosuiteclient_ticket_automation', $data, 'id'); }
$this->jsonResponse(['success' => true, 'message' => 'Rule saved.', 'id' => (int) $data->id]);
}
public function deleteAutomation()
{
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
if (!$this->checkAcl('core.admin')) { $this->jsonForbidden(); }
$db = Factory::getDbo();
$db->setQuery($db->getQuery(true)->delete('#__mokosuiteclient_ticket_automation')->where('id = ' . Factory::getApplication()->getInput()->getInt('id', 0)))->execute();
$this->jsonResponse(['success' => true, 'message' => 'Rule deleted.']);
}
public function toggleAutomation()
{
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
if (!$this->checkAcl('core.admin')) { $this->jsonForbidden(); }
$input = Factory::getApplication()->getInput();
$db = Factory::getDbo();
$db->setQuery($db->getQuery(true)->update('#__mokosuiteclient_ticket_automation')
->set('enabled = ' . $input->getInt('enabled', 0))
->where('id = ' . $input->getInt('id', 0)))->execute();
$this->jsonResponse(['success' => true, 'message' => 'Rule updated.']);
}
public function reorderAutomation()
{
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
if (!$this->checkAcl('core.admin')) { $this->jsonForbidden(); }
$order = json_decode(Factory::getApplication()->getInput()->getRaw('order', '[]'), true);
if (!is_array($order)) { $this->jsonResponse(['success' => false, 'message' => 'Invalid order']); return; }
$db = Factory::getDbo();
foreach ($order as $i => $id) {
$db->setQuery('UPDATE ' . $db->quoteName('#__mokosuiteclient_ticket_automation') . ' SET ordering = ' . (int) $i . ' WHERE id = ' . (int) $id)->execute();
}
$this->jsonResponse(['success' => true, 'message' => 'Order saved.']);
}
// ==================================================================
// Settings Import/Export (#132)
// ==================================================================
@@ -891,7 +687,7 @@ class DisplayController extends BaseController
{
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
if (!$this->checkAcl('core.admin'))
if (!$this->checkAcl('mokosuiteclient.security.waflog'))
{
$this->jsonForbidden();
return;
@@ -907,7 +703,7 @@ class DisplayController extends BaseController
{
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
if (!$this->checkAcl('core.admin'))
if (!$this->checkAcl('mokosuiteclient.security.waflog'))
{
$this->jsonForbidden();
return;
@@ -991,19 +787,6 @@ class DisplayController extends BaseController
// Importers
// ==================================================================
public function importAts()
{
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
if (!$this->checkAcl('mokosuiteclient.tickets'))
{
$this->jsonForbidden();
return;
}
$this->jsonResponse($this->getModel('Import')->importAts());
}
public function importAdminTools()
{
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
@@ -0,0 +1,525 @@
<?php
/**
* @package MokoSuiteClient
* @subpackage com_mokosuiteclient
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
* @license GNU General Public License version 3 or later; see LICENSE
*/
namespace Moko\Component\MokoSuiteClient\Administrator\Helper;
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\Uri\Uri;
/**
* Conditions Engine — evaluates rule-based display conditions.
*
* Supports nested groups of rules with AND/OR logic and per-rule exclusion.
*
* @since 02.48.00
*/
class ConditionsHelper
{
/**
* Runtime evaluation cache keyed by condition ID.
*
* @var array<int, bool>
*/
private static array $cache = [];
/**
* Check whether a condition set passes.
*
* @param int $conditionId The condition record ID.
*
* @return bool True when the condition passes (content should display).
*/
public static function pass(int $conditionId): bool
{
if (isset(self::$cache[$conditionId])) {
return self::$cache[$conditionId];
}
$condition = self::load($conditionId);
if ($condition === null || !(int) $condition->published) {
self::$cache[$conditionId] = false;
return false;
}
$groups = $condition->groups ?? [];
if (empty($groups)) {
// No groups means no restrictions — pass.
self::$cache[$conditionId] = true;
return true;
}
$matchAll = (bool) $condition->match_all;
foreach ($groups as $group) {
$groupResult = self::passGroup($group);
if ($matchAll && !$groupResult) {
self::$cache[$conditionId] = false;
return false;
}
if (!$matchAll && $groupResult) {
self::$cache[$conditionId] = true;
return true;
}
}
// match_all: all passed; match_any: none passed.
$result = $matchAll;
self::$cache[$conditionId] = $result;
return $result;
}
/**
* Load a condition with its groups and rules from the database.
*
* @param int $conditionId The condition record ID.
*
* @return object|null The condition object with nested groups/rules, or null.
*/
public static function load(int $conditionId): ?object
{
$db = Factory::getContainer()->get('DatabaseDriver');
// Load the condition record.
$query = $db->getQuery(true)
->select('*')
->from($db->quoteName('#__mokosuiteclient_conditions'))
->where($db->quoteName('id') . ' = :id')
->bind(':id', $conditionId, \Joomla\Database\ParameterType::INTEGER);
$condition = $db->setQuery($query)->loadObject();
if ($condition === null) {
return null;
}
// Load groups.
$query = $db->getQuery(true)
->select('*')
->from($db->quoteName('#__mokosuiteclient_conditions_groups'))
->where($db->quoteName('condition_id') . ' = :cid')
->bind(':cid', $conditionId, \Joomla\Database\ParameterType::INTEGER)
->order($db->quoteName('ordering') . ' ASC');
$groups = $db->setQuery($query)->loadObjectList();
// Load rules for each group.
foreach ($groups as $group) {
$groupId = (int) $group->id;
$query = $db->getQuery(true)
->select('*')
->from($db->quoteName('#__mokosuiteclient_conditions_rules'))
->where($db->quoteName('group_id') . ' = :gid')
->bind(':gid', $groupId, \Joomla\Database\ParameterType::INTEGER)
->order($db->quoteName('ordering') . ' ASC');
$group->rules = $db->setQuery($query)->loadObjectList();
// Decode params JSON on each rule.
foreach ($group->rules as $rule) {
$rule->params = json_decode($rule->params ?: '{}');
}
}
$condition->groups = $groups;
return $condition;
}
/**
* Evaluate a single group (AND/OR its rules).
*
* @param object $group The group object with a rules array.
*
* @return bool
*/
private static function passGroup(object $group): bool
{
$rules = $group->rules ?? [];
if (empty($rules)) {
return true;
}
$matchAll = (bool) $group->match_all;
foreach ($rules as $rule) {
$ruleResult = self::passRule($rule);
// If the rule is an exclusion, invert the result.
if ((int) $rule->exclude) {
$ruleResult = !$ruleResult;
}
if ($matchAll && !$ruleResult) {
return false;
}
if (!$matchAll && $ruleResult) {
return true;
}
}
return $matchAll;
}
/**
* Evaluate a single rule by dispatching to the right type handler.
*
* @param object $rule The rule object (type, params decoded).
*
* @return bool
*/
private static function passRule(object $rule): bool
{
$params = $rule->params ?? new \stdClass();
return match ($rule->type) {
'menu__menu_item' => self::evalMenuMenuItem($params),
'menu__home_page' => self::evalMenuHomePage($params),
'visitor__user_group' => self::evalVisitorUserGroup($params),
'visitor__access_level' => self::evalVisitorAccessLevel($params),
'date__date' => self::evalDateDate($params),
'date__day' => self::evalDateDay($params),
'other__url' => self::evalOtherUrl($params),
default => false,
};
}
// ------------------------------------------------------------------
// Rule type evaluators
// ------------------------------------------------------------------
/**
* menu__menu_item — check if current menu item ID is in selection.
*/
private static function evalMenuMenuItem(object $params): bool
{
$selection = self::toIntArray($params->selection ?? []);
if (empty($selection)) {
return true;
}
$app = Factory::getApplication();
$itemId = (int) $app->getInput()->getInt('Itemid', 0);
return \in_array($itemId, $selection, true);
}
/**
* menu__home_page — check if current page is the site home page.
*/
private static function evalMenuHomePage(object $params): bool
{
$app = Factory::getApplication();
$menu = $app->getMenu();
if ($menu === null) {
return false;
}
$active = $menu->getActive();
$default = $menu->getDefault($app->getLanguage()->getTag());
$isHome = ($active !== null && $default !== null && $active->id === $default->id);
// params->selection can be [1] for "is home" or [0] for "is not home".
$want = (bool) ($params->selection[0] ?? true);
return $isHome === $want;
}
/**
* visitor__user_group — check if current user belongs to specified groups.
*/
private static function evalVisitorUserGroup(object $params): bool
{
$selection = self::toIntArray($params->selection ?? []);
if (empty($selection)) {
return true;
}
$user = Factory::getApplication()->getIdentity();
$userGroups = $user ? $user->getAuthorisedGroups() : [];
$comparison = $params->comparison ?? 'any';
if ($comparison === 'all') {
return empty(array_diff($selection, $userGroups));
}
// Default: any
return !empty(array_intersect($selection, $userGroups));
}
/**
* visitor__access_level — check if current user has specified access levels.
*/
private static function evalVisitorAccessLevel(object $params): bool
{
$selection = self::toIntArray($params->selection ?? []);
if (empty($selection)) {
return true;
}
$user = Factory::getApplication()->getIdentity();
$accessLevels = $user ? $user->getAuthorisedViewLevels() : [];
$comparison = $params->comparison ?? 'any';
if ($comparison === 'all') {
return empty(array_diff($selection, $accessLevels));
}
return !empty(array_intersect($selection, $accessLevels));
}
/**
* date__date — check if current date is before/after/between specified dates.
*
* params->comparison: 'before', 'after', 'between'
* params->selection: [start_date] or [start_date, end_date]
*/
private static function evalDateDate(object $params): bool
{
$comparison = $params->comparison ?? 'after';
$selection = (array) ($params->selection ?? []);
if (empty($selection)) {
return true;
}
$now = Factory::getDate()->toUnix();
return match ($comparison) {
'before' => $now < strtotime($selection[0]),
'after' => $now > strtotime($selection[0]),
'between' => isset($selection[1])
&& $now >= strtotime($selection[0])
&& $now <= strtotime($selection[1]),
default => false,
};
}
/**
* date__day — check if current day of week matches selection.
*
* params->selection: array of day numbers (1=Monday .. 7=Sunday, ISO-8601).
*/
private static function evalDateDay(object $params): bool
{
$selection = self::toIntArray($params->selection ?? []);
if (empty($selection)) {
return true;
}
$today = (int) Factory::getDate()->format('N'); // 1=Mon, 7=Sun
return \in_array($today, $selection, true);
}
/**
* other__url — check if current URL matches a regex pattern.
*
* params->selection: array of regex patterns (without delimiters).
*/
private static function evalOtherUrl(object $params): bool
{
$patterns = (array) ($params->selection ?? []);
if (empty($patterns)) {
return true;
}
$url = Uri::getInstance()->toString();
foreach ($patterns as $pattern) {
$pattern = trim($pattern);
if ($pattern === '') {
continue;
}
// Wrap in delimiters, escape internal delimiter.
$safePattern = str_replace('#', '\\#', $pattern);
if (@preg_match('#' . $safePattern . '#i', $url)) {
return true;
}
}
return false;
}
// ------------------------------------------------------------------
// Mapping helpers
// ------------------------------------------------------------------
/**
* Get all condition IDs mapped to a specific extension/item pair.
*
* @param string $extension The extension identifier (e.g. 'mod_custom').
* @param int $itemId The item ID within that extension.
*
* @return int[] Array of condition IDs.
*/
public static function getConditionsForItem(string $extension, int $itemId): array
{
$db = Factory::getContainer()->get('DatabaseDriver');
$query = $db->getQuery(true)
->select($db->quoteName('condition_id'))
->from($db->quoteName('#__mokosuiteclient_conditions_map'))
->where($db->quoteName('extension') . ' = :ext')
->where($db->quoteName('item_id') . ' = :iid')
->bind(':ext', $extension)
->bind(':iid', $itemId, \Joomla\Database\ParameterType::INTEGER);
return $db->setQuery($query)->loadColumn();
}
/**
* Check if an item should display based on its mapped conditions.
*
* If no conditions are mapped, the item displays (returns true).
* If conditions are mapped, ALL must pass for the item to display.
*
* @param string $extension The extension identifier.
* @param int $itemId The item ID.
*
* @return bool
*/
public static function shouldDisplay(string $extension, int $itemId): bool
{
$conditionIds = self::getConditionsForItem($extension, $itemId);
if (empty($conditionIds)) {
return true;
}
foreach ($conditionIds as $conditionId) {
if (!self::pass((int) $conditionId)) {
return false;
}
}
return true;
}
/**
* Evaluate a condition by its alias string.
*
* @param string $alias The condition alias.
*
* @return bool True when the condition passes.
*
* @since 02.48.00
*/
public static function passByAlias(string $alias): bool
{
$id = self::resolveAlias($alias);
if ($id === null) {
return false;
}
return self::pass($id);
}
/**
* Resolve a condition reference that may be an integer ID or an alias string.
*
* @param string $ref The reference (numeric ID or alias).
*
* @return int|null The condition ID, or null if not found.
*
* @since 02.48.00
*/
public static function resolveAlias(string $ref): ?int
{
if (is_numeric($ref)) {
return (int) $ref;
}
$db = Factory::getContainer()->get('DatabaseDriver');
$query = $db->getQuery(true)
->select($db->quoteName('id'))
->from($db->quoteName('#__mokosuiteclient_conditions'))
->where($db->quoteName('alias') . ' = :alias')
->bind(':alias', $ref);
$id = $db->setQuery($query)->loadResult();
return $id !== null ? (int) $id : null;
}
/**
* Evaluate a single inline rule (public wrapper around passRule).
*
* @param string $type The rule type (e.g. 'visitor__access_level').
* @param object $params The rule params object.
*
* @return bool
*
* @since 02.48.00
*/
public static function evaluateInlineRule(string $type, object $params): bool
{
$rule = (object) [
'type' => $type,
'params' => $params,
];
return self::passRule($rule);
}
/**
* Clear the evaluation cache (useful between requests in testing).
*
* @return void
*/
public static function clearCache(): void
{
self::$cache = [];
}
// ------------------------------------------------------------------
// Internal utilities
// ------------------------------------------------------------------
/**
* Normalize a mixed selection value into an array of integers.
*
* @param mixed $value Scalar, array, or object.
*
* @return int[]
*/
private static function toIntArray(mixed $value): array
{
if (\is_object($value)) {
$value = (array) $value;
}
if (!\is_array($value)) {
$value = [$value];
}
return array_map('intval', array_values($value));
}
}
@@ -0,0 +1,286 @@
<?php
/**
* @package MokoSuiteClient
* @subpackage com_mokosuiteclient
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
* @license GNU General Public License version 3 or later; see LICENSE
*/
namespace Moko\Component\MokoSuiteClient\Administrator\Helper;
defined('_JEXEC') or die;
use Joomla\Database\DatabaseInterface;
/**
* Shared Support PIN helper.
*
* Generates HMAC-based support PINs from the core plugin's health token.
* Used by the component dashboard, cpanel module, cache module, and
* the requestPin AJAX controller.
*
* @since 02.48.00
*/
class SupportPinHelper
{
/** @var int Default PIN validity window in seconds (72 hours) */
public const PIN_TTL_DEFAULT = 72 * 3600;
/**
* Load core plugin params and return PIN state.
*
* @param DatabaseInterface $db Database driver.
*
* @return array{available: bool, pin: string, token: string, params: array}
*/
public static function getState(DatabaseInterface $db): array
{
$result = [
'available' => false,
'pin' => '',
'token' => '',
'params' => [],
'ext_id' => 0,
];
try
{
$query = $db->getQuery(true)
->select([$db->quoteName('extension_id'), $db->quoteName('params')])
->from($db->quoteName('#__extensions'))
->where($db->quoteName('element') . ' = ' . $db->quote('mokosuiteclient'))
->where($db->quoteName('type') . ' = ' . $db->quote('plugin'))
->where($db->quoteName('folder') . ' = ' . $db->quote('system'));
$db->setQuery($query);
$ext = $db->loadObject();
if (!$ext)
{
return $result;
}
$params = json_decode($ext->params, true) ?: [];
$token = $params['health_api_token'] ?? '';
$result['params'] = $params;
$result['ext_id'] = (int) $ext->extension_id;
$result['token'] = $token;
if (empty($token))
{
return $result;
}
$result['available'] = true;
$pinTtl = (int) ($params['support_pin_hours'] ?? 0) * 3600 ?: self::PIN_TTL_DEFAULT;
$requestedAt = (int) ($params['support_pin_requested_at'] ?? 0);
if ($requestedAt && (time() - $requestedAt) < $pinTtl)
{
$result['pin'] = self::generate($token, $requestedAt, $pinTtl);
}
}
catch (\Throwable $e)
{
// Silently degrade — PIN is non-critical UI sugar
}
return $result;
}
/**
* Generate a PIN string from a token and timestamp.
*
* @param string $token Health API token (HMAC key).
* @param int $timestamp The request timestamp.
* @param int $ttl PIN validity window in seconds.
*
* @return string e.g. "MOKO-A1B2-C3D4"
*/
public static function generate(string $token, int $timestamp, int $ttl = 0): string
{
$ttl = $ttl ?: self::PIN_TTL_DEFAULT;
$window = floor($timestamp / $ttl);
$hash = hash_hmac('sha256', (string) $window, $token);
return 'MOKO-' . strtoupper(substr($hash, 0, 4)) . '-' . strtoupper(substr($hash, 4, 4));
}
/**
* Request a new PIN: stamps the current time into plugin params and returns the PIN.
*
* @param DatabaseInterface $db Database driver.
*
* @return array{success: bool, pin?: string, message: string}
*/
/**
* Render PIN badge HTML (active PIN with copy, or request button).
*
* @param array $state Result from getState().
* @param string $token CSRF form token name.
* @param string $context 'dashboard'|'cpanel'|'cache' — controls layout variant.
*
* @return string HTML fragment (no wrapping div).
*/
public static function renderBadge(array $state, string $token, string $context = 'dashboard'): string
{
if (!$state['available'])
{
return '';
}
$requestUrl = \Joomla\CMS\Router\Route::_('index.php?option=com_mokosuiteclient&task=display.requestPin&format=json');
$pin = $state['pin'];
$html = '';
if (!empty($pin))
{
$escaped = htmlspecialchars($pin, ENT_QUOTES, 'UTF-8');
if ($context === 'cache')
{
$html .= '<a href="#" class="btn btn-sm btn-outline-secondary rounded-0 border-end-0 d-flex align-items-center gap-1 px-3 py-2 mokosuiteclient-pin-copy" data-pin="' . $escaped . '" title="Support PIN — click to copy" style="font-size:0.8rem;">';
$html .= '<span class="icon-key" aria-hidden="true"></span>';
$html .= '<span class="mokosuiteclient-pin-text">' . $escaped . '</span>';
$html .= '</a>';
}
else
{
$html .= '<span class="badge bg-dark mokosuiteclient-pin-copy" style="font-family:monospace;letter-spacing:0.08em;cursor:pointer;" title="Click to copy" data-pin="' . $escaped . '">';
$html .= '<span class="icon-key small me-1" aria-hidden="true"></span><span class="mokosuiteclient-pin-text">' . $escaped . '</span></span>';
}
}
else
{
if ($context === 'cache')
{
$html .= '<a href="#" class="btn btn-sm btn-outline-secondary rounded-0 border-end-0 d-flex align-items-center gap-1 px-3 py-2 mokosuiteclient-pin-request" data-url="' . $requestUrl . '" data-token="' . $token . '" title="Request support PIN" style="font-size:0.8rem;">';
$html .= '<span class="icon-key" aria-hidden="true"></span>';
$html .= '<span class="mokosuiteclient-pin-text">PIN</span>';
$html .= '</a>';
}
else
{
$html .= '<button type="button" class="btn btn-sm btn-outline-dark py-0 px-2 mokosuiteclient-pin-request" data-url="' . $requestUrl . '" data-token="' . $token . '" style="font-size:0.75rem;" title="Request a support PIN">';
$html .= '<span class="icon-key" aria-hidden="true"></span> Request PIN</button>';
}
}
return $html;
}
/**
* Render shared JS for PIN copy and request functionality.
*
* @return string <script> block.
*/
public static function renderScript(): string
{
return <<<'JS'
<script>
(function() {
if (window._mokoPinBound) return;
window._mokoPinBound = true;
function bindCopy(el) {
if (el.dataset.bound) return;
el.dataset.bound = '1';
if (!el.title) el.title = 'Click to copy';
el.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
var pin = this.dataset.pin;
if (pin && navigator.clipboard) {
var textEl = this.querySelector('.mokosuiteclient-pin-text');
navigator.clipboard.writeText(pin).then(function() {
if (textEl) {
textEl.textContent = 'Copied!';
setTimeout(function() { textEl.textContent = pin; }, 5000);
}
});
}
});
}
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('.mokosuiteclient-pin-copy').forEach(bindCopy);
document.querySelectorAll('.mokosuiteclient-pin-request').forEach(function(el) {
if (el.dataset.bound) return;
el.dataset.bound = '1';
if (!el.title) el.title = 'Request a support PIN';
el.addEventListener('click', function(e) {
e.preventDefault();
if (this.dataset.busy) return;
this.dataset.busy = '1';
var btn = this;
var textEl = btn.querySelector('.mokosuiteclient-pin-text');
var origHtml = btn.innerHTML;
if (textEl) { textEl.textContent = '...'; } else { btn.textContent = '...'; }
var fd = new FormData();
fd.append(btn.dataset.token, '1');
fetch(btn.dataset.url, {method:'POST', body:fd, headers:{'X-Requested-With':'XMLHttpRequest'}})
.then(function(r) { return r.json(); })
.then(function(data) {
if (data.success && data.pin) {
btn.classList.remove('mokosuiteclient-pin-request');
btn.classList.add('mokosuiteclient-pin-copy');
btn.dataset.pin = data.pin;
btn.title = 'Click to copy';
if (textEl) {
textEl.textContent = data.pin;
} else {
btn.className = 'badge bg-dark mokosuiteclient-pin-copy';
btn.style = 'font-family:monospace;letter-spacing:0.08em;cursor:pointer;';
btn.innerHTML = '<span class="icon-key small me-1" aria-hidden="true"></span><span class="mokosuiteclient-pin-text">' + data.pin + '</span>';
}
btn.dataset.bound = '';
bindCopy(btn);
} else {
Joomla.renderMessages({error: [data.message || 'Failed to generate PIN']});
btn.innerHTML = origHtml;
}
delete btn.dataset.busy;
})
.catch(function() {
Joomla.renderMessages({error: ['Network error']});
btn.innerHTML = origHtml;
delete btn.dataset.busy;
});
});
});
});
})();
</script>
JS;
}
public static function requestNew(DatabaseInterface $db): array
{
$state = self::getState($db);
if (!$state['available'])
{
return ['success' => false, 'message' => 'Health token not configured.'];
}
$now = time();
$params = $state['params'];
$params['support_pin_requested_at'] = $now;
$query = $db->getQuery(true)
->update($db->quoteName('#__extensions'))
->set($db->quoteName('params') . ' = ' . $db->quote(json_encode($params)))
->where($db->quoteName('extension_id') . ' = ' . $state['ext_id']);
$db->setQuery($query)->execute();
$pinHours = (int) ($params['support_pin_hours'] ?? 0) ?: (int) (self::PIN_TTL_DEFAULT / 3600);
$pinTtl = $pinHours * 3600;
$pin = self::generate($state['token'], $now, $pinTtl);
return ['success' => true, 'pin' => $pin, 'message' => 'PIN generated — valid for ' . $pinHours . ' hours.'];
}
}
@@ -77,6 +77,30 @@ class DashboardModel extends BaseDatabaseModel
'protected' => false,
'configure_only' => true,
],
'mokosuiteclient_backup' => [
'icon' => 'icon-archive',
'category' => 'monitoring',
'label' => 'Backup Bridge',
'description' => 'Detects MokoSuiteBackup and sends backup status in heartbeat payloads to HQ.',
'protected' => false,
'configure_only' => true,
],
'mokosuiteclient_dbip' => [
'icon' => 'icon-globe',
'category' => 'security',
'label' => 'GeoIP Lookup',
'description' => 'Country-level IP geolocation using DB-IP lite database for WAF and analytics.',
'protected' => false,
'configure_only' => true,
],
'mokosuiteclient_license' => [
'icon' => 'icon-key',
'category' => 'tools',
'label' => 'License Manager',
'description' => 'Download key management and license validation for MokoSuite packages.',
'protected' => false,
'configure_only' => true,
],
];
/**
@@ -213,30 +237,46 @@ class DashboardModel extends BaseDatabaseModel
}
/**
* Get installed MokoSuiteClient component and modules with versions.
* Discover all installed MokoSuite ecosystem extensions.
*
* @return array Array of extension objects with name, element, type, version.
* Fuzzy-matches packages, components, modules, plugins, and libraries
* by element name containing "mokosuite", "mokosuiteclient", "mokojoom",
* or "moko" prefix patterns.
*
* @return array Extension objects with name, element, type, version, enabled, family.
*/
public function getMokoExtensions(): array
{
$db = $this->getDatabase();
$el = $db->quoteName('element');
// Fuzzy match: any extension whose element contains moko patterns
$patterns = [
$el . ' LIKE ' . $db->quote('pkg_mokosuite%'),
$el . ' LIKE ' . $db->quote('com_mokosuite%'),
$el . ' LIKE ' . $db->quote('mod_mokosuite%'),
$el . ' LIKE ' . $db->quote('mokosuite%'),
$el . ' LIKE ' . $db->quote('mokosuiteclient%'),
$el . ' LIKE ' . $db->quote('pkg_mokojoom%'),
$el . ' LIKE ' . $db->quote('com_mokojoom%'),
$el . ' LIKE ' . $db->quote('mod_mokojoom%'),
$el . ' LIKE ' . $db->quote('mokojoom%'),
$el . ' LIKE ' . $db->quote('plg_%_mokosuite%'),
$el . ' LIKE ' . $db->quote('plg_%_mokojoom%'),
];
$query = $db->getQuery(true)
->select([
$db->quoteName('extension_id'),
$db->quoteName('element'),
$db->quoteName('name'),
$db->quoteName('type'),
$db->quoteName('folder'),
$db->quoteName('enabled'),
$db->quoteName('manifest_cache'),
])
->from($db->quoteName('#__extensions'))
->where('('
// The component
. '(' . $db->quoteName('type') . ' = ' . $db->quote('component')
. ' AND ' . $db->quoteName('element') . ' = ' . $db->quote('com_mokosuiteclient') . ')'
// Admin modules
. ' OR (' . $db->quoteName('type') . ' = ' . $db->quote('module')
. ' AND ' . $db->quoteName('element') . ' LIKE ' . $db->quote('mod_mokosuiteclient%') . ')'
. ')')
->where('(' . implode(' OR ', $patterns) . ')')
->order($db->quoteName('type') . ' ASC, ' . $db->quoteName('element') . ' ASC');
$db->setQuery($query);
@@ -248,12 +288,27 @@ class DashboardModel extends BaseDatabaseModel
{
$manifest = json_decode($row->manifest_cache ?? '{}');
// Determine product family from element name
$family = 'mokosuite';
if (stripos($row->element, 'mokosuiteclient') !== false) {
$family = 'mokosuiteclient';
} elseif (stripos($row->element, 'mokosuitehq') !== false) {
$family = 'mokosuitehq';
} elseif (stripos($row->element, 'mokosuitecrm') !== false) {
$family = 'mokosuitecrm';
} elseif (stripos($row->element, 'mokojoom') !== false) {
$family = 'mokojoom';
}
$extensions[] = (object) [
'element' => $row->element,
'name' => $manifest->name ?? $row->name,
'type' => $row->type,
'version' => $manifest->version ?? '',
'enabled' => (int) $row->enabled,
'extension_id' => (int) $row->extension_id,
'element' => $row->element,
'name' => $manifest->name ?? $row->name,
'type' => $row->type,
'folder' => $row->folder ?? '',
'version' => $manifest->version ?? '',
'enabled' => (int) $row->enabled,
'family' => $family,
];
}
@@ -277,7 +332,9 @@ class DashboardModel extends BaseDatabaseModel
->select([$db->quoteName('element'), $db->quoteName('protected')])
->from($db->quoteName('#__extensions'))
->where($db->quoteName('extension_id') . ' = ' . $extensionId)
->where($db->quoteName('type') . ' = ' . $db->quote('plugin'));
->where($db->quoteName('type') . ' = ' . $db->quote('plugin'))
->where('(' . $db->quoteName('element') . ' = ' . $db->quote('mokosuiteclient')
. ' OR ' . $db->quoteName('element') . ' LIKE ' . $db->quote('mokosuiteclient\\_%') . ')');
$db->setQuery($query);
$ext = $db->loadObject();
@@ -454,7 +511,7 @@ class DashboardModel extends BaseDatabaseModel
])
->from($db->quoteName('#__action_logs', 'a'))
->leftJoin($db->quoteName('#__users', 'u') . ' ON ' . $db->quoteName('u.id') . ' = ' . $db->quoteName('a.user_id'))
->where($db->quoteName('a.message_language_key') . ' LIKE ' . $db->quote('%LOGIN%'))
->where($db->quoteName('a.message_language_key') . ' = ' . $db->quote('PLG_ACTIONLOG_JOOMLA_USER_LOGGED_IN'))
->order($db->quoteName('a.log_date') . ' DESC')
->setLimit($limit);
$db->setQuery($query);
@@ -568,7 +625,7 @@ class DashboardModel extends BaseDatabaseModel
$db->setQuery(
"SELECT DATE(" . $db->quoteName('created') . ") AS day, COUNT(*) AS total"
. " FROM " . $db->quoteName('#__mokosuiteclient_waf_log')
. " WHERE " . $db->quoteName('created') . " >= DATE_SUB(NOW(), INTERVAL $days DAY)"
. " WHERE " . $db->quoteName('created') . " >= DATE_SUB(NOW(), INTERVAL " . (int) $days . " DAY)"
. " GROUP BY day ORDER BY day"
);
$rows = $db->loadObjectList() ?: [];
@@ -609,7 +666,7 @@ class DashboardModel extends BaseDatabaseModel
"SELECT DATE(" . $db->quoteName('log_date') . ") AS day, COUNT(*) AS total"
. " FROM " . $db->quoteName('#__action_logs')
. " WHERE " . $db->quoteName('message_language_key') . " = 'PLG_ACTIONLOG_JOOMLA_USER_LOGGED_IN'"
. " AND " . $db->quoteName('log_date') . " >= DATE_SUB(NOW(), INTERVAL $days DAY)"
. " AND " . $db->quoteName('log_date') . " >= DATE_SUB(NOW(), INTERVAL " . (int) $days . " DAY)"
. " GROUP BY day ORDER BY day"
);
$rows = $db->loadObjectList() ?: [];
@@ -112,7 +112,7 @@ class ExtensionsModel extends BaseDatabaseModel
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 120);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
$data = curl_exec($ch);
$code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
@@ -221,7 +221,7 @@ class ExtensionsModel extends BaseDatabaseModel
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
$response = curl_exec($ch);
$code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
@@ -238,8 +238,15 @@ class ExtensionsModel extends BaseDatabaseModel
return [];
}
// Determine site's update channel preference
$channel = 'dev'; // default to dev — show everything
// Dev channel only available on Moko domains; all others forced to stable
$isMokoDomain = (bool) preg_match('/\.mokoconsulting\.tech$/i', $_SERVER['HTTP_HOST'] ?? '');
$channel = 'stable';
if ($isMokoDomain) {
try {
$channel = \Joomla\CMS\Component\ComponentHelper::getParams('com_installer')
->get('update_channel', 'stable') ?: 'stable';
} catch (\Throwable $e) {}
}
$hasStable = false;
$hasDev = false;
@@ -269,7 +276,18 @@ class ExtensionsModel extends BaseDatabaseModel
$hasDev = true;
}
if ($ver === '' || version_compare($ver, $bestVersion, '<='))
if ($ver === '')
{
continue;
}
// Respect update channel: stable channel skips dev-tagged versions
if ($channel === 'stable' && $tag === 'dev')
{
continue;
}
if (version_compare($ver, $bestVersion, '<='))
{
continue;
}
File diff suppressed because it is too large Load Diff
@@ -1,177 +0,0 @@
<?php
/**
* @package MokoSuiteClient
* @subpackage com_mokosuiteclient
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
* @license GNU General Public License version 3 or later; see LICENSE
*/
namespace Moko\Component\MokoSuiteClient\Administrator\Service;
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\Filesystem\File;
use Joomla\CMS\Filesystem\Folder;
use Joomla\CMS\Log\Log;
class AttachmentService
{
private const STORAGE_DIR = JPATH_ROOT . '/media/com_mokosuiteclient/attachments';
private const ALLOWED_EXTENSIONS = [
'jpg', 'jpeg', 'png', 'gif', 'webp',
'pdf', 'doc', 'docx', 'xls', 'xlsx', 'csv', 'txt', 'rtf',
'zip', 'gz', 'tar',
];
private const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10 MB
/**
* Upload file(s) for a ticket or reply.
*
* @param int $ticketId Ticket ID
* @param int|null $replyId Reply ID (null for ticket-level attachments)
* @param array $files $_FILES array entry (single or multi)
* @return array Saved attachment records
*/
public static function upload(int $ticketId, ?int $replyId, array $files): array
{
$saved = [];
// Normalize single file to array format
if (!is_array($files['name'])) {
$files = [
'name' => [$files['name']],
'type' => [$files['type']],
'tmp_name' => [$files['tmp_name']],
'error' => [$files['error']],
'size' => [$files['size']],
];
}
$ticketDir = self::STORAGE_DIR . '/' . $ticketId;
if (!is_dir($ticketDir)) {
Folder::create($ticketDir);
}
$userId = (int) Factory::getUser()->id;
$db = Factory::getDbo();
for ($i = 0, $count = count($files['name']); $i < $count; $i++)
{
if ($files['error'][$i] !== UPLOAD_ERR_OK) {
continue;
}
$originalName = File::makeSafe($files['name'][$i]);
$ext = strtolower(pathinfo($originalName, PATHINFO_EXTENSION));
// Validate extension
if (!in_array($ext, self::ALLOWED_EXTENSIONS, true)) {
Log::add("Attachment rejected: disallowed extension .{$ext}", Log::WARNING, 'mokosuiteclient');
continue;
}
// Validate size
if ($files['size'][$i] > self::MAX_FILE_SIZE) {
Log::add("Attachment rejected: file too large ({$files['size'][$i]} bytes)", Log::WARNING, 'mokosuiteclient');
continue;
}
// Generate unique filename to prevent overwrites
$storedName = uniqid('att_', true) . '.' . $ext;
$destPath = $ticketDir . '/' . $storedName;
if (!File::upload($files['tmp_name'][$i], $destPath)) {
Log::add("Attachment upload failed: {$originalName}", Log::ERROR, 'mokosuiteclient');
continue;
}
$record = (object) [
'ticket_id' => $ticketId,
'reply_id' => $replyId,
'filename' => $originalName,
'filepath' => $ticketId . '/' . $storedName,
'filesize' => $files['size'][$i],
'mimetype' => mime_content_type($destPath) ?: 'application/octet-stream',
'uploaded_by' => $userId,
'created' => Factory::getDate()->toSql(),
];
$db->insertObject('#__mokosuiteclient_ticket_attachments', $record, 'id');
$saved[] = $record;
}
return $saved;
}
/**
* Get attachments for a ticket.
*/
public static function getForTicket(int $ticketId): array
{
$db = Factory::getDbo();
$db->setQuery(
$db->getQuery(true)
->select('a.*, u.name AS uploader_name')
->from($db->quoteName('#__mokosuiteclient_ticket_attachments', 'a'))
->leftJoin($db->quoteName('#__users', 'u') . ' ON u.id = a.uploaded_by')
->where($db->quoteName('a.ticket_id') . ' = ' . $ticketId)
->order('a.created ASC')
);
return $db->loadObjectList() ?: [];
}
/**
* Get the absolute filesystem path for an attachment.
*/
public static function getAbsolutePath(object $attachment): string
{
return self::STORAGE_DIR . '/' . $attachment->filepath;
}
/**
* Delete an attachment (file + DB record).
*/
public static function delete(int $attachmentId): bool
{
$db = Factory::getDbo();
$db->setQuery(
$db->getQuery(true)
->select('*')
->from('#__mokosuiteclient_ticket_attachments')
->where('id = ' . $attachmentId)
);
$att = $db->loadObject();
if (!$att) {
return false;
}
$path = self::STORAGE_DIR . '/' . $att->filepath;
if (file_exists($path)) {
File::delete($path);
}
$db->setQuery(
$db->getQuery(true)
->delete('#__mokosuiteclient_ticket_attachments')
->where('id = ' . $attachmentId)
)->execute();
return true;
}
/**
* Format file size for display.
*/
public static function formatSize(int $bytes): string
{
if ($bytes < 1024) return $bytes . ' B';
if ($bytes < 1048576) return round($bytes / 1024, 1) . ' KB';
return round($bytes / 1048576, 1) . ' MB';
}
}
@@ -1,279 +0,0 @@
<?php
/**
* @package MokoSuiteClient
* @subpackage com_mokosuiteclient
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
* @license GNU General Public License version 3 or later; see LICENSE
*/
namespace Moko\Component\MokoSuiteClient\Administrator\Service;
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\Log\Log;
/**
* Automation rule engine — evaluates trigger/condition/action rules.
*
* Called from event hooks (system plugin, task plugin) whenever
* a triggering event occurs. Loads matching rules, checks conditions,
* and executes actions.
*
* @since 02.35.00
*/
class AutomationEngine
{
/**
* Fire all matching rules for a given trigger event.
*
* @param string $triggerEvent Event name (ticket_created, user_login, etc.)
* @param array $context Context data (ticket object, user data, etc.)
*/
public static function fire(string $triggerEvent, array $context = []): void
{
try
{
$rules = self::getActiveRules($triggerEvent);
foreach ($rules as $rule)
{
$conditions = json_decode($rule->conditions, true) ?: [];
$actions = json_decode($rule->actions, true) ?: [];
if (self::evaluateConditions($conditions, $context))
{
self::executeActions($actions, $rule, $context);
}
}
}
catch (\Throwable $e)
{
Log::add('Automation engine error: ' . $e->getMessage(), Log::ERROR, 'mokosuiteclient');
}
}
/**
* Get active automation rules for a trigger event.
*/
private static function getActiveRules(string $event): array
{
$db = Factory::getDbo();
$db->setQuery(
$db->getQuery(true)
->select('*')
->from('#__mokosuiteclient_ticket_automation')
->where($db->quoteName('trigger_event') . ' = ' . $db->quote($event))
->where($db->quoteName('enabled') . ' = 1')
->order('ordering ASC')
);
return $db->loadObjectList() ?: [];
}
/**
* Evaluate all conditions (AND logic).
*/
private static function evaluateConditions(array $conditions, array $context): bool
{
foreach ($conditions as $c)
{
$field = $c['field'] ?? '';
$op = $c['op'] ?? 'eq';
$expected = $c['value'] ?? '';
$actual = $context[$field] ?? '';
switch ($op)
{
case 'eq': if ((string) $actual !== (string) $expected) return false; break;
case 'neq': if ((string) $actual === (string) $expected) return false; break;
case 'gt': if ((float) $actual <= (float) $expected) return false; break;
case 'lt': if ((float) $actual >= (float) $expected) return false; break;
case 'in':
$values = array_map('trim', explode(',', $expected));
if (!in_array((string) $actual, $values, true)) return false;
break;
case 'not_in':
$values = array_map('trim', explode(',', $expected));
if (in_array((string) $actual, $values, true)) return false;
break;
}
}
return true;
}
/**
* Execute actions for a matched rule.
*/
private static function executeActions(array $actions, object $rule, array $context): void
{
$db = Factory::getDbo();
$ticketId = (int) ($context['ticket_id'] ?? $context['id'] ?? 0);
foreach ($actions as $action)
{
$type = $action['type'] ?? '';
$value = $action['value'] ?? '';
try
{
switch ($type)
{
case 'set_status':
if ($ticketId) {
$statusId = self::resolveStatusId($db, $value);
$sets = "status = {$db->quote($value)}, modified = {$db->quote(Factory::getDate()->toSql())}";
if ($statusId) { $sets .= ", status_id = {$statusId}"; }
$db->setQuery("UPDATE {$db->quoteName('#__mokosuiteclient_tickets')} SET {$sets} WHERE id = {$ticketId}")->execute();
}
break;
case 'set_priority':
if ($ticketId) {
$priorityId = self::resolvePriorityId($db, $value);
$sets = "priority = {$db->quote($value)}, modified = {$db->quote(Factory::getDate()->toSql())}";
if ($priorityId) { $sets .= ", priority_id = {$priorityId}"; }
$db->setQuery("UPDATE {$db->quoteName('#__mokosuiteclient_tickets')} SET {$sets} WHERE id = {$ticketId}")->execute();
}
break;
case 'assign':
if ($ticketId) {
$db->setQuery("UPDATE {$db->quoteName('#__mokosuiteclient_tickets')} SET assigned_to = {$db->quote($value)}, modified = {$db->quote(Factory::getDate()->toSql())} WHERE id = {$ticketId}")->execute();
}
break;
case 'add_note':
if ($ticketId) {
$note = (object) [
'ticket_id' => $ticketId,
'user_id' => 0,
'body' => $value ?: '[Automation: ' . ($rule->title ?? '') . ']',
'is_internal' => 1,
'created' => Factory::getDate()->toSql(),
];
$db->insertObject('#__mokosuiteclient_ticket_replies', $note);
}
break;
case 'send_email':
NotificationService::securityAlert(
'automation',
'Automation: ' . ($rule->title ?? ''),
$value ?: 'Rule triggered for ticket #' . $ticketId
);
break;
case 'send_ntfy':
NotificationService::pushNtfySecurity(
'automation',
'Automation: ' . ($rule->title ?? ''),
$value ?: 'Rule triggered for ticket #' . $ticketId
);
break;
case 'close':
if ($ticketId) {
$closedId = self::resolveClosedStatusId($db);
$sets = "status = 'closed', closed = {$db->quote(Factory::getDate()->toSql())}, modified = {$db->quote(Factory::getDate()->toSql())}";
if ($closedId) { $sets .= ", status_id = {$closedId}"; }
$db->setQuery("UPDATE {$db->quoteName('#__mokosuiteclient_tickets')} SET {$sets} WHERE id = {$ticketId}")->execute();
}
break;
case 'create_ticket':
self::createTicketFromAutomation($rule, $context, $value);
break;
}
}
catch (\Throwable $e)
{
Log::add("Automation action {$type} failed: " . $e->getMessage(), Log::WARNING, 'mokosuiteclient');
}
}
}
/**
* Create a ticket from automation (with behavior: append/always_new/skip_if_open).
*/
private static function resolveStatusId($db, string $alias): int
{
return (int) $db->setQuery(
$db->getQuery(true)->select('id')->from('#__mokosuiteclient_ticket_statuses')
->where($db->quoteName('alias') . ' = ' . $db->quote($alias)), 0, 1
)->loadResult();
}
private static function resolvePriorityId($db, string $alias): int
{
return (int) $db->setQuery(
$db->getQuery(true)->select('id')->from('#__mokosuiteclient_ticket_priorities')
->where($db->quoteName('alias') . ' = ' . $db->quote($alias)), 0, 1
)->loadResult();
}
private static function resolveClosedStatusId($db): int
{
return (int) $db->setQuery(
$db->getQuery(true)->select('id')->from('#__mokosuiteclient_ticket_statuses')
->where($db->quoteName('is_closed') . ' = 1'), 0, 1
)->loadResult();
}
private static function createTicketFromAutomation(object $rule, array $context, string $subject): void
{
$db = Factory::getDbo();
$behavior = $rule->behavior ?? 'append';
$userId = (int) ($context['user_id'] ?? 0);
$catId = (int) ($context['category_id'] ?? 0);
if ($behavior !== 'always_new' && $userId > 0)
{
// Check for existing open ticket (check both status ENUM and status_id)
$query = $db->getQuery(true)
->select('t.id')
->from($db->quoteName('#__mokosuiteclient_tickets', 't'))
->join('LEFT', $db->quoteName('#__mokosuiteclient_ticket_statuses', 's') . ' ON t.status_id = s.id')
->where('t.created_by = ' . $userId)
->where("(s.id IS NULL AND t.status NOT IN ('closed', 'resolved')) OR (s.id IS NOT NULL AND s.is_closed = 0)");
if ($catId > 0) {
$query->where('category_id = ' . $catId);
}
$db->setQuery($query, 0, 1);
$existingId = (int) $db->loadResult();
if ($existingId > 0)
{
if ($behavior === 'skip_if_open') return;
// append — add reply to existing ticket
$reply = (object) [
'ticket_id' => $existingId,
'user_id' => 0,
'body' => $subject ?: '[Automation: ' . ($rule->title ?? '') . ']',
'is_internal' => 1,
'created' => Factory::getDate()->toSql(),
];
$db->insertObject('#__mokosuiteclient_ticket_replies', $reply);
return;
}
}
// Create new ticket
$openStatusId = self::resolveStatusId($db, 'open') ?: null;
$normalPriorityId = self::resolvePriorityId($db, $context['priority'] ?? 'normal') ?: null;
$ticket = (object) [
'subject' => $subject ?: 'Automation: ' . ($rule->title ?? ''),
'body' => $context['body'] ?? '',
'status' => 'open',
'status_id' => $openStatusId,
'priority' => $context['priority'] ?? 'normal',
'priority_id' => $normalPriorityId,
'category_id' => $catId ?: null,
'created_by' => $userId,
'created' => Factory::getDate()->toSql(),
];
$db->insertObject('#__mokosuiteclient_tickets', $ticket, 'id');
}
}
@@ -1,575 +0,0 @@
<?php
/**
* @package MokoSuiteClient
* @subpackage com_mokosuiteclient
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
* @license GNU General Public License version 3 or later; see LICENSE
*/
namespace Moko\Component\MokoSuiteClient\Administrator\Service;
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\Log\Log;
use Joomla\CMS\Uri\Uri;
/**
* Helpdesk email notification service.
*
* Sends emails for ticket events to Joomla users (by ID) and/or
* raw email addresses. Uses Joomla's configured mailer.
*
* @since 02.32.00
*/
class NotificationService
{
/**
* Send a ticket notification email.
*
* @param string $event Event name (ticket_created, ticket_replied, status_changed, ticket_assigned)
* @param object $ticket Ticket object with id, subject, status, priority, created_by, assigned_to
* @param array $extra Extra context (reply body, old status, etc.)
*/
public static function notify(string $event, object $ticket, array $extra = []): void
{
try
{
$recipients = self::getRecipients($event, $ticket);
if (empty($recipients))
{
return;
}
$subject = self::buildSubject($event, $ticket);
$body = self::buildBody($event, $ticket, $extra);
$mailer = Factory::getMailer();
$mailer->isHtml(false);
$mailer->setSubject($subject);
$mailer->setBody($body);
foreach ($recipients as $email)
{
$email = trim($email);
if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL))
{
continue;
}
try
{
$mailer->clearAddresses();
$mailer->addRecipient($email);
$mailer->Send();
}
catch (\Throwable $e)
{
Log::add('Notification send failed to ' . $email . ': ' . $e->getMessage(), Log::WARNING, 'mokosuiteclient');
}
}
// Push notification via ntfy
self::pushNtfy($event, $ticket, $subject);
}
catch (\Throwable $e)
{
Log::add('Notification error: ' . $e->getMessage(), Log::WARNING, 'mokosuiteclient');
}
}
/**
* Determine recipients based on event type and ticket data.
*/
private static function getRecipients(string $event, object $ticket): array
{
$emails = [];
// Get notification config from component params
$config = self::getNotificationConfig();
// Always notify configured admin emails
$adminEmails = array_filter(array_map('trim', explode(',', $config['admin_emails'] ?? '')));
$emails = array_merge($emails, $adminEmails);
// Always notify configured admin user IDs
$adminUserIds = array_filter(array_map('intval', explode(',', $config['admin_user_ids'] ?? '')));
foreach ($adminUserIds as $uid)
{
$email = self::getUserEmail($uid);
if ($email)
{
$emails[] = $email;
}
}
switch ($event)
{
case 'ticket_created':
// Notify assigned user if any
if (!empty($ticket->assigned_to))
{
$email = self::getUserEmail((int) $ticket->assigned_to);
if ($email)
{
$emails[] = $email;
}
}
break;
case 'ticket_replied':
// Notify ticket creator (customer gets notified of staff reply)
if (!empty($ticket->created_by))
{
$email = self::getUserEmail((int) $ticket->created_by);
if ($email)
{
$emails[] = $email;
}
}
// Notify assigned user
if (!empty($ticket->assigned_to))
{
$email = self::getUserEmail((int) $ticket->assigned_to);
if ($email)
{
$emails[] = $email;
}
}
break;
case 'status_changed':
// Notify ticket creator
if (!empty($ticket->created_by))
{
$email = self::getUserEmail((int) $ticket->created_by);
if ($email)
{
$emails[] = $email;
}
}
break;
case 'ticket_assigned':
// Notify newly assigned user
if (!empty($ticket->assigned_to))
{
$email = self::getUserEmail((int) $ticket->assigned_to);
if ($email)
{
$emails[] = $email;
}
}
break;
}
return array_unique($emails);
}
/**
* Build email subject line.
*/
private static function buildSubject(string $event, object $ticket): string
{
$siteName = Factory::getConfig()->get('sitename', 'Support');
$prefix = '[' . $siteName . ' #' . $ticket->id . '] ';
switch ($event)
{
case 'ticket_created':
return $prefix . 'New Ticket: ' . ($ticket->subject ?? '');
case 'ticket_replied':
return $prefix . 'Reply: ' . ($ticket->subject ?? '');
case 'status_changed':
return $prefix . 'Status Changed: ' . ($ticket->subject ?? '');
case 'ticket_assigned':
return $prefix . 'Assigned: ' . ($ticket->subject ?? '');
default:
return $prefix . ($ticket->subject ?? '');
}
}
/**
* Build email body.
*/
private static function buildBody(string $event, object $ticket, array $extra): string
{
$siteName = Factory::getConfig()->get('sitename', 'Support');
$siteUrl = rtrim(Uri::root(), '/');
$ticketUrl = $siteUrl . '/index.php?option=com_mokosuiteclient&view=ticket&id=' . $ticket->id;
$lines = [];
$lines[] = $siteName . ' Support';
$lines[] = str_repeat('-', 40);
$lines[] = '';
switch ($event)
{
case 'ticket_created':
$lines[] = 'A new support ticket has been created.';
$lines[] = '';
$lines[] = 'Subject: ' . ($ticket->subject ?? '');
$lines[] = 'Priority: ' . ucfirst($ticket->priority ?? 'normal');
$lines[] = 'Category: ' . ($ticket->category_title ?? 'General');
$lines[] = '';
if (!empty($ticket->body))
{
$lines[] = 'Description:';
$lines[] = strip_tags($ticket->body);
$lines[] = '';
}
break;
case 'ticket_replied':
$lines[] = 'A new reply has been added to your ticket.';
$lines[] = '';
$lines[] = 'Subject: ' . ($ticket->subject ?? '');
$lines[] = 'Status: ' . ucwords(str_replace('_', ' ', $ticket->status ?? ''));
$lines[] = '';
if (!empty($extra['reply_body']))
{
$lines[] = 'Reply:';
$lines[] = strip_tags($extra['reply_body']);
$lines[] = '';
}
break;
case 'status_changed':
$lines[] = 'Your ticket status has been updated.';
$lines[] = '';
$lines[] = 'Subject: ' . ($ticket->subject ?? '');
$lines[] = 'New Status: ' . ucwords(str_replace('_', ' ', $ticket->status ?? ''));
if (!empty($extra['old_status']))
{
$lines[] = 'Old Status: ' . ucwords(str_replace('_', ' ', $extra['old_status']));
}
$lines[] = '';
break;
case 'ticket_assigned':
$lines[] = 'A ticket has been assigned to you.';
$lines[] = '';
$lines[] = 'Subject: ' . ($ticket->subject ?? '');
$lines[] = 'Priority: ' . ucfirst($ticket->priority ?? 'normal');
$lines[] = '';
break;
}
$lines[] = 'View ticket: ' . $ticketUrl;
$lines[] = '';
$lines[] = '-- ';
$lines[] = $siteName . ' | Powered by MokoSuiteClient';
return implode("\n", $lines);
}
/**
* Get email address for a Joomla user ID.
*/
private static function getUserEmail(int $userId): ?string
{
if ($userId <= 0)
{
return null;
}
try
{
$db = Factory::getDbo();
$db->setQuery(
$db->getQuery(true)
->select($db->quoteName('email'))
->from($db->quoteName('#__users'))
->where($db->quoteName('id') . ' = ' . $userId)
);
return $db->loadResult() ?: null;
}
catch (\Throwable $e)
{
return null;
}
}
/**
* Get notification configuration from component params.
*/
private static function getNotificationConfig(): array
{
try
{
$db = Factory::getDbo();
$db->setQuery(
$db->getQuery(true)
->select($db->quoteName('params'))
->from($db->quoteName('#__extensions'))
->where($db->quoteName('element') . ' = ' . $db->quote('com_mokosuiteclient'))
->where($db->quoteName('type') . ' = ' . $db->quote('component'))
);
$params = json_decode($db->loadResult() ?? '{}', true);
return $params['notifications'] ?? [];
}
catch (\Throwable $e)
{
return [];
}
}
// ==================================================================
// Ntfy Push Notifications (#205)
// ==================================================================
/**
* Send a push notification via ntfy for ticket events.
*/
private static function pushNtfy(string $event, object $ticket, string $title): void
{
$config = self::getNotificationConfig();
$ntfyEnabled = $config['ntfy_enabled'] ?? '0';
if (!$ntfyEnabled)
{
return;
}
$ntfyServer = rtrim($config['ntfy_server'] ?? 'https://ntfy.mokoconsulting.tech', '/');
$ntfyTopic = $config['ntfy_topic'] ?? 'mokosuiteclient-tickets';
$ntfyToken = $config['ntfy_token'] ?? '';
$tagMap = [
'ticket_created' => 'ticket,new',
'ticket_replied' => 'speech_balloon',
'status_changed' => 'arrows_counterclockwise',
'ticket_assigned' => 'bust_in_silhouette',
];
$priorityMap = [
'ticket_created' => '4',
'ticket_replied' => '3',
'status_changed' => '3',
'ticket_assigned' => '3',
];
$siteUrl = rtrim(Uri::root(), '/');
$ticketUrl = $siteUrl . '/administrator/index.php?option=com_mokosuiteclient&view=ticket&id=' . ($ticket->id ?? 0);
$message = self::buildNtfyMessage($event, $ticket);
$headers = [
'Title: ' . $title,
'Priority: ' . ($priorityMap[$event] ?? '3'),
'Tags: ' . ($tagMap[$event] ?? 'ticket'),
'Click: ' . $ticketUrl,
];
if ($ntfyToken !== '')
{
$headers[] = 'Authorization: Bearer ' . $ntfyToken;
}
$url = $ntfyServer . '/' . $ntfyTopic;
try
{
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $message);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_exec($ch);
$httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode < 200 || $httpCode >= 300)
{
Log::add("Ntfy push failed (HTTP {$httpCode}) for event {$event}", Log::WARNING, 'mokosuiteclient');
}
}
catch (\Throwable $e)
{
Log::add('Ntfy push error: ' . $e->getMessage(), Log::WARNING, 'mokosuiteclient');
}
}
/**
* Build a short ntfy message body for ticket events.
*/
private static function buildNtfyMessage(string $event, object $ticket): string
{
$subject = $ticket->subject ?? 'Ticket #' . ($ticket->id ?? '?');
switch ($event)
{
case 'ticket_created':
$priority = ucfirst($ticket->priority ?? 'normal');
return "New ticket: {$subject}\nPriority: {$priority}";
case 'ticket_replied':
return "Reply on: {$subject}";
case 'status_changed':
$status = ucwords(str_replace('_', ' ', $ticket->status ?? ''));
return "Status → {$status}: {$subject}";
case 'ticket_assigned':
return "Assigned to you: {$subject}";
default:
return $subject;
}
}
/**
* Send a push notification via ntfy for security events.
*/
public static function pushNtfySecurity(string $event, string $title, string $body): void
{
$config = self::getNotificationConfig();
$ntfyEnabled = $config['ntfy_enabled'] ?? '0';
if (!$ntfyEnabled)
{
return;
}
$ntfyServer = rtrim($config['ntfy_server'] ?? 'https://ntfy.mokoconsulting.tech', '/');
$ntfyTopic = $config['ntfy_security_topic'] ?? $config['ntfy_topic'] ?? 'mokosuiteclient-security';
$ntfyToken = $config['ntfy_token'] ?? '';
$headers = [
'Title: [Security] ' . $title,
'Priority: 5',
'Tags: warning,shield',
];
if ($ntfyToken !== '')
{
$headers[] = 'Authorization: Bearer ' . $ntfyToken;
}
$url = $ntfyServer . '/' . $ntfyTopic;
try
{
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_exec($ch);
curl_close($ch);
}
catch (\Throwable $e)
{
Log::add('Ntfy security push error: ' . $e->getMessage(), Log::WARNING, 'mokosuiteclient');
}
}
// ==================================================================
// Security Event Notifications (#131)
// ==================================================================
/**
* Send a security alert to admin emails.
*/
public static function securityAlert(string $event, string $subject, string $body): void
{
try
{
$config = self::getNotificationConfig();
$enabled = $config['security_alerts'] ?? '1';
if (!$enabled)
{
return;
}
$adminEmails = array_filter(array_map('trim', explode(',', $config['admin_emails'] ?? '')));
$adminUserIds = array_filter(array_map('intval', explode(',', $config['admin_user_ids'] ?? '')));
$recipients = $adminEmails;
foreach ($adminUserIds as $uid)
{
$email = self::getUserEmail($uid);
if ($email)
{
$recipients[] = $email;
}
}
$recipients = array_unique($recipients);
if (empty($recipients))
{
return;
}
$siteName = Factory::getConfig()->get('sitename', 'Site');
$fullSubject = '[' . $siteName . ' Security] ' . $subject;
$lines = [
$siteName . ' Security Alert',
str_repeat('-', 40),
'',
'Event: ' . $event,
'Time: ' . gmdate('Y-m-d H:i:s') . ' UTC',
'',
$body,
'',
'-- ',
$siteName . ' | MokoSuiteClient Security',
];
$mailer = Factory::getMailer();
$mailer->isHtml(false);
$mailer->setSubject($fullSubject);
$mailer->setBody(implode("\n", $lines));
foreach ($recipients as $email)
{
try
{
$mailer->clearAddresses();
$mailer->addRecipient(trim($email));
$mailer->Send();
}
catch (\Throwable $e)
{
Log::add('Security alert send failed: ' . $e->getMessage(), Log::WARNING, 'mokosuiteclient');
}
}
// Also push via ntfy
self::pushNtfySecurity($event, $subject, $body);
}
catch (\Throwable $e)
{
Log::add('Security alert error: ' . $e->getMessage(), Log::WARNING, 'mokosuiteclient');
}
}
}
@@ -18,6 +18,7 @@ class HtmlView extends BaseHtmlView
ToolbarHelper::title('Automation Rules', 'cogs');
ToolbarHelper::back('JTOOLBAR_BACK', 'index.php?option=com_mokosuiteclient&view=tickets');
ToolbarHelper::help('', false, 'https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteClient/wiki/Automation');
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
$wa->registerAndUseStyle('com_mokosuiteclient.dashboard', 'com_mokosuiteclient/dashboard.css');
@@ -1,33 +0,0 @@
<?php
namespace Moko\Component\MokoSuiteClient\Administrator\View\Canned;
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Toolbar\ToolbarHelper;
class HtmlView extends BaseHtmlView
{
protected $responses = [];
protected $categories = [];
public function display($tpl = null)
{
$db = Factory::getContainer()->get('Joomla\Database\DatabaseInterface');
$db->setQuery('SELECT * FROM #__mokosuiteclient_ticket_canned ORDER BY ordering ASC');
$this->responses = $db->loadObjectList() ?: [];
$db->setQuery('SELECT id, title FROM #__mokosuiteclient_ticket_categories WHERE published = 1 ORDER BY ordering');
$this->categories = $db->loadObjectList() ?: [];
ToolbarHelper::title('Canned Responses', 'comment');
ToolbarHelper::back('JTOOLBAR_BACK', 'index.php?option=com_mokosuiteclient&view=tickets');
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
$wa->registerAndUseStyle('com_mokosuiteclient.dashboard', 'com_mokosuiteclient/dashboard.css');
parent::display($tpl);
}
}
@@ -32,6 +32,7 @@ class HtmlView extends BaseHtmlView
ToolbarHelper::title('Ticket Categories', 'folder');
ToolbarHelper::back('JTOOLBAR_BACK', 'index.php?option=com_mokosuiteclient&view=tickets');
ToolbarHelper::help('', false, 'https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteClient/wiki/Categories');
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
$wa->registerAndUseStyle('com_mokosuiteclient.dashboard', 'com_mokosuiteclient/dashboard.css');
@@ -18,6 +18,7 @@ class HtmlView extends BaseHtmlView
ToolbarHelper::title('Cache &amp; Temp Cleanup', 'trash');
ToolbarHelper::back('JTOOLBAR_BACK', 'index.php?option=com_mokosuiteclient');
ToolbarHelper::help('', false, 'https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteClient/wiki/Cleanup');
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
$wa->registerAndUseStyle('com_mokosuiteclient.dashboard', 'com_mokosuiteclient/dashboard.css');
@@ -26,6 +26,9 @@ class HtmlView extends BaseHtmlView
protected $wafChartData = [];
protected $loginChartData = [];
protected $mokoExtensions = [];
public $supportPin = '';
public $supportPinAvailable = false;
public $regularLabsAvailable = false;
public function display($tpl = null)
{
@@ -33,7 +36,26 @@ class HtmlView extends BaseHtmlView
$this->plugins = $model->getFeaturePlugins();
$this->siteInfo = $model->getSiteInfo();
$this->recentLogins = $model->getRecentLogins(5);
// Daily support PIN from health token
$pinState = \Moko\Component\MokoSuiteClient\Administrator\Helper\SupportPinHelper::getState(
\Joomla\CMS\Factory::getContainer()->get(\Joomla\Database\DatabaseInterface::class)
);
$this->supportPinAvailable = $pinState['available'];
$this->supportPin = $pinState['pin'];
// Detect Regular Labs data for import
try {
$rlDb = \Joomla\CMS\Factory::getDbo();
$rlTables = $rlDb->getTableList();
$rlPrefix = $rlDb->getPrefix();
$this->regularLabsAvailable = in_array($rlPrefix . 'conditions', $rlTables)
|| in_array($rlPrefix . 'snippets', $rlTables)
|| in_array($rlPrefix . 'rereplacer', $rlTables)
|| in_array($rlPrefix . 'contenttemplater', $rlTables);
} catch (\Throwable $e) {}
$this->recentLogins = $model->getRecentLogins(10);
$this->pendingUpdates = $model->getPendingUpdates();
$this->checkedOutItems = $model->getCheckedOutItems();
$this->wafBlocks = $model->getRecentWafBlocks(5);
@@ -73,5 +95,7 @@ class HtmlView extends BaseHtmlView
{
ToolbarHelper::preferences('com_mokosuiteclient');
}
ToolbarHelper::help('', false, 'https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteClient/wiki/Dashboard');
}
}
@@ -18,6 +18,7 @@ class HtmlView extends BaseHtmlView
ToolbarHelper::title('Database Tools', 'database');
ToolbarHelper::back('JTOOLBAR_BACK', 'index.php?option=com_mokosuiteclient');
ToolbarHelper::help('', false, 'https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteClient/wiki/Database');
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
$wa->registerAndUseStyle('com_mokosuiteclient.dashboard', 'com_mokosuiteclient/dashboard.css');
@@ -31,6 +31,7 @@ class HtmlView extends BaseHtmlView
$this->pipelineData = $model->getPipelineReport($this->dateFrom, $this->dateTo);
$this->agingData = $model->getAgingReceivables();
ToolbarHelper::title('ERP Reports', 'icon-chart-bar');
ToolbarHelper::help('', false, 'https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteClient/wiki/ERP-Reports');
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
$wa->registerAndUseStyle('com_mokosuiteclient.erp', 'com_mokosuiteclient/erp.css');
$wa->registerAndUseScript('com_mokosuiteclient.erp-dashboard', 'com_mokosuiteclient/erp-dashboard.js', [], ['defer' => true]);
@@ -37,5 +37,6 @@ class HtmlView extends BaseHtmlView
{
ToolbarHelper::title(Text::_('COM_MOKOSUITECLIENT_EXTENSIONS_TITLE'), 'puzzle-piece');
ToolbarHelper::back('JTOOLBAR_BACK', 'index.php?option=com_mokosuiteclient');
ToolbarHelper::help('', false, 'https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteClient/wiki/Extensions');
}
}
@@ -43,5 +43,6 @@ class HtmlView extends BaseHtmlView
{
ToolbarHelper::title(Text::_('COM_MOKOSUITECLIENT_HTACCESS_TITLE'), 'file-code');
ToolbarHelper::back('JTOOLBAR_BACK', 'index.php?option=com_mokosuiteclient');
ToolbarHelper::help('', false, 'https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteClient/wiki/Htaccess');
}
}
@@ -35,5 +35,6 @@ class HtmlView extends BaseHtmlView
{
ToolbarHelper::title('Privacy Guard', 'lock');
ToolbarHelper::back('JTOOLBAR_BACK', 'index.php?option=com_mokosuiteclient');
ToolbarHelper::help('', false, 'https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteClient/wiki/Privacy');
}
}
@@ -1,72 +0,0 @@
<?php
/**
* @package MokoSuiteClient
* @subpackage com_mokosuiteclient
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
* @license GNU General Public License version 3 or later; see LICENSE
*/
namespace Moko\Component\MokoSuiteClient\Administrator\View\Ticket;
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Toolbar\ToolbarHelper;
class HtmlView extends BaseHtmlView
{
protected $ticket;
protected $cannedResponses = [];
protected $statuses = [];
protected $priorities = [];
protected $customFields = [];
protected $fieldValues = [];
protected $attachments = [];
public function display($tpl = null)
{
$model = $this->getModel('Tickets');
$id = Factory::getApplication()->getInput()->getInt('id', 0);
$this->ticket = $model->getTicket($id);
$this->cannedResponses = $model->getCannedResponses((int) ($this->ticket->category_id ?? 0));
$this->statuses = $model->getStatuses();
$this->priorities = $model->getPriorities();
// Load custom fields for this ticket's category
if ($this->ticket && $this->ticket->category_id)
{
$groups = $model->getFieldGroupsForCategory((int) $this->ticket->category_id);
$groupIds = array_column($groups, 'id');
$this->customFields = $model->getFieldsForGroups($groupIds);
$this->fieldValues = $model->getFieldValues($id);
}
// Load attachments
$this->attachments = \Moko\Component\MokoSuiteClient\Administrator\Service\AttachmentService::getForTicket($id);
if (!$this->ticket)
{
Factory::getApplication()->enqueueMessage('Ticket not found.', 'error');
Factory::getApplication()->redirect('index.php?option=com_mokosuiteclient&view=tickets');
return;
}
$this->addToolbar();
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
$wa->registerAndUseStyle('com_mokosuiteclient.dashboard', 'com_mokosuiteclient/dashboard.css');
parent::display($tpl);
}
protected function addToolbar(): void
{
$title = $this->ticket ? 'Ticket #' . $this->ticket->id . ' — ' . $this->ticket->subject : 'Ticket';
ToolbarHelper::title($title, 'headphones');
ToolbarHelper::back('JTOOLBAR_BACK', 'index.php?option=com_mokosuiteclient&view=tickets');
}
}
@@ -1,67 +0,0 @@
<?php
/**
* @package MokoSuiteClient
* @subpackage com_mokosuiteclient
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
* @license GNU General Public License version 3 or later; see LICENSE
*/
namespace Moko\Component\MokoSuiteClient\Administrator\View\Tickets;
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Toolbar\ToolbarHelper;
class HtmlView extends BaseHtmlView
{
protected $tickets = [];
protected $categories = [];
protected $statusCounts;
protected $overdue = [];
protected $atsAvailable = null;
protected $contacts = [];
protected $statuses = [];
protected $priorities = [];
protected $backendUsers = [];
protected $userGroups = [];
public function display($tpl = null)
{
$model = $this->getModel();
$app = Factory::getApplication();
$filters = [
'status_id' => $app->getInput()->getInt('filter_status', 0),
'priority_id' => $app->getInput()->getInt('filter_priority', 0),
'category_id' => $app->getInput()->getInt('filter_category', 0),
'contact_id' => $app->getInput()->getInt('filter_contact', 0),
];
$this->tickets = $model->getTickets($filters);
$this->categories = $model->getCategories();
$this->statuses = $model->getStatuses();
$this->priorities = $model->getPriorities();
$this->statusCounts = $model->getStatusCounts();
$this->overdue = $model->getOverdueTickets();
$this->atsAvailable = $model->checkAtsAvailable();
$this->contacts = $model->getContacts();
$this->backendUsers = $model->getBackendUsers();
$this->userGroups = $model->getUserGroups();
$this->addToolbar();
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
$wa->registerAndUseStyle('com_mokosuiteclient.dashboard', 'com_mokosuiteclient/dashboard.css');
parent::display($tpl);
}
protected function addToolbar(): void
{
ToolbarHelper::title(Text::_('COM_MOKOSUITECLIENT_TICKETS_TITLE'), 'headphones');
ToolbarHelper::back('JTOOLBAR_BACK', 'index.php?option=com_mokosuiteclient');
}
}
@@ -1,41 +0,0 @@
<?php
/**
* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
*
* SPDX-LICENSE-IDENTIFIER: GPL-3.0-or-later
*
* @package MokoSuiteClient
* @subpackage Component
*/
namespace Moko\Component\MokoSuiteClient\Administrator\View\Ticketsettings;
defined('_JEXEC') or die;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Toolbar\ToolbarHelper;
class HtmlView extends BaseHtmlView
{
protected $statuses = [];
protected $priorities = [];
public function display($tpl = null)
{
$model = $this->getModel('Tickets');
$this->statuses = $model->getStatuses();
$this->priorities = $model->getPriorities();
$this->addToolbar();
parent::display($tpl);
}
protected function addToolbar(): void
{
ToolbarHelper::title(Text::_('COM_MOKOSUITE_TICKET_SETTINGS'), 'cog');
ToolbarHelper::back('JTOOLBAR_BACK', 'index.php?option=com_mokosuiteclient&view=tickets');
}
}
@@ -1 +0,0 @@
<html><body bgcolor="#FFFFFF"></body></html>
@@ -51,5 +51,6 @@ class HtmlView extends BaseHtmlView
{
ToolbarHelper::title('WAF Log Viewer', 'shield-alt');
ToolbarHelper::back('JTOOLBAR_BACK', 'index.php?option=com_mokosuiteclient');
ToolbarHelper::help('', false, 'https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteClient/wiki/WAF-Log');
}
}
@@ -1,227 +0,0 @@
<?php
defined('_JEXEC') or die;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Session\Session;
$responses = $this->responses;
$categories = $this->categories;
$token = Session::getFormToken();
$saveUrl = Route::_('index.php?option=com_mokosuiteclient&task=display.saveCanned&format=json');
$deleteUrl = Route::_('index.php?option=com_mokosuiteclient&task=display.deleteCanned&format=json');
$reorderUrl = Route::_('index.php?option=com_mokosuiteclient&task=display.reorderCanned&format=json');
// Build category map for filter display
$catMap = [0 => 'All Categories'];
foreach ($categories as $cat)
{
$catMap[$cat->id] = $cat->title;
}
?>
<div id="mokosuiteclient-canned">
<div class="d-flex justify-content-between align-items-center mb-3">
<div class="d-flex align-items-center gap-3">
<h4 class="mb-0"><?php echo count($responses); ?> Canned Responses</h4>
<select id="canned-filter-category" class="form-select form-select-sm" style="width:auto;">
<option value="">All Categories</option>
<?php foreach ($categories as $cat): ?>
<option value="<?php echo $cat->id; ?>"><?php echo htmlspecialchars($cat->title); ?></option>
<?php endforeach; ?>
</select>
</div>
<button type="button" class="btn btn-primary btn-sm" onclick="openCannedModal(0)">
<span class="icon-plus"></span> Add Response
</button>
</div>
<div id="canned-list">
<?php foreach ($responses as $r): ?>
<div class="card mb-2 canned-card" data-id="<?php echo $r->id; ?>" data-category="<?php echo (int) $r->category_id; ?>" style="cursor:grab;">
<div class="card-body py-2">
<div class="d-flex justify-content-between align-items-start">
<div class="flex-grow-1" style="cursor:pointer;" onclick="openCannedModal(<?php echo $r->id; ?>)">
<div class="d-flex align-items-center gap-2">
<span class="icon-menu text-muted" style="cursor:grab;" title="Drag to reorder"></span>
<strong><?php echo htmlspecialchars($r->title); ?></strong>
<?php if (!empty($r->category_id) && isset($catMap[$r->category_id])): ?>
<span class="badge bg-secondary"><?php echo htmlspecialchars($catMap[$r->category_id]); ?></span>
<?php endif; ?>
</div>
<p class="text-muted small mb-0 mt-1 ms-4"><?php echo htmlspecialchars(mb_substr(strip_tags($r->body), 0, 150)); ?></p>
</div>
<button type="button" class="btn btn-sm btn-outline-danger btn-delete-canned" data-id="<?php echo $r->id; ?>">
<span class="icon-trash"></span>
</button>
</div>
</div>
</div>
<?php endforeach; ?>
<?php if (empty($responses)): ?>
<div class="alert alert-info" id="canned-empty">No canned responses yet. Click "Add Response" to create one.</div>
<?php endif; ?>
</div>
</div>
<!-- Canned Response Modal (create + edit) -->
<div class="modal fade" id="cannedModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 id="cannedModalTitle">Add Canned Response</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<input type="hidden" id="canned-id" value="0">
<div class="mb-3">
<label class="form-label">Title</label>
<input type="text" id="canned-title" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label">Category (optional)</label>
<select id="canned-category" class="form-select">
<option value="">No category</option>
<?php foreach ($categories as $cat): ?>
<option value="<?php echo $cat->id; ?>"><?php echo htmlspecialchars($cat->title); ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="mb-3">
<label class="form-label">Response Text</label>
<textarea id="canned-body" class="form-control" rows="8" required></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" id="btn-save-canned"><span class="icon-save"></span> Save</button>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
var tokenKey = '<?php echo $token; ?>';
// ── Response data store (for edit modal) ────────────────────
var responseData = {};
<?php foreach ($responses as $r): ?>
responseData[<?php echo $r->id; ?>] = {
title: <?php echo json_encode($r->title); ?>,
body: <?php echo json_encode($r->body); ?>,
category_id: <?php echo json_encode($r->category_id ?? ''); ?>
};
<?php endforeach; ?>
// ── Open modal for create (id=0) or edit ────────────────────
window.openCannedModal = function(id) {
document.getElementById('canned-id').value = id;
if (id > 0 && responseData[id]) {
document.getElementById('cannedModalTitle').textContent = 'Edit Canned Response';
document.getElementById('canned-title').value = responseData[id].title;
document.getElementById('canned-body').value = responseData[id].body;
document.getElementById('canned-category').value = responseData[id].category_id || '';
} else {
document.getElementById('cannedModalTitle').textContent = 'Add Canned Response';
document.getElementById('canned-title').value = '';
document.getElementById('canned-body').value = '';
document.getElementById('canned-category').value = '';
}
new bootstrap.Modal(document.getElementById('cannedModal')).show();
};
// ── Save (create or update) ─────────────────────────────────
document.getElementById('btn-save-canned').addEventListener('click', function() {
var title = document.getElementById('canned-title').value.trim();
if (!title) { Joomla.renderMessages({error:['Title is required']}); return; }
var fd = new FormData();
fd.append('id', document.getElementById('canned-id').value);
fd.append('title', title);
fd.append('body', document.getElementById('canned-body').value);
fd.append('category_id', document.getElementById('canned-category').value);
fd.append(tokenKey, '1');
fetch('<?php echo $saveUrl; ?>', {method:'POST', body:fd, headers:{'X-Requested-With':'XMLHttpRequest'}})
.then(function(r){return r.json()})
.then(function(d){
if (d.success) location.reload();
else Joomla.renderMessages({error:[d.message]});
});
});
// ── Delete ──────────────────────────────────────────────────
document.querySelectorAll('.btn-delete-canned').forEach(function(btn) {
btn.addEventListener('click', function(e) {
e.stopPropagation();
if (!confirm('Delete this canned response?')) return;
var card = this.closest('.card');
var fd = new FormData();
fd.append('id', this.dataset.id);
fd.append(tokenKey, '1');
fetch('<?php echo $deleteUrl; ?>', {method:'POST', body:fd, headers:{'X-Requested-With':'XMLHttpRequest'}})
.then(function(r){return r.json()})
.then(function(d){ if (d.success) card.remove(); else Joomla.renderMessages({error:[d.message]}); });
});
});
// ── Category filter ─────────────────────────────────────────
document.getElementById('canned-filter-category').addEventListener('change', function() {
var catId = this.value;
document.querySelectorAll('.canned-card').forEach(function(card) {
if (!catId || card.dataset.category === catId) {
card.style.display = '';
} else {
card.style.display = 'none';
}
});
});
// ── Drag-and-drop reorder ───────────────────────────────────
var list = document.getElementById('canned-list');
var dragCard = null;
list.addEventListener('dragstart', function(e) {
dragCard = e.target.closest('.canned-card');
if (dragCard) {
dragCard.style.opacity = '0.5';
e.dataTransfer.effectAllowed = 'move';
}
});
list.addEventListener('dragend', function() {
if (dragCard) dragCard.style.opacity = '';
dragCard = null;
});
list.addEventListener('dragover', function(e) {
e.preventDefault();
var target = e.target.closest('.canned-card');
if (target && target !== dragCard) {
var rect = target.getBoundingClientRect();
var after = (e.clientY - rect.top) > rect.height / 2;
if (after) {
target.parentNode.insertBefore(dragCard, target.nextSibling);
} else {
target.parentNode.insertBefore(dragCard, target);
}
}
});
list.addEventListener('drop', function(e) {
e.preventDefault();
// Persist new order
var ids = [];
document.querySelectorAll('.canned-card').forEach(function(c) { ids.push(c.dataset.id); });
var fd = new FormData();
fd.append('order', JSON.stringify(ids));
fd.append(tokenKey, '1');
fetch('<?php echo $reorderUrl; ?>', {method:'POST', body:fd, headers:{'X-Requested-With':'XMLHttpRequest'}});
});
// Make cards draggable
document.querySelectorAll('.canned-card').forEach(function(card) {
card.setAttribute('draggable', 'true');
});
});
</script>
@@ -25,6 +25,9 @@ $atsAvail = $this->atsAvailable ?? null;
$checkedOut = $this->checkedOutItems;
$wafBlocks = $this->wafBlocks;
$token = Session::getFormToken();
$user = \Joomla\CMS\Factory::getApplication()->getIdentity();
$canWafLog = $user->authorise('mokosuiteclient.security.waflog', 'com_mokosuiteclient')
|| $user->authorise('core.admin', 'com_mokosuiteclient');
// Group plugins by category
$grouped = [];
@@ -34,89 +37,77 @@ foreach ($plugins as $plugin)
}
$categoryOrder = ['core', 'security', 'monitoring', 'content', 'tools', 'api'];
$actionLogsEnabled = Joomla\CMS\Component\ComponentHelper::isEnabled('com_actionlogs');
?>
<div id="mokosuiteclient-dashboard">
<!-- Site Info Bar -->
<div class="mokosuiteclient-info-bar card mb-4">
<div class="card-body d-flex flex-wrap align-items-center gap-4">
<div class="mokosuiteclient-info-item">
<span class="mokosuiteclient-info-label"><?php echo Text::_('COM_MOKOSUITECLIENT_SITE'); ?></span>
<span class="mokosuiteclient-info-value fw-bold"><?php echo $this->escape($siteInfo->sitename); ?></span>
</div>
<div class="mokosuiteclient-info-item">
<span class="mokosuiteclient-info-label">MokoSuiteClient</span>
<span class="mokosuiteclient-info-value"><span class="badge bg-primary"><?php echo $this->escape($siteInfo->mokosuiteclient_version); ?></span></span>
</div>
<div class="mokosuiteclient-info-item">
<span class="mokosuiteclient-info-label">Joomla</span>
<span class="mokosuiteclient-info-value"><span class="badge bg-secondary"><?php echo $this->escape($siteInfo->joomla_version); ?></span></span>
</div>
<div class="mokosuiteclient-info-item">
<span class="mokosuiteclient-info-label">PHP</span>
<span class="mokosuiteclient-info-value"><span class="badge bg-secondary"><?php echo $this->escape($siteInfo->php_version); ?></span></span>
</div>
<div class="mokosuiteclient-info-item">
<span class="mokosuiteclient-info-label"><?php echo Text::_('COM_MOKOSUITECLIENT_DATABASE'); ?></span>
<span class="mokosuiteclient-info-value"><span class="badge bg-secondary"><?php echo $this->escape($siteInfo->db_type); ?></span></span>
</div>
<?php if ($siteInfo->debug): ?>
<span class="badge bg-warning text-dark"><?php echo Text::_('COM_MOKOSUITECLIENT_DEBUG_ON'); ?></span>
<?php endif; ?>
<?php if ($siteInfo->offline): ?>
<span class="badge bg-danger"><?php echo Text::_('COM_MOKOSUITECLIENT_OFFLINE'); ?></span>
<?php endif; ?>
<div class="mokosuiteclient-info-item ms-auto">
<span class="icon-globe" aria-hidden="true"></span>
<code><?php echo $this->escape($_SERVER['REMOTE_ADDR'] ?? ''); ?></code>
</div>
<?php if (!$actionLogsEnabled): ?>
<div class="alert alert-danger d-flex align-items-center gap-2 mb-4">
<span class="icon-exclamation-triangle" style="font-size:1.25rem"></span>
<div>
<strong>Action Logs Required</strong> — MokoSuite requires Joomla's Action Logs component to be enabled for login tracking and audit compliance.
<a href="<?php echo Route::_('index.php?option=com_plugins&filter[search]=actionlog'); ?>" class="alert-link ms-1">Enable Action Log Plugins</a>
</div>
</div>
<?php if (!empty($mokoExts)): ?>
<!-- Moko Component & Module Versions -->
<div class="d-flex flex-wrap gap-2 mb-4">
<?php
$extIcons = [
'com_mokosuiteclient' => 'icon-cogs',
'mod_mokosuiteclient_cpanel' => 'icon-tachometer-alt',
'mod_mokosuiteclient_menu' => 'icon-bars',
'mod_mokosuiteclient_cache' => 'icon-bolt',
'mod_mokosuiteclient_categories' => 'icon-folder',
];
foreach ($mokoExts as $ext):
$icon = $extIcons[$ext->element] ?? 'icon-puzzle-piece';
$label = str_replace(['mod_mokosuiteclient_', 'com_mokosuiteclient'], ['', 'Component'], $ext->element);
$label = ucfirst($label ?: 'Component');
?>
<div class="d-flex align-items-center gap-2 px-3 py-2 rounded border bg-white" style="font-size:0.85rem;">
<span class="<?php echo $icon; ?>" aria-hidden="true" style="color:#1a2744;"></span>
<span><?php echo $this->escape($label); ?></span>
<span class="badge bg-light text-dark"><?php echo $this->escape($ext->version); ?></span>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
<!-- Site Info Bar -->
<div class="card mb-4">
<div class="card-body d-flex flex-wrap align-items-center gap-2" style="padding:0.75rem 1.25rem;font-size:0.85rem;">
<span class="icon-shield-alt" aria-hidden="true" style="font-size:1.1rem;color:#1a2744"></span>
<span class="fw-bold"><?php echo $this->escape($siteInfo->sitename); ?></span>
<span class="badge bg-primary">MokoSuite <?php echo $this->escape($siteInfo->mokosuiteclient_version); ?></span>
<?php echo \Moko\Component\MokoSuiteClient\Administrator\Helper\SupportPinHelper::renderBadge(
['available' => !empty($this->supportPinAvailable), 'pin' => $this->supportPin ?? ''],
$token, 'dashboard'
); ?>
<?php if (!empty($this->supportPin)): ?>
<button type="button" class="btn btn-sm btn-outline-primary py-0 px-1" id="mokosuiteclient-btn-heartbeat-pin"
data-url="<?php echo Route::_('index.php?option=com_mokosuiteclient&task=display.sendHeartbeat&format=json'); ?>"
data-token="<?php echo $token; ?>"
title="Send heartbeat with PIN to MokoSuiteHQ">
<span class="icon-upload" aria-hidden="true"></span>
</button>
<?php endif; ?>
<span class="badge bg-secondary">Joomla <?php echo $this->escape($siteInfo->joomla_version); ?></span>
<span class="badge bg-secondary">PHP <?php echo $this->escape($siteInfo->php_version); ?></span>
<span class="badge bg-secondary"><?php echo $this->escape($siteInfo->db_type); ?></span>
<?php if ($siteInfo->debug): ?>
<span class="badge bg-warning text-dark">Debug ON</span>
<?php endif; ?>
<?php if ($siteInfo->offline): ?>
<span class="badge bg-danger">Offline</span>
<?php endif; ?>
<span class="ms-auto d-flex align-items-center gap-2">
<span class="icon-globe" aria-hidden="true"></span>
<code><?php echo $this->escape($_SERVER['REMOTE_ADDR'] ?? ''); ?></code>
</span>
</div>
</div>
<?php if ($adminToolsAvail || $atsAvail): ?>
<?php if ($adminToolsAvail): ?>
<!-- Akeeba Import Banner -->
<div class="alert alert-info d-flex flex-wrap align-items-center gap-3 mb-4">
<span class="icon-info-circle" style="font-size:1.25rem"></span>
<strong>Akeeba data detected — import into MokoSuiteClient:</strong>
<?php if ($adminToolsAvail): ?>
<strong>Akeeba data detected:</strong>
<button type="button" class="btn btn-sm btn-info" id="btn-import-admintools"
data-url="<?php echo Route::_('index.php?option=com_mokosuiteclient&task=display.importAdminTools&format=json'); ?>"
data-token="<?php echo $token; ?>">
<span class="icon-shield-alt"></span> Import Admin Tools Settings
</button>
<?php endif; ?>
<?php if ($atsAvail): ?>
<button type="button" class="btn btn-sm btn-info" id="btn-import-ats-dash"
data-url="<?php echo Route::_('index.php?option=com_mokosuiteclient&task=display.importAts&format=json'); ?>"
</div>
<?php endif; ?>
<?php if ($this->regularLabsAvailable): ?>
<!-- Regular Labs Import Banner -->
<div class="alert alert-warning d-flex flex-wrap align-items-center gap-3 mb-4">
<span class="icon-info-circle" style="font-size:1.25rem"></span>
<strong>Regular Labs data detected — import into MokoSuite:</strong>
<button type="button" class="btn btn-sm btn-warning text-dark" id="btn-import-regularlabs"
data-url="<?php echo Route::_('index.php?option=com_mokosuiteclient&task=display.importRegularLabs&format=json'); ?>"
data-token="<?php echo $token; ?>">
<span class="icon-headphones"></span> Import Tickets (<?php echo $atsAvail->tickets; ?> tickets)
<span class="icon-download"></span> Import Conditions, Snippets, Replacements &amp; Templates
</button>
<?php endif; ?>
</div>
<?php endif; ?>
@@ -130,6 +121,14 @@ $categoryOrder = ['core', 'security', 'monitoring', 'content', 'tools', 'api'];
Clear Cache
</button>
</div>
<?php if (\Joomla\CMS\Component\ComponentHelper::isEnabled('com_mokosuitebackup')): ?>
<div class="col-6 col-md-4 col-xl-3">
<a href="<?php echo Route::_('index.php?option=com_mokosuitebackup'); ?>" class="btn btn-outline-primary w-100 py-3">
<span class="icon-archive d-block mb-1" aria-hidden="true" style="font-size:1.5rem"></span>
MokoSuiteBackup
</a>
</div>
<?php endif; ?>
<div class="col-6 col-md-4 col-xl-3">
<a href="<?php echo Route::_('index.php?option=com_installer&view=update'); ?>" class="btn btn-outline-primary w-100 py-3">
<span class="icon-refresh d-block mb-1" aria-hidden="true" style="font-size:1.5rem"></span>
@@ -197,7 +196,7 @@ $categoryOrder = ['core', 'security', 'monitoring', 'content', 'tools', 'api'];
</h3>
<div class="mokosuiteclient-plugin-grid row g-3 mb-4">
<?php foreach ($catPlugins as $plugin): ?>
<div class="col-12 col-md-6">
<div class="col-12 <?php echo $catKey === 'core' ? '' : 'col-md-6 col-lg-4'; ?>">
<div class="card mokosuiteclient-plugin-card h-100 <?php echo $plugin->enabled ? '' : 'mokosuiteclient-plugin-disabled'; ?>"
data-extension-id="<?php echo $plugin->extension_id; ?>">
<div class="card-body d-flex flex-column">
@@ -214,11 +213,7 @@ $categoryOrder = ['core', 'security', 'monitoring', 'content', 'tools', 'api'];
<div class="d-flex align-items-center justify-content-between mt-auto pt-2 border-top">
<?php if ($plugin->protected): ?>
<span class="badge bg-dark"><?php echo Text::_('COM_MOKOSUITECLIENT_PROTECTED'); ?></span>
<?php elseif ($plugin->configure_only): ?>
<span class="badge bg-<?php echo $plugin->enabled ? 'success' : 'secondary'; ?>">
<?php echo $plugin->enabled ? Text::_('COM_MOKOSUITECLIENT_ENABLED') : Text::_('COM_MOKOSUITECLIENT_DISABLED'); ?>
</span>
<?php else: ?>
<?php elseif ($plugin->extension_id): ?>
<div class="form-check form-switch">
<input type="checkbox" class="form-check-input mokosuiteclient-toggle" role="switch"
id="toggle-<?php echo $plugin->extension_id; ?>"
@@ -231,7 +226,7 @@ $categoryOrder = ['core', 'security', 'monitoring', 'content', 'tools', 'api'];
</label>
</div>
<?php endif; ?>
<?php if ($plugin->type === 'plugin'): ?>
<?php if ($plugin->extension_id && $plugin->type === 'plugin'): ?>
<a href="<?php echo Route::_('index.php?option=com_plugins&task=plugin.edit&extension_id=' . $plugin->extension_id); ?>" class="btn btn-sm btn-outline-secondary">
<span class="icon-cog" aria-hidden="true"></span> <?php echo Text::_('COM_MOKOSUITECLIENT_CONFIGURE'); ?>
</a>
@@ -248,6 +243,7 @@ $categoryOrder = ['core', 'security', 'monitoring', 'content', 'tools', 'api'];
<!-- Right: Charts & Information (4 cols) -->
<div class="col-12 col-xl-4" style="border-left:1px solid var(--gray-300, #dee2e6);padding-left:1.5rem;">
<?php if ($canWafLog): ?>
<!-- WAF Activity Chart -->
<div class="card mb-3">
<div class="card-header">
@@ -257,6 +253,7 @@ $categoryOrder = ['core', 'security', 'monitoring', 'content', 'tools', 'api'];
<canvas id="mokosuiteclient-chart-waf" height="140"></canvas>
</div>
</div>
<?php endif; ?>
<!-- Login Activity Chart -->
<div class="card mb-3">
@@ -311,7 +308,7 @@ $categoryOrder = ['core', 'security', 'monitoring', 'content', 'tools', 'api'];
<tr>
<td class="text-muted"><?php echo $this->escape(mb_substr($item->title, 0, 30)); ?></td>
<td class="text-muted"><?php echo $this->escape($item->username ?? ''); ?></td>
<td class="text-muted"><?php echo HTMLHelper::_('date', $item->checked_out_time, 'M d H:i'); ?></td>
<td class="text-muted"><?php echo HTMLHelper::_('date', $item->checked_out_time, Text::_('DATE_FORMAT_LC4')); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
@@ -327,6 +324,7 @@ $categoryOrder = ['core', 'security', 'monitoring', 'content', 'tools', 'api'];
<?php endif; ?>
</div>
<?php if ($canWafLog): ?>
<!-- WAF Blocks -->
<div class="card mb-3">
<div class="card-header d-flex justify-content-between align-items-center">
@@ -342,7 +340,7 @@ $categoryOrder = ['core', 'security', 'monitoring', 'content', 'tools', 'api'];
<tr>
<td class="text-muted"><code><?php echo $this->escape($block->ip); ?></code></td>
<td class="text-muted"><span class="badge bg-danger"><?php echo $this->escape($block->rule); ?></span></td>
<td class="text-muted"><?php echo HTMLHelper::_('date', $block->created, 'M d H:i'); ?></td>
<td class="text-muted"><?php echo HTMLHelper::_('date', $block->created, Text::_('DATE_FORMAT_LC4')); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
@@ -354,6 +352,7 @@ $categoryOrder = ['core', 'security', 'monitoring', 'content', 'tools', 'api'];
</div>
<?php endif; ?>
</div>
<?php endif; ?>
<!-- Recent Logins -->
<div class="card mb-3">
@@ -363,13 +362,28 @@ $categoryOrder = ['core', 'security', 'monitoring', 'content', 'tools', 'api'];
<?php if (!empty($recentLogins)): ?>
<div class="table-responsive">
<table class="table table-sm table-striped mb-0">
<thead><tr><th>User</th><th>IP</th><th>Time</th></tr></thead>
<thead><tr><th>User</th><th>App</th><th>IP</th><th>Time</th></tr></thead>
<tbody>
<?php foreach ($recentLogins as $login): ?>
<?php foreach ($recentLogins as $login):
$msgData = json_decode($login->message ?? '{}');
$appKey = $msgData->app ?? '';
if (stripos($appKey, 'ADMINISTRATOR') !== false) {
$appLabel = 'Admin';
$appBadge = 'bg-dark';
} elseif (stripos($appKey, 'SITE') !== false) {
$appLabel = 'Site';
$appBadge = 'bg-info text-dark';
} else {
$appLabel = 'Unknown';
$appBadge = 'bg-secondary';
}
?>
<tr>
<td class="text-muted"><?php echo $this->escape($login->username ?? ''); ?></td>
<td class="text-muted"><code><?php echo $this->escape($login->ip_address ?? ''); ?></code></td>
<td class="text-muted"><?php echo HTMLHelper::_('date', $login->log_date, 'M d H:i'); ?></td>
<td><span class="badge <?php echo $appBadge; ?>" style="font-size:0.7rem;"><?php echo $appLabel; ?></span></td>
<?php $ip = $login->ip_address ?? ''; ?>
<td class="text-muted"><?php if ($ip && $ip !== 'COM_ACTIONLOGS_DISABLED'): ?><code><?php echo $this->escape($ip); ?></code><?php else: ?><span class="text-muted fst-italic">IP logging off</span><?php endif; ?></td>
<td class="text-muted"><?php echo HTMLHelper::_('date', $login->log_date, Text::_('DATE_FORMAT_LC4')); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
@@ -449,3 +463,5 @@ document.addEventListener('DOMContentLoaded', function() {
}
});
</script>
<?php echo \Moko\Component\MokoSuiteClient\Administrator\Helper\SupportPinHelper::renderScript(); ?>
@@ -3,6 +3,7 @@ defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Session\Session;
@@ -140,8 +141,8 @@ $typeBadge = [
<td><?php echo $this->escape($r->user_name ?? ''); ?><br><small class="text-muted"><?php echo $this->escape($r->user_email ?? ''); ?></small></td>
<td><span class="badge <?php echo $typeBadge[$r->type] ?? 'bg-secondary'; ?>"><?php echo ucfirst($r->type); ?></span></td>
<td><span class="badge <?php echo $statusBadge[$r->status] ?? 'bg-secondary'; ?>"><?php echo ucfirst($r->status); ?></span></td>
<td class="text-nowrap small"><?php echo HTMLHelper::_('date', $r->created, 'M d, Y H:i'); ?></td>
<td class="text-nowrap small"><?php echo $r->processed ? HTMLHelper::_('date', $r->processed, 'M d, Y H:i') : '—'; ?></td>
<td class="text-nowrap small"><?php echo HTMLHelper::_('date', $r->created, Text::_('DATE_FORMAT_LC2')); ?></td>
<td class="text-nowrap small"><?php echo $r->processed ? HTMLHelper::_('date', $r->processed, Text::_('DATE_FORMAT_LC2')) : '—'; ?></td>
<td>
<?php if ($r->status === 'pending'): ?>
<div class="btn-group btn-group-sm">
@@ -1,364 +0,0 @@
<?php
defined('_JEXEC') or die;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Session\Session;
$t = $this->ticket;
$canned = $this->cannedResponses;
$token = Session::getFormToken();
$attachments = $this->attachments;
$downloadUrl = Route::_('index.php?option=com_mokosuiteclient&task=display.downloadAttachment');
$uploadUrl = Route::_('index.php?option=com_mokosuiteclient&task=display.uploadAttachment&format=json');
$deleteAttUrl = Route::_('index.php?option=com_mokosuiteclient&task=display.deleteAttachment&format=json');
// Group attachments by reply_id (null = ticket-level)
$attByReply = [];
foreach ($attachments as $att) {
$key = $att->reply_id ?? 0;
$attByReply[$key][] = $att;
}
$statuses = $this->statuses ?? [];
$priorities = $this->priorities ?? [];
?>
<div id="mokosuiteclient-ticket" class="row">
<!-- Left: conversation thread -->
<div class="col-12 col-xl-8">
<!-- Original ticket -->
<div class="card mb-3">
<div class="card-header d-flex justify-content-between align-items-center">
<div>
<strong><?php echo $this->escape($t->created_by_name); ?></strong>
<small class="text-muted ms-2"><?php echo HTMLHelper::_('date', $t->created, 'M d, Y H:i'); ?></small>
</div>
<span class="badge bg-dark">Original</span>
</div>
<div class="card-body">
<?php echo nl2br($this->escape($t->body)); ?>
<?php if (!empty($attByReply[0])): ?>
<hr>
<div class="small">
<strong>Attachments:</strong>
<?php foreach ($attByReply[0] as $att): ?>
<a href="<?php echo $downloadUrl . '&id=' . $att->id; ?>" class="d-inline-block me-3">
<span class="icon-download"></span> <?php echo $this->escape($att->filename); ?>
<span class="text-muted">(<?php echo \Moko\Component\MokoSuiteClient\Administrator\Service\AttachmentService::formatSize($att->filesize); ?>)</span>
</a>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
</div>
<!-- Replies -->
<?php foreach ($t->replies as $reply): ?>
<div class="card mb-3 <?php echo $reply->is_internal ? 'border-warning' : ''; ?>">
<div class="card-header d-flex justify-content-between align-items-center">
<div>
<strong><?php echo $this->escape($reply->user_name ?? 'System'); ?></strong>
<small class="text-muted ms-2"><?php echo HTMLHelper::_('date', $reply->created, 'M d, Y H:i'); ?></small>
</div>
<?php if ($reply->is_internal): ?>
<span class="badge bg-warning text-dark">Internal Note</span>
<?php endif; ?>
</div>
<div class="card-body">
<?php echo nl2br($this->escape($reply->body)); ?>
<?php if (!empty($attByReply[$reply->id])): ?>
<hr>
<div class="small">
<strong>Attachments:</strong>
<?php foreach ($attByReply[$reply->id] as $att): ?>
<a href="<?php echo $downloadUrl . '&id=' . $att->id; ?>" class="d-inline-block me-3">
<span class="icon-download"></span> <?php echo $this->escape($att->filename); ?>
<span class="text-muted">(<?php echo \Moko\Component\MokoSuiteClient\Administrator\Service\AttachmentService::formatSize($att->filesize); ?>)</span>
</a>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
</div>
<?php endforeach; ?>
<!-- Reply form -->
<div class="card mb-3">
<div class="card-header"><strong>Reply</strong></div>
<div class="card-body">
<?php if (!empty($canned)): ?>
<div class="mb-2">
<select class="form-select form-select-sm" id="canned-select">
<option value="">Insert canned response...</option>
<?php foreach ($canned as $c): ?>
<option value="<?php echo $this->escape($c->body); ?>"><?php echo $this->escape($c->title); ?></option>
<?php endforeach; ?>
</select>
</div>
<?php endif; ?>
<textarea id="reply-body" class="form-control mb-2" rows="5" placeholder="Type your reply..."></textarea>
<div class="mb-2">
<input type="file" id="reply-attachments" class="form-control form-control-sm" multiple
accept=".jpg,.jpeg,.png,.gif,.webp,.pdf,.doc,.docx,.xls,.xlsx,.csv,.txt,.zip">
</div>
<div class="d-flex gap-2">
<button type="button" class="btn btn-primary" id="btn-reply"
data-url="<?php echo Route::_('index.php?option=com_mokosuiteclient&task=display.addTicketReply&format=json'); ?>"
data-ticket="<?php echo $t->id; ?>" data-token="<?php echo $token; ?>">
<span class="icon-reply"></span> Send Reply
</button>
<button type="button" class="btn btn-outline-warning" id="btn-internal"
data-url="<?php echo Route::_('index.php?option=com_mokosuiteclient&task=display.addTicketReply&format=json'); ?>"
data-ticket="<?php echo $t->id; ?>" data-token="<?php echo $token; ?>" data-internal="1">
<span class="icon-eye-slash"></span> Internal Note
</button>
</div>
</div>
</div>
</div>
<!-- Right: ticket metadata -->
<div class="col-12 col-xl-4">
<div class="card mb-3">
<div class="card-header"><strong>Details</strong></div>
<div class="card-body">
<table class="table table-sm mb-0">
<tr><td class="text-muted">Status</td><td><span class="badge <?php echo $this->escape($t->status_color ?? 'bg-secondary'); ?>"><?php echo $this->escape($t->status_title ?? $t->status); ?></span></td></tr>
<tr><td class="text-muted">Priority</td><td><span class="badge <?php echo $this->escape($t->priority_color ?? 'bg-secondary'); ?>"><?php echo $this->escape($t->priority_title ?? $t->priority); ?></span></td></tr>
<tr><td class="text-muted">Category</td><td><?php echo $this->escape($t->category_title ?? '—'); ?></td></tr>
<tr><td class="text-muted">Created By</td><td><?php echo $this->escape($t->created_by_name); ?><br><small><?php echo $this->escape($t->created_by_email ?? ''); ?></small></td></tr>
<tr><td class="text-muted">Assigned To</td><td><?php
if (!empty($t->assignees)) {
foreach ($t->assignees as $a) {
$icon = $a->assignee_type === 'group' ? '<span class="icon-users"></span> ' : '<span class="icon-user"></span> ';
echo '<div>' . $icon . $this->escape($a->name) . '</div>';
}
} else {
echo '<em>Unassigned</em>';
}
?></td></tr>
<?php if ($t->contact_id): ?>
<tr><td class="text-muted">Contact</td><td>
<a href="<?php echo Route::_('index.php?option=com_contact&task=contact.edit&id=' . (int) $t->contact_id); ?>">
<?php echo $this->escape($t->contact_name ?? 'Contact #' . $t->contact_id); ?>
</a>
<?php if (!empty($t->contact_email)): ?><br><small><?php echo $this->escape($t->contact_email); ?></small><?php endif; ?>
<?php if (!empty($t->contact_phone)): ?><br><small><?php echo $this->escape($t->contact_phone); ?></small><?php endif; ?>
</td></tr>
<?php endif; ?>
<tr><td class="text-muted">Created</td><td><?php echo HTMLHelper::_('date', $t->created, 'M d, Y H:i'); ?></td></tr>
<?php if ($t->resolved): ?><tr><td class="text-muted">Resolved</td><td><?php echo HTMLHelper::_('date', $t->resolved, 'M d, Y H:i'); ?></td></tr><?php endif; ?>
<?php if ($t->closed): ?><tr><td class="text-muted">Closed</td><td><?php echo HTMLHelper::_('date', $t->closed, 'M d, Y H:i'); ?></td></tr><?php endif; ?>
<tr><td class="text-muted">Replies</td><td><?php echo $t->reply_count; ?></td></tr>
</table>
</div>
</div>
<!-- SLA -->
<?php if ($t->sla_response_due || $t->sla_resolution_due): ?>
<div class="card mb-3">
<div class="card-header"><strong>SLA</strong></div>
<div class="card-body">
<?php if ($t->sla_response_due): ?>
<div class="mb-2">
<small class="text-muted">Response Due</small><br>
<?php
$responseOverdue = !$t->sla_responded && strtotime($t->sla_response_due) < time();
?>
<span class="<?php echo $t->sla_responded ? 'text-success' : ($responseOverdue ? 'text-danger fw-bold' : ''); ?>">
<?php echo $t->sla_responded ? 'Responded' : HTMLHelper::_('date', $t->sla_response_due, 'M d H:i'); ?>
<?php echo $responseOverdue ? ' OVERDUE' : ''; ?>
</span>
</div>
<?php endif; ?>
<?php if ($t->sla_resolution_due): ?>
<div>
<small class="text-muted">Resolution Due</small><br>
<?php
$resolutionOverdue = !!empty($t->status_is_closed) && strtotime($t->sla_resolution_due) < time();
?>
<span class="<?php echo !empty($t->status_is_closed) ? 'text-success' : ($resolutionOverdue ? 'text-danger fw-bold' : ''); ?>">
<?php echo !empty($t->status_is_closed) ? 'Met' : HTMLHelper::_('date', $t->sla_resolution_due, 'M d H:i'); ?>
<?php echo $resolutionOverdue ? ' OVERDUE' : ''; ?>
</span>
</div>
<?php endif; ?>
</div>
</div>
<?php endif; ?>
<!-- Satisfaction Rating -->
<?php
$isClosed = in_array($t->status, ['resolved', 'closed'], true);
$hasRating = !empty($t->satisfaction_rating);
?>
<?php if ($hasRating): ?>
<div class="card mb-3">
<div class="card-header"><strong>Satisfaction</strong></div>
<div class="card-body text-center">
<div class="mb-1">
<?php for ($s = 1; $s <= 5; $s++): ?>
<span style="font-size:1.5rem;color:<?php echo $s <= $t->satisfaction_rating ? '#f5a623' : '#dee2e6'; ?>;">&#9733;</span>
<?php endfor; ?>
</div>
<div class="text-muted small"><?php echo $t->satisfaction_rating; ?>/5</div>
<?php if (!empty($t->satisfaction_feedback)): ?>
<p class="small mt-2 mb-0"><?php echo $this->escape($t->satisfaction_feedback); ?></p>
<?php endif; ?>
</div>
</div>
<?php elseif ($isClosed): ?>
<div class="card mb-3" id="rating-card">
<div class="card-header"><strong>Rate this Support</strong></div>
<div class="card-body text-center">
<div class="mb-2" id="star-rating">
<?php for ($s = 1; $s <= 5; $s++): ?>
<span class="star-btn" data-value="<?php echo $s; ?>" style="font-size:2rem;cursor:pointer;color:#dee2e6;">&#9733;</span>
<?php endfor; ?>
</div>
<textarea id="rating-feedback" class="form-control form-control-sm mb-2" rows="2" placeholder="Optional feedback..."></textarea>
<button type="button" class="btn btn-primary btn-sm" id="btn-rate"
data-url="<?php echo Route::_('index.php?option=com_mokosuiteclient&task=display.rateTicket&format=json'); ?>"
data-ticket="<?php echo $t->id; ?>" data-token="<?php echo $token; ?>" disabled>
Submit Rating
</button>
</div>
</div>
<?php endif; ?>
<!-- Status actions -->
<div class="card mb-3">
<div class="card-header"><strong>Actions</strong></div>
<div class="card-body d-grid gap-2">
<?php foreach ($statuses as $s): ?>
<?php if ((int) $s->id !== (int) $t->status_id): ?>
<button type="button" class="btn btn-sm btn-outline-<?php echo $s->is_closed ? 'danger' : 'secondary'; ?> btn-status"
data-url="<?php echo Route::_('index.php?option=com_mokosuiteclient&task=display.updateTicketStatus&format=json'); ?>"
data-ticket="<?php echo $t->id; ?>" data-status="<?php echo $s->id; ?>" data-token="<?php echo $token; ?>">
<?php echo $this->escape($s->title); ?>
</button>
<?php endif; ?>
<?php endforeach; ?>
</div>
</div>
<!-- Custom Fields -->
<?php if (!empty($this->customFields)): ?>
<div class="card mb-3">
<div class="card-header"><strong>Custom Fields</strong></div>
<div class="card-body">
<table class="table table-sm mb-0">
<?php foreach ($this->customFields as $field): ?>
<tr>
<td class="text-muted"><?php echo $this->escape($field->title); ?></td>
<td><?php echo $this->escape($this->fieldValues[(int) $field->id] ?? '—'); ?></td>
</tr>
<?php endforeach; ?>
</table>
</div>
</div>
<?php endif; ?>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Canned response insert
var cannedSel = document.getElementById('canned-select');
if (cannedSel) {
cannedSel.addEventListener('change', function() {
if (this.value) { document.getElementById('reply-body').value = this.value; this.selectedIndex = 0; }
});
}
// Reply buttons (with attachment upload)
document.querySelectorAll('#btn-reply, #btn-internal').forEach(function(btn) {
btn.addEventListener('click', function() {
var body = document.getElementById('reply-body').value.trim();
var fileInput = document.getElementById('reply-attachments');
if (!body && (!fileInput || !fileInput.files.length)) return;
var el = this;
el.disabled = true;
var fd = new FormData();
fd.append('ticket_id', el.dataset.ticket);
fd.append('body', body || '(attachment)');
fd.append('is_internal', el.dataset.internal || '0');
fd.append(el.dataset.token, '1');
fetch(el.dataset.url, {method:'POST', body:fd, headers:{'X-Requested-With':'XMLHttpRequest'}})
.then(function(r){return r.json()})
.then(function(d){
if (!d.success) { Joomla.renderMessages({error:[d.message]}); el.disabled = false; return; }
// Upload attachments if any
if (fileInput && fileInput.files.length > 0) {
var afd = new FormData();
afd.append('ticket_id', el.dataset.ticket);
if (d.reply_id) afd.append('reply_id', d.reply_id);
for (var i = 0; i < fileInput.files.length; i++) {
afd.append('attachments[' + i + ']', fileInput.files[i]);
}
afd.append(el.dataset.token, '1');
fetch('<?php echo $uploadUrl; ?>', {method:'POST', body:afd, headers:{'X-Requested-With':'XMLHttpRequest'}})
.then(function(){ location.reload(); });
} else {
location.reload();
}
})
.catch(function(){ el.disabled = false; });
});
});
// Status buttons
document.querySelectorAll('.btn-status').forEach(function(btn) {
btn.addEventListener('click', function() {
var el = this;
el.disabled = true;
var fd = new FormData();
fd.append('ticket_id', el.dataset.ticket);
fd.append('status', el.dataset.status);
fd.append(el.dataset.token, '1');
fetch(el.dataset.url, {method:'POST', body:fd, headers:{'X-Requested-With':'XMLHttpRequest'}})
.then(function(r){return r.json()})
.then(function(d){ if(d.success) location.reload(); else Joomla.renderMessages({error:[d.message]}); })
.finally(function(){ el.disabled = false; });
});
});
// Star rating
var selectedRating = 0;
document.querySelectorAll('.star-btn').forEach(function(star) {
star.addEventListener('mouseenter', function() {
var val = parseInt(this.dataset.value);
document.querySelectorAll('.star-btn').forEach(function(s) {
s.style.color = parseInt(s.dataset.value) <= val ? '#f5a623' : '#dee2e6';
});
});
star.addEventListener('mouseleave', function() {
document.querySelectorAll('.star-btn').forEach(function(s) {
s.style.color = parseInt(s.dataset.value) <= selectedRating ? '#f5a623' : '#dee2e6';
});
});
star.addEventListener('click', function() {
selectedRating = parseInt(this.dataset.value);
document.getElementById('btn-rate').disabled = false;
});
});
var rateBtn = document.getElementById('btn-rate');
if (rateBtn) {
rateBtn.addEventListener('click', function() {
if (!selectedRating) return;
var el = this;
el.disabled = true;
var fd = new FormData();
fd.append('ticket_id', el.dataset.ticket);
fd.append('rating', selectedRating);
fd.append('feedback', document.getElementById('rating-feedback').value);
fd.append(el.dataset.token, '1');
fetch(el.dataset.url, {method:'POST', body:fd, headers:{'X-Requested-With':'XMLHttpRequest'}})
.then(function(r){return r.json()})
.then(function(d){ if(d.success) location.reload(); else Joomla.renderMessages({error:[d.message]}); })
.finally(function(){ el.disabled = false; });
});
}
});
</script>
@@ -1,317 +0,0 @@
<?php
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Session\Session;
$tickets = $this->tickets;
$categories = $this->categories;
$statuses = $this->statuses;
$priorities = $this->priorities;
$counts = $this->statusCounts;
$overdue = $this->overdue;
$atsAvailable = $this->atsAvailable;
$token = Session::getFormToken();
?>
<div id="mokosuiteclient-tickets">
<!-- Status summary cards -->
<div class="row g-3 mb-4">
<?php foreach ($counts as $sc): ?>
<div class="col"><div class="card text-center p-2"><span class="fw-bold fs-4"><?php echo (int) $sc->cnt; ?></span><small class="text-muted"><?php echo $this->escape($sc->title); ?></small></div></div>
<?php endforeach; ?>
<?php if (\count($overdue) > 0): ?>
<div class="col"><div class="card text-center p-2 border-danger"><span class="fw-bold fs-4 text-danger"><?php echo \count($overdue); ?></span><small class="text-danger">SLA Overdue</small></div></div>
<?php endif; ?>
</div>
<!-- New ticket + filters -->
<div class="d-flex flex-wrap justify-content-between align-items-center mb-3">
<div class="d-flex gap-2">
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#newTicketModal">
<span class="icon-plus"></span> New Ticket
</button>
<?php if ($atsAvailable): ?>
<button type="button" class="btn btn-outline-info" id="btn-import-ats"
data-url="<?php echo Route::_('index.php?option=com_mokosuiteclient&task=display.importAts&format=json'); ?>"
data-token="<?php echo $token; ?>"
data-tickets="<?php echo $atsAvailable->tickets; ?>"
data-posts="<?php echo $atsAvailable->posts; ?>">
<span class="icon-upload"></span> Import from Akeeba (<?php echo $atsAvailable->tickets; ?> tickets, <?php echo $atsAvailable->posts; ?> posts)
</button>
<?php endif; ?>
</div>
<form method="get" class="d-flex gap-2">
<input type="hidden" name="option" value="com_mokosuiteclient">
<input type="hidden" name="view" value="tickets">
<select name="filter_status" class="form-select form-select-sm" style="width:auto" onchange="this.form.submit()">
<option value="">All Statuses</option>
<?php foreach ($statuses as $s): ?>
<option value="<?php echo $s->id; ?>" <?php echo Factory::getApplication()->getInput()->getInt('filter_status') === (int) $s->id ? 'selected' : ''; ?>><?php echo $this->escape($s->title); ?></option>
<?php endforeach; ?>
</select>
<select name="filter_priority" class="form-select form-select-sm" style="width:auto" onchange="this.form.submit()">
<option value="">All Priorities</option>
<?php foreach ($priorities as $p): ?>
<option value="<?php echo $p->id; ?>" <?php echo Factory::getApplication()->getInput()->getInt('filter_priority') === (int) $p->id ? 'selected' : ''; ?>><?php echo $this->escape($p->title); ?></option>
<?php endforeach; ?>
</select>
</form>
</div>
<!-- Ticket table -->
<div class="card">
<div class="table-responsive">
<table class="table table-striped table-hover mb-0">
<thead>
<tr>
<th>#</th>
<th>Subject</th>
<th>Status</th>
<th>Priority</th>
<th>Category</th>
<th>Contact</th>
<th>Created By</th>
<th>Assigned To</th>
<th>Created</th>
<th>SLA</th>
</tr>
</thead>
<tbody>
<?php if (empty($tickets)): ?>
<tr><td colspan="10" class="text-center text-muted py-4">No tickets found.</td></tr>
<?php else: ?>
<?php foreach ($tickets as $t): ?>
<?php
$slaClass = '';
$now = time();
if ($t->sla_response_due && !$t->sla_responded && strtotime($t->sla_response_due) < $now) $slaClass = 'table-danger';
elseif ($t->sla_resolution_due && strtotime($t->sla_resolution_due) < $now && empty($t->status_is_closed)) $slaClass = 'table-danger';
elseif ($t->sla_response_due && !$t->sla_responded && strtotime($t->sla_response_due) < $now + 3600) $slaClass = 'table-warning';
?>
<tr class="<?php echo $slaClass; ?>">
<td><a href="<?php echo Route::_('index.php?option=com_mokosuiteclient&view=ticket&id=' . $t->id); ?>"><?php echo $t->id; ?></a></td>
<td><a href="<?php echo Route::_('index.php?option=com_mokosuiteclient&view=ticket&id=' . $t->id); ?>"><?php echo $this->escape(mb_substr($t->subject, 0, 60)); ?></a></td>
<td><span class="badge <?php echo $this->escape($t->status_color ?? 'bg-secondary'); ?>"><?php echo $this->escape($t->status_title ?? $t->status); ?></span></td>
<td><span class="badge <?php echo $this->escape($t->priority_color ?? 'bg-secondary'); ?>"><?php echo $this->escape($t->priority_title ?? $t->priority); ?></span></td>
<td><?php echo $this->escape($t->category_title ?? '—'); ?></td>
<td><?php echo $t->contact_name ? '<a href="' . Route::_('index.php?option=com_contact&task=contact.edit&id=' . (int) $t->contact_id) . '">' . $this->escape($t->contact_name) . '</a>' : '—'; ?></td>
<td><?php echo $this->escape($t->created_by_name ?? ''); ?></td>
<td><?php
if (!empty($t->assignees)) {
$names = [];
foreach ($t->assignees as $a) {
$icon = $a->assignee_type === 'group' ? '<span class="icon-users"></span> ' : '';
$names[] = $icon . $this->escape($a->name);
}
echo implode(', ', $names);
} else {
echo '<em>Unassigned</em>';
}
?></td>
<td class="small"><?php echo HTMLHelper::_('date', $t->created, 'M d H:i'); ?></td>
<td class="small">
<?php if ($t->sla_response_due && !$t->sla_responded): ?>
<span title="Response due"><?php echo HTMLHelper::_('date', $t->sla_response_due, 'M d H:i'); ?></span>
<?php elseif ($t->sla_resolution_due): ?>
<span title="Resolution due"><?php echo HTMLHelper::_('date', $t->sla_resolution_due, 'M d H:i'); ?></span>
<?php else: ?>—<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
<!-- New Ticket Modal -->
<div class="modal fade" id="newTicketModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header"><h5 class="modal-title">New Ticket</h5><button type="button" class="btn-close" data-bs-dismiss="modal"></button></div>
<div class="modal-body">
<!-- KB Search step -->
<div id="modal-kb-step">
<label class="form-label fw-bold">What's the issue?</label>
<div class="input-group mb-3">
<input type="text" id="modal-kb-search" class="form-control" placeholder="Describe your issue to search for existing answers...">
<button type="button" class="btn btn-outline-primary" id="modal-kb-btn"><span class="icon-search"></span></button>
</div>
<div id="modal-kb-results" class="list-group mb-3 d-none"></div>
<button type="button" class="btn btn-primary" id="modal-show-form">
<span class="icon-plus"></span> Create Ticket
</button>
</div>
<!-- Ticket form step (hidden initially) -->
<form id="modal-ticket-form" class="d-none" method="post" action="<?php echo Route::_('index.php?option=com_mokosuiteclient&task=display.createTicket&format=json'); ?>">
<div class="mb-3">
<label class="form-label">Subject</label>
<input type="text" name="subject" id="modal-subject" class="form-control" required>
</div>
<div class="row mb-3">
<div class="col-md-4">
<label class="form-label">Category</label>
<select name="category_id" class="form-select">
<option value="">— Select —</option>
<?php foreach ($categories as $cat): ?>
<option value="<?php echo $cat->id; ?>"><?php echo $this->escape($cat->title); ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-4">
<label class="form-label">Priority</label>
<select name="priority_id" class="form-select">
<?php foreach ($priorities as $p): ?>
<option value="<?php echo $p->id; ?>" <?php echo $p->is_default ? 'selected' : ''; ?>><?php echo $this->escape($p->title); ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-4">
<label class="form-label">Contact</label>
<select name="contact_id" class="form-select">
<option value="">— None —</option>
<?php foreach ($this->contacts as $contact): ?>
<option value="<?php echo $contact->id; ?>"><?php echo $this->escape($contact->name); ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="row mb-3">
<div class="col-md-6">
<label class="form-label">Assign Users</label>
<select name="assign_users[]" class="form-select" multiple size="4">
<?php foreach ($this->backendUsers as $u): ?>
<option value="<?php echo $u->id; ?>"><?php echo $this->escape($u->name); ?></option>
<?php endforeach; ?>
</select>
<small class="text-muted">Hold Ctrl/Cmd to select multiple</small>
</div>
<div class="col-md-6">
<label class="form-label">Assign Groups</label>
<select name="assign_groups[]" class="form-select" multiple size="4">
<?php foreach ($this->userGroups as $g): ?>
<option value="<?php echo $g->id; ?>"><?php echo $this->escape($g->title); ?></option>
<?php endforeach; ?>
</select>
<small class="text-muted">Hold Ctrl/Cmd to select multiple</small>
</div>
</div>
<div class="mb-3">
<label class="form-label">Description</label>
<textarea name="body" class="form-control" rows="6" required></textarea>
</div>
<input type="hidden" name="<?php echo $token; ?>" value="1">
<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary"><span class="icon-plus"></span> Create Ticket</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
</div>
</form>
</div>
</div>
</div>
</div>
<script>
// Modal KB search
var modalSearch = document.getElementById('modal-kb-search');
var modalSearchBtn = document.getElementById('modal-kb-btn');
var modalResults = document.getElementById('modal-kb-results');
var modalShowForm = document.getElementById('modal-show-form');
var modalKbStep = document.getElementById('modal-kb-step');
var modalForm = document.getElementById('modal-ticket-form');
var modalSubject = document.getElementById('modal-subject');
function modalDoSearch() {
var q = modalSearch.value.trim();
if (q.length < 3) return;
fetch('<?php echo Route::_('index.php?option=com_mokosuiteclient&task=display.searchKb&format=json'); ?>&q=' + encodeURIComponent(q), {
headers: {'X-Requested-With': 'XMLHttpRequest'}
}).then(function(r){return r.json()}).then(function(d) {
modalResults.textContent = '';
if (d.results && d.results.length > 0) {
d.results.forEach(function(item) {
var a = document.createElement('a');
a.href = item.url;
a.target = '_blank';
a.className = 'list-group-item list-group-item-action';
var strong = document.createElement('strong');
strong.textContent = item.title;
a.appendChild(strong);
if (item.description) {
a.appendChild(document.createElement('br'));
var small = document.createElement('small');
small.className = 'text-muted';
small.textContent = item.description;
a.appendChild(small);
}
modalResults.appendChild(a);
});
modalResults.classList.remove('d-none');
} else {
modalResults.classList.add('d-none');
}
});
}
if (modalSearchBtn) modalSearchBtn.addEventListener('click', modalDoSearch);
if (modalSearch) modalSearch.addEventListener('keydown', function(e) { if (e.key === 'Enter') { e.preventDefault(); modalDoSearch(); } });
// Show ticket form
if (modalShowForm) {
modalShowForm.addEventListener('click', function() {
modalKbStep.classList.add('d-none');
modalForm.classList.remove('d-none');
if (modalSearch.value && !modalSubject.value) modalSubject.value = modalSearch.value;
modalSubject.focus();
});
}
// Submit ticket from modal
if (modalForm) {
modalForm.addEventListener('submit', function(e) {
e.preventDefault();
var form = this;
var fd = new FormData(form);
fetch(form.action, {method:'POST', body:fd, headers:{'X-Requested-With':'XMLHttpRequest'}})
.then(function(r){return r.json()})
.then(function(d){
if (d.success) { location.href = 'index.php?option=com_mokosuiteclient&view=ticket&id=' + d.id; }
else { Joomla.renderMessages({error:[d.message]}); }
});
});
}
// Reset modal on close
document.getElementById('newTicketModal').addEventListener('hidden.bs.modal', function() {
modalKbStep.classList.remove('d-none');
modalForm.classList.add('d-none');
modalResults.classList.add('d-none');
modalSearch.value = '';
modalForm.reset();
});
// ATS Import
var atsBtn = document.getElementById('btn-import-ats');
if (atsBtn) {
atsBtn.addEventListener('click', function() {
var el = this;
if (!confirm('Import ' + el.dataset.tickets + ' tickets and ' + el.dataset.posts + ' posts from Akeeba Ticket System? Duplicates will be skipped.')) return;
el.disabled = true;
el.textContent = ' Importing...';
var fd = new FormData();
fd.append(el.dataset.token, '1');
fetch(el.dataset.url, {method:'POST', body:fd, headers:{'X-Requested-With':'XMLHttpRequest'}})
.then(function(r){return r.json()})
.then(function(d){
if (d.success) { Joomla.renderMessages({message:[d.message]}); location.reload(); }
else { Joomla.renderMessages({error:[d.message]}); el.disabled = false; el.textContent = 'Import Failed - Retry'; }
})
.catch(function(){ Joomla.renderMessages({error:['Network error']}); el.disabled = false; });
});
}
</script>
@@ -1,203 +0,0 @@
<?php
/**
* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
*
* SPDX-LICENSE-IDENTIFIER: GPL-3.0-or-later
*
* @package MokoSuiteClient
* @subpackage Component
*/
defined('_JEXEC') or die;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Session\Session;
$token = Session::getFormToken();
$colorOptions = [
'bg-primary', 'bg-secondary', 'bg-success', 'bg-danger',
'bg-warning text-dark', 'bg-info text-dark', 'bg-dark', 'bg-light text-dark',
];
?>
<div class="row">
<!-- Statuses -->
<div class="col-lg-6">
<div class="card mb-4">
<div class="card-header d-flex justify-content-between align-items-center">
<strong><span class="fa-solid fa-circle-dot"></span> Ticket Statuses</strong>
</div>
<div class="card-body p-0">
<table class="table table-striped mb-0">
<thead>
<tr>
<th>Title</th>
<th class="w-10 text-center">Color</th>
<th class="w-10 text-center">Default</th>
<th class="w-10 text-center">Closed?</th>
<th class="w-10 text-center">Order</th>
<th class="w-10 text-center">Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($this->statuses as $s): ?>
<tr>
<td><?php echo $this->escape($s->title); ?> <small class="text-muted">(<?php echo $this->escape($s->alias); ?>)</small></td>
<td class="text-center"><span class="badge <?php echo $this->escape($s->color); ?>">&nbsp;&nbsp;&nbsp;</span></td>
<td class="text-center"><?php echo $s->is_default ? '<span class="badge bg-success">Yes</span>' : ''; ?></td>
<td class="text-center"><?php echo $s->is_closed ? '<span class="badge bg-dark">Closed</span>' : ''; ?></td>
<td class="text-center"><?php echo (int) $s->ordering; ?></td>
<td class="text-center">
<button class="btn btn-sm btn-outline-primary" onclick="editStatus(<?php echo htmlspecialchars(json_encode($s)); ?>)">
<span class="icon-pencil"></span>
</button>
<a href="<?php echo Route::_('index.php?option=com_mokosuiteclient&task=display.deleteStatus&id=' . $s->id . '&' . $token . '=1'); ?>"
class="btn btn-sm btn-outline-danger"
onclick="return confirm('Delete this status?')">
<span class="icon-trash"></span>
</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div class="card-footer">
<form method="post" action="<?php echo Route::_('index.php?option=com_mokosuiteclient&task=display.saveStatus'); ?>" id="statusForm" class="row g-2 align-items-end">
<input type="hidden" name="id" id="status-id" value="0">
<div class="col-md-3">
<label class="form-label small">Title</label>
<input type="text" name="title" id="status-title" class="form-control form-control-sm" required>
</div>
<div class="col-md-2">
<label class="form-label small">Alias</label>
<input type="text" name="alias" id="status-alias" class="form-control form-control-sm">
</div>
<div class="col-md-2">
<label class="form-label small">Color</label>
<select name="color" id="status-color" class="form-select form-select-sm">
<?php foreach ($colorOptions as $c): ?>
<option value="<?php echo $c; ?>"><?php echo $c; ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-1">
<label class="form-label small">Order</label>
<input type="number" name="ordering" id="status-ordering" class="form-control form-control-sm" value="0">
</div>
<div class="col-md-1 text-center">
<label class="form-label small">Default</label>
<input type="checkbox" name="is_default" id="status-default" value="1" class="form-check-input">
</div>
<div class="col-md-1 text-center">
<label class="form-label small">Closed</label>
<input type="checkbox" name="is_closed" id="status-closed" value="1" class="form-check-input">
</div>
<div class="col-md-2">
<input type="hidden" name="<?php echo $token; ?>" value="1">
<button type="submit" class="btn btn-sm btn-primary w-100" id="status-btn">Add</button>
</div>
</form>
</div>
</div>
</div>
<!-- Priorities -->
<div class="col-lg-6">
<div class="card mb-4">
<div class="card-header d-flex justify-content-between align-items-center">
<strong><span class="fa-solid fa-flag"></span> Ticket Priorities</strong>
</div>
<div class="card-body p-0">
<table class="table table-striped mb-0">
<thead>
<tr>
<th>Title</th>
<th class="w-10 text-center">Color</th>
<th class="w-10 text-center">Default</th>
<th class="w-10 text-center">Order</th>
<th class="w-10 text-center">Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($this->priorities as $p): ?>
<tr>
<td><?php echo $this->escape($p->title); ?> <small class="text-muted">(<?php echo $this->escape($p->alias); ?>)</small></td>
<td class="text-center"><span class="badge <?php echo $this->escape($p->color); ?>">&nbsp;&nbsp;&nbsp;</span></td>
<td class="text-center"><?php echo $p->is_default ? '<span class="badge bg-success">Yes</span>' : ''; ?></td>
<td class="text-center"><?php echo (int) $p->ordering; ?></td>
<td class="text-center">
<button class="btn btn-sm btn-outline-primary" onclick="editPriority(<?php echo htmlspecialchars(json_encode($p)); ?>)">
<span class="icon-pencil"></span>
</button>
<a href="<?php echo Route::_('index.php?option=com_mokosuiteclient&task=display.deletePriority&id=' . $p->id . '&' . $token . '=1'); ?>"
class="btn btn-sm btn-outline-danger"
onclick="return confirm('Delete this priority?')">
<span class="icon-trash"></span>
</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div class="card-footer">
<form method="post" action="<?php echo Route::_('index.php?option=com_mokosuiteclient&task=display.savePriority'); ?>" id="priorityForm" class="row g-2 align-items-end">
<input type="hidden" name="id" id="priority-id" value="0">
<div class="col-md-3">
<label class="form-label small">Title</label>
<input type="text" name="title" id="priority-title" class="form-control form-control-sm" required>
</div>
<div class="col-md-2">
<label class="form-label small">Alias</label>
<input type="text" name="alias" id="priority-alias" class="form-control form-control-sm">
</div>
<div class="col-md-2">
<label class="form-label small">Color</label>
<select name="color" id="priority-color" class="form-select form-select-sm">
<?php foreach ($colorOptions as $c): ?>
<option value="<?php echo $c; ?>"><?php echo $c; ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-1">
<label class="form-label small">Order</label>
<input type="number" name="ordering" id="priority-ordering" class="form-control form-control-sm" value="0">
</div>
<div class="col-md-1 text-center">
<label class="form-label small">Default</label>
<input type="checkbox" name="is_default" id="priority-default" value="1" class="form-check-input">
</div>
<div class="col-md-3">
<input type="hidden" name="<?php echo $token; ?>" value="1">
<button type="submit" class="btn btn-sm btn-primary w-100" id="priority-btn">Add</button>
</div>
</form>
</div>
</div>
</div>
</div>
<script>
function editStatus(s) {
document.getElementById('status-id').value = s.id;
document.getElementById('status-title').value = s.title;
document.getElementById('status-alias').value = s.alias;
document.getElementById('status-color').value = s.color;
document.getElementById('status-ordering').value = s.ordering;
document.getElementById('status-default').checked = !!parseInt(s.is_default);
document.getElementById('status-closed').checked = !!parseInt(s.is_closed);
document.getElementById('status-btn').textContent = 'Update';
}
function editPriority(p) {
document.getElementById('priority-id').value = p.id;
document.getElementById('priority-title').value = p.title;
document.getElementById('priority-alias').value = p.alias;
document.getElementById('priority-color').value = p.color;
document.getElementById('priority-ordering').value = p.ordering;
document.getElementById('priority-default').checked = !!parseInt(p.is_default);
document.getElementById('priority-btn').textContent = 'Update';
}
</script>
@@ -1 +0,0 @@
<html><body bgcolor="#FFFFFF"></body></html>
@@ -3,6 +3,7 @@ defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Session\Session;
@@ -98,7 +99,7 @@ $ruleBadge = [
<?php else: ?>
<?php foreach ($logs as $log): ?>
<tr>
<td class="text-nowrap small"><?php echo HTMLHelper::_('date', $log->created, 'M d H:i:s'); ?></td>
<td class="text-nowrap small"><?php echo HTMLHelper::_('date', $log->created, Text::_('DATE_FORMAT_LC4')); ?></td>
<td><code><?php echo htmlspecialchars($log->ip); ?></code></td>
<td><span class="badge <?php echo $ruleBadge[$log->rule] ?? 'bg-secondary'; ?>"><?php echo htmlspecialchars($log->rule); ?></span></td>
<td class="small" style="max-width:250px;overflow:hidden;text-overflow:ellipsis" title="<?php echo htmlspecialchars($log->uri); ?>"><?php echo htmlspecialchars(mb_substr($log->uri, 0, 60)); ?></td>
@@ -148,7 +149,7 @@ $ruleBadge = [
<tr>
<td><code class="small"><?php echo htmlspecialchars($tip->ip); ?></code></td>
<td class="fw-bold"><?php echo $tip->cnt; ?></td>
<td class="small text-nowrap"><?php echo HTMLHelper::_('date', $tip->last_seen, 'M d'); ?></td>
<td class="small text-nowrap"><?php echo HTMLHelper::_('date', $tip->last_seen, Text::_('DATE_FORMAT_LC4')); ?></td>
<td>
<button type="button" class="btn btn-sm btn-outline-danger btn-ban-ip" data-ip="<?php echo htmlspecialchars($tip->ip); ?>"
data-url="<?php echo Route::_('index.php?option=com_mokosuiteclient&task=display.banIpFromLog&format=json'); ?>"
@@ -1,278 +0,0 @@
<?php
/**
* @package MokoSuiteClient
* @subpackage com_mokosuiteclient
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
* @license GNU General Public License version 3 or later; see LICENSE
*/
namespace Moko\Component\MokoSuiteClient\Api\Controller;
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\MVC\Controller\BaseController;
/**
* Helpdesk Tickets REST API controller.
*
* GET /api/index.php/v1/mokosuiteclient/tickets - list tickets
* GET /api/index.php/v1/mokosuiteclient/tickets/{id} - get single ticket with replies
* POST /api/index.php/v1/mokosuiteclient/tickets - create ticket
* PATCH /api/index.php/v1/mokosuiteclient/tickets/{id} - update ticket fields
* POST /api/index.php/v1/mokosuiteclient/tickets/{id}/reply - add reply
*
* @since 02.35.00
*/
class TicketsController extends BaseController
{
/**
* GET /tickets — list tickets with optional filters.
*/
public function displayList(): void
{
$this->requireAuth('core.manage', 'com_mokosuiteclient');
$app = Factory::getApplication();
$db = Factory::getDbo();
$input = $app->getInput();
$query = $db->getQuery(true)
->select('t.*, s.title AS status_title, p.title AS priority_title, c.title AS category_title, u.name AS created_by_name')
->from($db->quoteName('#__mokosuiteclient_tickets', 't'))
->leftJoin($db->quoteName('#__mokosuiteclient_ticket_statuses', 's') . ' ON s.id = t.status_id')
->leftJoin($db->quoteName('#__mokosuiteclient_ticket_priorities', 'p') . ' ON p.id = t.priority_id')
->leftJoin($db->quoteName('#__mokosuiteclient_ticket_categories', 'c') . ' ON c.id = t.category_id')
->leftJoin($db->quoteName('#__users', 'u') . ' ON u.id = t.created_by')
->order('t.created DESC');
// Filters
$status = $input->getString('status', '');
if ($status) {
$query->where($db->quoteName('t.status') . ' = ' . $db->quote($status));
}
$categoryId = $input->getInt('category_id', 0);
if ($categoryId) {
$query->where($db->quoteName('t.category_id') . ' = ' . $categoryId);
}
$assignedTo = $input->getInt('assigned_to', 0);
if ($assignedTo) {
$query->where($db->quoteName('t.assigned_to') . ' = ' . $assignedTo);
}
$limit = min($input->getInt('limit', 25), 100);
$offset = $input->getInt('offset', 0);
$db->setQuery($query, $offset, $limit);
$tickets = $db->loadObjectList() ?: [];
// Total count
$countQuery = $db->getQuery(true)->select('COUNT(*)')->from('#__mokosuiteclient_tickets');
$db->setQuery($countQuery);
$total = (int) $db->loadResult();
$this->sendJson(200, [
'tickets' => $tickets,
'total' => $total,
'limit' => $limit,
'offset' => $offset,
]);
}
/**
* GET /tickets/{id} — single ticket with replies and attachments.
*/
public function displayItem(): void
{
$this->requireAuth('core.manage', 'com_mokosuiteclient');
$id = Factory::getApplication()->getInput()->getInt('id', 0);
$db = Factory::getDbo();
// Ticket
$db->setQuery(
$db->getQuery(true)
->select('t.*, s.title AS status_title, p.title AS priority_title, c.title AS category_title, u.name AS created_by_name')
->from($db->quoteName('#__mokosuiteclient_tickets', 't'))
->leftJoin($db->quoteName('#__mokosuiteclient_ticket_statuses', 's') . ' ON s.id = t.status_id')
->leftJoin($db->quoteName('#__mokosuiteclient_ticket_priorities', 'p') . ' ON p.id = t.priority_id')
->leftJoin($db->quoteName('#__mokosuiteclient_ticket_categories', 'c') . ' ON c.id = t.category_id')
->leftJoin($db->quoteName('#__users', 'u') . ' ON u.id = t.created_by')
->where('t.id = ' . $id)
);
$ticket = $db->loadObject();
if (!$ticket) {
$this->sendJson(404, ['error' => 'Ticket not found']);
return;
}
// Replies
$db->setQuery(
$db->getQuery(true)
->select('r.*, u.name AS user_name')
->from($db->quoteName('#__mokosuiteclient_ticket_replies', 'r'))
->leftJoin($db->quoteName('#__users', 'u') . ' ON u.id = r.user_id')
->where('r.ticket_id = ' . $id)
->order('r.created ASC')
);
$ticket->replies = $db->loadObjectList() ?: [];
// Attachments
$ticket->attachments = \Moko\Component\MokoSuiteClient\Administrator\Service\AttachmentService::getForTicket($id);
$this->sendJson(200, $ticket);
}
/**
* POST /tickets — create a new ticket.
*/
public function create(): void
{
$this->requireAuth('core.manage', 'com_mokosuiteclient');
$input = Factory::getApplication()->getInput();
$db = Factory::getDbo();
$subject = $input->getString('subject', '');
$body = $input->getRaw('body', '');
if (empty($subject)) {
$this->sendJson(400, ['error' => 'Subject is required']);
return;
}
$statusId = $input->getInt('status_id', 0) ?: null;
$priorityId = $input->getInt('priority_id', 0) ?: null;
$status = $input->getString('status', 'open');
$priority = $input->getString('priority', 'normal');
// Resolve status_id from alias if not provided
if (!$statusId && $status) {
$q = $db->getQuery(true)->select('id')->from('#__mokosuiteclient_ticket_statuses')
->where($db->quoteName('alias') . ' = ' . $db->quote($status));
$statusId = (int) $db->setQuery($q, 0, 1)->loadResult() ?: null;
}
if (!$priorityId && $priority) {
$q = $db->getQuery(true)->select('id')->from('#__mokosuiteclient_ticket_priorities')
->where($db->quoteName('alias') . ' = ' . $db->quote($priority));
$priorityId = (int) $db->setQuery($q, 0, 1)->loadResult() ?: null;
}
$ticket = (object) [
'subject' => $subject,
'body' => $body,
'status' => $status,
'status_id' => $statusId,
'priority' => $priority,
'priority_id' => $priorityId,
'category_id' => $input->getInt('category_id', 0) ?: null,
'created_by' => (int) Factory::getUser()->id,
'assigned_to' => $input->getInt('assigned_to', 0) ?: null,
'created' => Factory::getDate()->toSql(),
];
$db->insertObject('#__mokosuiteclient_tickets', $ticket, 'id');
// Trigger notification
\Moko\Component\MokoSuiteClient\Administrator\Service\NotificationService::notify('ticket_created', $ticket);
$this->sendJson(201, ['id' => (int) $ticket->id, 'message' => 'Ticket created']);
}
/**
* PATCH /tickets/{id} — update ticket fields.
*/
public function update(): void
{
$this->requireAuth('core.manage', 'com_mokosuiteclient');
$input = Factory::getApplication()->getInput();
$id = $input->getInt('id', 0);
$db = Factory::getDbo();
$fields = [];
$updatable = ['status', 'status_id', 'priority', 'priority_id', 'category_id', 'assigned_to'];
foreach ($updatable as $field) {
$value = $input->get($field, null, 'raw');
if ($value !== null) {
$fields[$field] = $value;
}
}
if (empty($fields)) {
$this->sendJson(400, ['error' => 'No fields to update']);
return;
}
$sets = [];
foreach ($fields as $k => $v) {
$sets[] = $db->quoteName($k) . ' = ' . $db->quote($v);
}
$sets[] = 'modified = ' . $db->quote(Factory::getDate()->toSql());
$db->setQuery('UPDATE ' . $db->quoteName('#__mokosuiteclient_tickets') . ' SET ' . implode(', ', $sets) . ' WHERE id = ' . $id)->execute();
$this->sendJson(200, ['id' => $id, 'message' => 'Ticket updated', 'updated' => array_keys($fields)]);
}
/**
* POST /tickets/{id}/reply — add a reply.
*/
public function reply(): void
{
$this->requireAuth('core.manage', 'com_mokosuiteclient');
$input = Factory::getApplication()->getInput();
$ticketId = $input->getInt('id', 0);
$body = $input->getRaw('body', '');
if (!$ticketId || empty($body)) {
$this->sendJson(400, ['error' => 'ticket_id and body are required']);
return;
}
$db = Factory::getDbo();
$reply = (object) [
'ticket_id' => $ticketId,
'user_id' => (int) Factory::getUser()->id,
'body' => $body,
'is_internal' => $input->getInt('is_internal', 0),
'created' => Factory::getDate()->toSql(),
];
$db->insertObject('#__mokosuiteclient_ticket_replies', $reply, 'id');
// Notify
$db->setQuery($db->getQuery(true)->select('*')->from('#__mokosuiteclient_tickets')->where('id = ' . $ticketId));
$ticket = $db->loadObject();
if ($ticket) {
\Moko\Component\MokoSuiteClient\Administrator\Service\NotificationService::notify('ticket_replied', $ticket, ['reply_body' => $body]);
}
$this->sendJson(201, ['reply_id' => (int) $reply->id, 'message' => 'Reply added']);
}
// ── Helpers ──────────────────────────────────────────────────
private function requireAuth(string $action, string $asset): void
{
$user = Factory::getUser();
if (!$user->authorise($action, $asset)) {
$this->sendJson(403, ['error' => 'Not authorized']);
}
}
private function sendJson(int $code, $payload): void
{
$app = Factory::getApplication();
$app->setHeader('Content-Type', 'application/json', true);
$app->setHeader('Status', (string) $code, true);
echo json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$app->close();
}
}
@@ -3,28 +3,43 @@
* @package com_mokosuiteclient
*/
/* Info bar */
/* Info bar — full-width with evenly distributed items */
.mokosuiteclient-info-bar .card-body {
padding: 1rem 1.5rem;
padding: 0.75rem 1.25rem;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 0.5rem 1rem;
}
.mokosuiteclient-info-item {
display: flex;
align-items: center;
gap: 0.5rem;
gap: 0.35rem;
flex: 0 1 auto;
min-width: 0;
}
.mokosuiteclient-info-label {
font-size: 0.8125rem;
font-size: 0.75rem;
color: #6c757d;
text-transform: uppercase;
letter-spacing: 0.025em;
letter-spacing: 0.04em;
white-space: nowrap;
}
.mokosuiteclient-info-value {
font-size: 0.875rem;
font-size: 0.85rem;
white-space: nowrap;
}
.mokosuiteclient-info-value .badge {
font-size: 0.8rem;
padding: 0.3em 0.6em;
}
/* Plugin cards */
.mokosuiteclient-plugin-card {
transition: box-shadow 0.15s ease, opacity 0.15s ease;
@@ -110,6 +110,71 @@ document.addEventListener('DOMContentLoaded', function () {
});
}
// Heartbeat + PIN send button
var hbBtn = document.getElementById('mokosuiteclient-btn-heartbeat-pin');
if (hbBtn) {
hbBtn.addEventListener('click', function () {
var btn = this;
var url = btn.dataset.url;
var token = btn.dataset.token;
var icon = btn.querySelector('span');
btn.disabled = true;
if (icon) icon.className = 'icon-spinner icon-spin';
var fd = new FormData();
fd.append(token, '1');
fetch(url, {method: 'POST', body: fd, headers: {'X-Requested-With': 'XMLHttpRequest'}})
.then(function (r) { return r.json(); })
.then(function (d) {
if (d.success) {
Joomla.renderMessages({message: [d.message || 'Heartbeat sent to HQ.']});
} else {
Joomla.renderMessages({error: [d.message || 'Heartbeat failed.']});
}
})
.catch(function () {
Joomla.renderMessages({error: ['Network error sending heartbeat.']});
})
.finally(function () {
btn.disabled = false;
if (icon) icon.className = 'icon-upload';
});
});
}
// Regular Labs import
var rlBtn = document.getElementById('btn-import-regularlabs');
if (rlBtn) {
rlBtn.addEventListener('click', function () {
var btn = this;
if (!confirm('Import Regular Labs data (conditions, snippets, replacements, templates) into MokoSuite?')) return;
btn.disabled = true;
var origText = btn.textContent;
btn.textContent = ' Importing...';
var fd = new FormData();
fd.append(btn.dataset.token, '1');
fetch(btn.dataset.url, {method: 'POST', body: fd, headers: {'X-Requested-With': 'XMLHttpRequest'}})
.then(function (r) { return r.json(); })
.then(function (d) {
if (d.success) {
Joomla.renderMessages({message: [d.message]});
setTimeout(function () { location.reload(); }, 2000);
} else {
Joomla.renderMessages({error: [d.message]});
btn.disabled = false;
btn.textContent = origText;
}
})
.catch(function () {
Joomla.renderMessages({error: ['Network error']});
btn.disabled = false;
btn.textContent = origText;
});
});
}
// Akeeba import buttons
['btn-import-admintools', 'btn-import-ats-dash'].forEach(function(id) {
var btn = document.getElementById(id);
@@ -20,7 +20,7 @@
<license>GPL-3.0-or-later</license>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
<authorUrl>https://mokoconsulting.tech</authorUrl>
<version>02.34.84-dev</version>
<version>02.48.24</version>
<description>MokoSuiteClient admin dashboard and REST API. Provides a control panel for managing MokoSuiteClient feature plugins, site health monitoring, and remote management endpoints.</description>
<namespace path="src">Moko\Component\MokoSuiteClient</namespace>
@@ -42,7 +42,6 @@
<submenu>
<menu link="option=com_mokosuiteclient" img="class:cogs">COM_MOKOSUITECLIENT_MENU_DASHBOARD</menu>
<menu link="option=com_mokosuiteclient&amp;view=extensions" img="class:puzzle-piece">COM_MOKOSUITECLIENT_MENU_EXTENSIONS</menu>
<menu link="option=com_mokosuiteclient&amp;view=tickets" img="class:headphones">COM_MOKOSUITECLIENT_MENU_TICKETS</menu>
<menu link="option=com_mokosuiteclient&amp;view=htaccess" img="class:file-code">COM_MOKOSUITECLIENT_MENU_HTACCESS</menu>
<menu link="option=com_mokosuiteclient&amp;view=privacy" img="class:lock">COM_MOKOSUITECLIENT_MENU_PRIVACY</menu>
<menu link="option=com_mokosuiteclient&amp;view=waflog" img="class:shield-alt">COM_MOKOSUITECLIENT_MENU_WAFLOG</menu>
@@ -1,84 +0,0 @@
<?php
/**
* @package MokoSuiteClient
* @subpackage com_mokosuiteclient.site
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
* @license GNU General Public License version 3 or later; see LICENSE
*/
namespace Moko\Component\MokoSuiteClient\Site\View\Ticket;
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Router\Route;
class HtmlView extends BaseHtmlView
{
protected $ticket;
protected $isStaff = false;
protected $canAssign = false;
public function display($tpl = null)
{
$db = Factory::getContainer()->get('Joomla\Database\DatabaseInterface');
$user = Factory::getApplication()->getIdentity();
$id = Factory::getApplication()->getInput()->getInt('id', 0);
$this->isStaff = $user->authorise('core.admin') || $user->authorise('mokosuiteclient.tickets', 'com_mokosuiteclient');
$this->canAssign = $user->authorise('core.admin') || $user->authorise('mokosuiteclient.tickets.assign', 'com_mokosuiteclient');
// Get ticket — staff see any, customers see only their own
$query = $db->getQuery(true)
->select([
$db->quoteName('t') . '.*',
$db->quoteName('c.title', 'category_title'),
$db->quoteName('u.name', 'created_by_name'),
$db->quoteName('u.email', 'created_by_email'),
$db->quoteName('a.name', 'assigned_to_name'),
])
->from($db->quoteName('#__mokosuiteclient_tickets', 't'))
->leftJoin($db->quoteName('#__mokosuiteclient_ticket_categories', 'c') . ' ON c.id = t.category_id')
->leftJoin($db->quoteName('#__users', 'u') . ' ON u.id = t.created_by')
->leftJoin($db->quoteName('#__users', 'a') . ' ON a.id = t.assigned_to')
->where($db->quoteName('t.id') . ' = ' . $id);
if (!$this->isStaff)
{
$query->where($db->quoteName('t.created_by') . ' = ' . (int) $user->id);
}
$db->setQuery($query);
$this->ticket = $db->loadObject();
if (!$this->ticket)
{
Factory::getApplication()->enqueueMessage('Ticket not found.', 'error');
Factory::getApplication()->redirect(Route::_('index.php?option=com_mokosuiteclient&view=tickets', false));
return;
}
// Load replies — staff see internal notes, customers don't
$query = $db->getQuery(true)
->select([
$db->quoteName('r') . '.*',
$db->quoteName('u.name', 'user_name'),
])
->from($db->quoteName('#__mokosuiteclient_ticket_replies', 'r'))
->leftJoin($db->quoteName('#__users', 'u') . ' ON u.id = r.user_id')
->where($db->quoteName('r.ticket_id') . ' = ' . $id);
if (!$this->isStaff)
{
$query->where($db->quoteName('r.is_internal') . ' = 0');
}
$query->order($db->quoteName('r.created') . ' ASC');
$db->setQuery($query);
$this->ticket->replies = $db->loadObjectList() ?: [];
parent::display($tpl);
}
}
@@ -1,75 +0,0 @@
<?php
/**
* @package MokoSuiteClient
* @subpackage com_mokosuiteclient.site
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
* @license GNU General Public License version 3 or later; see LICENSE
*/
namespace Moko\Component\MokoSuiteClient\Site\View\Tickets;
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
class HtmlView extends BaseHtmlView
{
protected $tickets = [];
protected $categories = [];
protected $isStaff = false;
public function display($tpl = null)
{
$db = Factory::getContainer()->get('Joomla\Database\DatabaseInterface');
$user = Factory::getApplication()->getIdentity();
$this->isStaff = $user->authorise('core.admin')
|| $user->authorise('mokosuiteclient.tickets', 'com_mokosuiteclient');
// Staff see all tickets, customers see their own
$query = $db->getQuery(true)
->select([
$db->quoteName('t.id'),
$db->quoteName('t.subject'),
$db->quoteName('t.status'),
$db->quoteName('t.priority'),
$db->quoteName('t.created'),
$db->quoteName('t.assigned_to'),
$db->quoteName('c.title', 'category_title'),
$db->quoteName('u.name', 'created_by_name'),
$db->quoteName('a.name', 'assigned_to_name'),
])
->from($db->quoteName('#__mokosuiteclient_tickets', 't'))
->leftJoin($db->quoteName('#__mokosuiteclient_ticket_categories', 'c') . ' ON c.id = t.category_id')
->leftJoin($db->quoteName('#__users', 'u') . ' ON u.id = t.created_by')
->leftJoin($db->quoteName('#__users', 'a') . ' ON a.id = t.assigned_to');
if (!$this->isStaff)
{
$query->where($db->quoteName('t.created_by') . ' = ' . (int) $user->id);
}
$filterStatus = Factory::getApplication()->getInput()->getString('filter_status', '');
if ($filterStatus)
{
$query->where($db->quoteName('t.status') . ' = ' . $db->quote($filterStatus));
}
$query->order($db->quoteName('t.created') . ' DESC')->setLimit(50);
$db->setQuery($query);
$this->tickets = $db->loadObjectList() ?: [];
// Categories for new ticket form
$query = $db->getQuery(true)
->select([$db->quoteName('id'), $db->quoteName('title')])
->from($db->quoteName('#__mokosuiteclient_ticket_categories'))
->where($db->quoteName('published') . ' = 1')
->order($db->quoteName('ordering') . ' ASC');
$db->setQuery($query);
$this->categories = $db->loadObjectList() ?: [];
parent::display($tpl);
}
}
@@ -1,241 +0,0 @@
<?php
defined('_JEXEC') or die;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Session\Session;
use Joomla\CMS\Factory;
$t = $this->ticket;
$isStaff = $this->isStaff;
$canAssign = $this->canAssign;
$token = Session::getFormToken();
$userId = Factory::getApplication()->getIdentity()->id;
$statusLabel = [
'open' => 'Open', 'in_progress' => 'In Progress', 'waiting' => 'Awaiting Response',
'resolved' => 'Resolved', 'closed' => 'Closed',
];
$statusClass = [
'open' => 'primary', 'in_progress' => 'info', 'waiting' => 'warning',
'resolved' => 'success', 'closed' => 'secondary',
];
?>
<div class="mokosuiteclient-portal-ticket">
<div class="mb-3">
<a href="<?php echo Route::_('index.php?option=com_mokosuiteclient&view=tickets'); ?>" class="btn btn-sm btn-outline-secondary">
<span class="icon-arrow-left"></span> Back to Tickets
</a>
</div>
<div class="row">
<!-- Main column: conversation -->
<div class="col-12 <?php echo $isStaff ? 'col-lg-8' : ''; ?>">
<!-- Ticket header -->
<div class="card mb-3">
<div class="card-body">
<div class="d-flex justify-content-between align-items-start">
<div>
<h3 class="mb-1">#<?php echo $t->id; ?> — <?php echo htmlspecialchars($t->subject); ?></h3>
<small class="text-muted">
<?php echo htmlspecialchars($t->category_title ?? 'General'); ?>
&middot; <?php echo HTMLHelper::_('date', $t->created, 'M d, Y H:i'); ?>
&middot; <?php echo ucfirst($t->priority); ?>
<?php if ($isStaff): ?>
&middot; By: <?php echo htmlspecialchars($t->created_by_name); ?>
<?php endif; ?>
</small>
</div>
<span class="badge bg-<?php echo $statusClass[$t->status] ?? 'secondary'; ?> fs-6">
<?php echo $statusLabel[$t->status] ?? $t->status; ?>
</span>
</div>
</div>
</div>
<!-- Original message -->
<div class="card mb-3">
<div class="card-header">
<strong><?php echo htmlspecialchars($t->created_by_name); ?></strong>
<small class="text-muted ms-2"><?php echo HTMLHelper::_('date', $t->created, 'M d, Y H:i'); ?></small>
</div>
<div class="card-body"><?php echo nl2br(htmlspecialchars($t->body)); ?></div>
</div>
<!-- Replies -->
<?php foreach ($t->replies as $reply): ?>
<?php
$replyIsStaffUser = ((int) $reply->user_id !== (int) $t->created_by);
$isInternal = (int) $reply->is_internal;
?>
<div class="card mb-3 <?php echo $isInternal ? 'border-warning bg-warning bg-opacity-10' : ($replyIsStaffUser ? 'border-primary' : ''); ?>">
<div class="card-header d-flex justify-content-between">
<div>
<strong><?php echo htmlspecialchars($reply->user_name ?? 'Support'); ?></strong>
<?php if ($replyIsStaffUser): ?><span class="badge bg-primary ms-1">Staff</span><?php endif; ?>
<?php if ($isInternal): ?><span class="badge bg-warning text-dark ms-1">Internal Note</span><?php endif; ?>
<small class="text-muted ms-2"><?php echo HTMLHelper::_('date', $reply->created, 'M d, Y H:i'); ?></small>
</div>
</div>
<div class="card-body"><?php echo nl2br(htmlspecialchars($reply->body)); ?></div>
</div>
<?php endforeach; ?>
<!-- Reply form -->
<?php if (!\in_array($t->status, ['closed'])): ?>
<div class="card mt-4">
<div class="card-body">
<h5>Reply</h5>
<form id="portalReply">
<textarea name="body" class="form-control mb-3" rows="5" required placeholder="Type your reply..."></textarea>
<input type="hidden" name="ticket_id" value="<?php echo $t->id; ?>">
<input type="hidden" name="<?php echo $token; ?>" value="1">
<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary">
<span class="icon-paper-plane"></span> Send Reply
</button>
<?php if ($isStaff): ?>
<button type="button" class="btn btn-outline-warning" id="btn-internal-note">
<span class="icon-eye-slash"></span> Internal Note
</button>
<?php endif; ?>
</div>
</form>
</div>
</div>
<?php elseif ($t->status === 'closed'): ?>
<div class="alert alert-secondary mt-4">
This ticket is closed. <a href="<?php echo Route::_('index.php?option=com_mokosuiteclient&view=tickets&layout=submit'); ?>">Open a new ticket</a> if you need further help.
</div>
<?php endif; ?>
</div>
<!-- Staff sidebar -->
<?php if ($isStaff): ?>
<div class="col-12 col-lg-4">
<!-- Ticket info -->
<div class="card mb-3">
<div class="card-header"><strong>Details</strong></div>
<div class="card-body">
<dl class="row mb-0">
<dt class="col-5 text-muted">Status</dt>
<dd class="col-7"><span class="badge bg-<?php echo $statusClass[$t->status] ?? 'secondary'; ?>"><?php echo $statusLabel[$t->status] ?? $t->status; ?></span></dd>
<dt class="col-5 text-muted">Priority</dt>
<dd class="col-7"><?php echo ucfirst($t->priority); ?></dd>
<dt class="col-5 text-muted">Category</dt>
<dd class="col-7"><?php echo htmlspecialchars($t->category_title ?? '—'); ?></dd>
<dt class="col-5 text-muted">Submitted By</dt>
<dd class="col-7"><?php echo htmlspecialchars($t->created_by_name); ?><br><small class="text-muted"><?php echo htmlspecialchars($t->created_by_email ?? ''); ?></small></dd>
<dt class="col-5 text-muted">Assigned To</dt>
<dd class="col-7"><?php echo htmlspecialchars($t->assigned_to_name ?? 'Unassigned'); ?></dd>
<dt class="col-5 text-muted">Created</dt>
<dd class="col-7"><?php echo HTMLHelper::_('date', $t->created, 'M d H:i'); ?></dd>
<dt class="col-5 text-muted">Replies</dt>
<dd class="col-7"><?php echo \count($t->replies); ?></dd>
</dl>
</div>
</div>
<!-- Status actions -->
<div class="card mb-3">
<div class="card-header"><strong>Change Status</strong></div>
<div class="card-body d-grid gap-2">
<?php foreach (['open' => 'Reopen', 'in_progress' => 'In Progress', 'waiting' => 'Waiting on Customer', 'resolved' => 'Resolve', 'closed' => 'Close'] as $s => $label): ?>
<?php if ($s !== $t->status): ?>
<button type="button" class="btn btn-sm btn-outline-<?php echo $s === 'closed' ? 'danger' : ($s === 'resolved' ? 'success' : 'secondary'); ?> btn-status"
data-status="<?php echo $s; ?>">
<?php echo $label; ?>
</button>
<?php endif; ?>
<?php endforeach; ?>
</div>
</div>
<?php if ($canAssign): ?>
<!-- Quick assign -->
<div class="card mb-3">
<div class="card-header"><strong>Assign</strong></div>
<div class="card-body">
<button type="button" class="btn btn-sm btn-outline-primary w-100" id="btn-assign-me">
Assign to Me
</button>
</div>
</div>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
var token = '<?php echo $token; ?>';
var ticketId = <?php echo $t->id; ?>;
// Reply
var replyForm = document.getElementById('portalReply');
if (replyForm) {
replyForm.addEventListener('submit', function(e) {
e.preventDefault();
sendReply(false);
});
}
// Internal note
var internalBtn = document.getElementById('btn-internal-note');
if (internalBtn) {
internalBtn.addEventListener('click', function() { sendReply(true); });
}
function sendReply(isInternal) {
var body = replyForm.querySelector('textarea[name=body]').value.trim();
if (!body) return;
var fd = new FormData();
fd.append('ticket_id', ticketId);
fd.append('body', body);
fd.append('is_internal', isInternal ? '1' : '0');
fd.append(token, '1');
fetch('<?php echo Route::_("index.php?option=com_mokosuiteclient&task=display.submitReply&format=json"); ?>', {
method:'POST', body:fd, headers:{'X-Requested-With':'XMLHttpRequest'}
}).then(function(r){return r.json()}).then(function(d){
if (d.success) location.reload();
else alert(d.message);
});
}
// Status buttons
document.querySelectorAll('.btn-status').forEach(function(btn) {
btn.addEventListener('click', function() {
var fd = new FormData();
fd.append('ticket_id', ticketId);
fd.append('status', this.dataset.status);
fd.append(token, '1');
fetch('<?php echo Route::_("index.php?option=com_mokosuiteclient&task=display.updateStatus&format=json"); ?>', {
method:'POST', body:fd, headers:{'X-Requested-With':'XMLHttpRequest'}
}).then(function(r){return r.json()}).then(function(d){
if (d.success) location.reload();
else alert(d.message);
});
});
});
// Assign to me
var assignBtn = document.getElementById('btn-assign-me');
if (assignBtn) {
assignBtn.addEventListener('click', function() {
var fd = new FormData();
fd.append('ticket_id', ticketId);
fd.append('assigned_to', <?php echo $userId; ?>);
fd.append(token, '1');
fetch('<?php echo Route::_("index.php?option=com_mokosuiteclient&task=display.assignTicket&format=json"); ?>', {
method:'POST', body:fd, headers:{'X-Requested-With':'XMLHttpRequest'}
}).then(function(r){return r.json()}).then(function(d){
if (d.success) location.reload();
else alert(d.message);
});
});
}
});
</script>
@@ -1,83 +0,0 @@
<?php
defined('_JEXEC') or die;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Session\Session;
$tickets = $this->tickets;
$categories = $this->categories;
$isStaff = $this->isStaff;
$token = Session::getFormToken();
$statusLabel = [
'open' => 'Open', 'in_progress' => 'In Progress', 'waiting' => 'Awaiting Response',
'resolved' => 'Resolved', 'closed' => 'Closed',
];
$statusClass = [
'open' => 'primary', 'in_progress' => 'info', 'waiting' => 'warning',
'resolved' => 'success', 'closed' => 'secondary',
];
?>
<div class="mokosuiteclient-portal">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2><?php echo $isStaff ? 'All Support Tickets' : 'My Support Tickets'; ?></h2>
<div class="d-flex gap-2">
<a href="<?php echo Route::_('index.php?option=com_mokosuiteclient&view=tickets&layout=submit'); ?>" class="btn btn-primary">
<span class="icon-plus"></span> New Ticket
</a>
<?php if ($isStaff): ?>
<form method="get" class="d-inline">
<input type="hidden" name="option" value="com_mokosuiteclient">
<input type="hidden" name="view" value="tickets">
<select name="filter_status" class="form-select form-select-sm" style="width:auto" onchange="this.form.submit()">
<option value="">All Statuses</option>
<?php foreach ($statusLabel as $k => $v): ?>
<option value="<?php echo $k; ?>" <?php echo Factory::getApplication()->getInput()->getString('filter_status') === $k ? 'selected' : ''; ?>><?php echo $v; ?></option>
<?php endforeach; ?>
</select>
</form>
<?php endif; ?>
</div>
</div>
<?php if (empty($tickets)): ?>
<div class="alert alert-info">
<span class="icon-info-circle"></span>
<?php echo $isStaff ? 'No tickets found.' : 'You haven\'t submitted any support tickets yet.'; ?>
</div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>#</th>
<th>Subject</th>
<th>Status</th>
<th>Priority</th>
<th>Category</th>
<?php if ($isStaff): ?><th>Submitted By</th><th>Assigned To</th><?php endif; ?>
<th>Date</th>
</tr>
</thead>
<tbody>
<?php foreach ($tickets as $t): ?>
<tr>
<td><a href="<?php echo Route::_('index.php?option=com_mokosuiteclient&view=ticket&id=' . $t->id); ?>"><?php echo $t->id; ?></a></td>
<td><a href="<?php echo Route::_('index.php?option=com_mokosuiteclient&view=ticket&id=' . $t->id); ?>"><?php echo htmlspecialchars(mb_substr($t->subject, 0, 60)); ?></a></td>
<td><span class="badge bg-<?php echo $statusClass[$t->status] ?? 'secondary'; ?>"><?php echo $statusLabel[$t->status] ?? $t->status; ?></span></td>
<td><?php echo ucfirst($t->priority); ?></td>
<td><?php echo htmlspecialchars($t->category_title ?? '—'); ?></td>
<?php if ($isStaff): ?>
<td><?php echo htmlspecialchars($t->created_by_name ?? ''); ?></td>
<td><?php echo htmlspecialchars($t->assigned_to_name ?? '<em>Unassigned</em>'); ?></td>
<?php endif; ?>
<td class="text-nowrap"><?php echo HTMLHelper::_('date', $t->created, 'M d, Y'); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
@@ -1,204 +0,0 @@
<?php
/**
* Submit a Ticket layout — search KB first, then submit form.
*/
defined('_JEXEC') or die;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Session\Session;
$categories = $this->categories;
$token = Session::getFormToken();
$searchUrl = Route::_('index.php?option=com_mokosuiteclient&task=display.searchKb&format=json');
$submitUrl = Route::_('index.php?option=com_mokosuiteclient&task=display.submitTicket&format=json');
$ticketUrl = Route::_('index.php?option=com_mokosuiteclient&view=ticket&id=');
$ticketsUrl = Route::_('index.php?option=com_mokosuiteclient&view=tickets');
// Check if Smart Search has indexed content
$finderEnabled = false;
try {
$db = \Joomla\CMS\Factory::getContainer()->get('Joomla\Database\DatabaseInterface');
$db->setQuery('SELECT COUNT(*) FROM #__finder_links WHERE published = 1');
$finderEnabled = (int) $db->loadResult() > 0;
} catch (\Throwable $e) {}
?>
<div class="mokosuiteclient-portal">
<h2>Submit a Support Request</h2>
<?php if ($finderEnabled): ?>
<!-- Step 1: Search -->
<div id="step-search" class="mb-4">
<p class="text-muted">Before submitting, let's see if we already have an answer for you.</p>
<div class="card">
<div class="card-body">
<label class="form-label fw-bold" for="kb-search">Describe your issue</label>
<div class="input-group input-group-lg">
<input type="text" id="kb-search" class="form-control" placeholder="e.g. how do I reset my password?" autofocus>
<button type="button" class="btn btn-primary" id="kb-search-btn">
<span class="icon-search"></span> Search
</button>
</div>
</div>
</div>
<!-- Search results -->
<div id="kb-results" class="mt-3 d-none">
<h5>Related Articles</h5>
<div id="kb-results-list" class="list-group mb-3"></div>
<p class="text-muted">Didn't find what you need?</p>
</div>
<div class="mt-3">
<button type="button" class="btn btn-outline-primary" id="btn-show-form">
<span class="icon-plus"></span> Submit a Ticket Anyway
</button>
</div>
</div>
<?php endif; ?>
<!-- Step 2: Ticket Form -->
<div id="step-form" class="<?php echo $finderEnabled ? 'd-none' : ''; ?>">
<div class="card">
<div class="card-body">
<h5 class="card-title mb-3">Ticket Details</h5>
<form id="submitTicketForm">
<div class="mb-3">
<label class="form-label" for="ticket-subject">Subject <span class="text-danger">*</span></label>
<input type="text" id="ticket-subject" name="subject" class="form-control" required placeholder="Brief description of your issue">
</div>
<div class="row mb-3">
<div class="col-md-6">
<label class="form-label" for="ticket-category">Category</label>
<select id="ticket-category" name="category_id" class="form-select">
<option value="">Select a category</option>
<?php foreach ($categories as $cat): ?>
<option value="<?php echo $cat->id; ?>"><?php echo htmlspecialchars($cat->title); ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-6">
<label class="form-label" for="ticket-priority">Priority</label>
<select id="ticket-priority" name="priority" class="form-select">
<option value="normal">Normal</option>
<option value="low">Low</option>
<option value="high">High</option>
<option value="urgent">Urgent</option>
</select>
</div>
</div>
<div class="mb-3">
<label class="form-label" for="ticket-body">Description <span class="text-danger">*</span></label>
<textarea id="ticket-body" name="body" class="form-control" rows="8" required placeholder="Please describe your issue in detail."></textarea>
</div>
<input type="hidden" name="<?php echo $token; ?>" value="1">
<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary btn-lg">
<span class="icon-paper-plane"></span> Submit Ticket
</button>
<a href="<?php echo $ticketsUrl; ?>" class="btn btn-outline-secondary btn-lg">
My Tickets
</a>
</div>
</form>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
var searchInput = document.getElementById('kb-search');
var searchBtn = document.getElementById('kb-search-btn');
var resultBox = document.getElementById('kb-results');
var resultList = document.getElementById('kb-results-list');
var showFormBtn = document.getElementById('btn-show-form');
var stepSearch = document.getElementById('step-search');
var stepForm = document.getElementById('step-form');
var subjectField = document.getElementById('ticket-subject');
// Search
function doSearch() {
var q = (searchInput ? searchInput.value.trim() : '');
if (q.length < 3) return;
fetch('<?php echo $searchUrl; ?>&q=' + encodeURIComponent(q), {
headers: {'X-Requested-With': 'XMLHttpRequest'}
})
.then(function(r) { return r.json(); })
.then(function(d) {
resultList.textContent = '';
if (d.results && d.results.length > 0) {
d.results.forEach(function(item) {
var a = document.createElement('a');
a.href = item.url;
a.target = '_blank';
a.className = 'list-group-item list-group-item-action';
var strong = document.createElement('strong');
strong.textContent = item.title;
a.appendChild(strong);
if (item.description) {
a.appendChild(document.createElement('br'));
var small = document.createElement('small');
small.className = 'text-muted';
small.textContent = item.description;
a.appendChild(small);
}
resultList.appendChild(a);
});
resultBox.classList.remove('d-none');
} else {
resultBox.classList.add('d-none');
}
// Always show the "submit anyway" button after search
if (showFormBtn) showFormBtn.classList.remove('d-none');
});
}
if (searchBtn) searchBtn.addEventListener('click', doSearch);
if (searchInput) {
searchInput.addEventListener('keydown', function(e) {
if (e.key === 'Enter') { e.preventDefault(); doSearch(); }
});
}
// Show form and prefill subject from search query
if (showFormBtn) {
showFormBtn.addEventListener('click', function() {
if (stepSearch) stepSearch.classList.add('d-none');
if (stepForm) stepForm.classList.remove('d-none');
if (searchInput && subjectField && !subjectField.value) {
subjectField.value = searchInput.value;
}
subjectField.focus();
});
}
// Submit ticket
var form = document.getElementById('submitTicketForm');
if (form) {
form.addEventListener('submit', function(e) {
e.preventDefault();
var btn = form.querySelector('button[type=submit]');
btn.disabled = true;
btn.textContent = ' Submitting...';
var fd = new FormData(form);
fetch('<?php echo $submitUrl; ?>', {
method: 'POST', body: fd, headers: {'X-Requested-With': 'XMLHttpRequest'}
})
.then(function(r) { return r.json(); })
.then(function(d) {
if (d.success && d.id) {
window.location.href = '<?php echo $ticketUrl; ?>' + d.id;
} else {
alert(d.message || 'Failed.');
btn.disabled = false;
btn.textContent = ' Submit Ticket';
}
})
.catch(function() { alert('Network error.'); btn.disabled = false; });
});
}
});
</script>
@@ -7,9 +7,9 @@
<license>GPL-3.0-or-later</license>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
<authorUrl>https://mokoconsulting.tech</authorUrl>
<version>02.34.84-dev</version>
<description>MOD_MOKOSUITE_CACHE_DESC</description>
<namespace path="src">Moko\Module\MokoSuiteCache</namespace>
<version>02.48.24</version>
<description>MOD_MOKOSUITECLIENT_CACHE_DESC</description>
<namespace path="src">Moko\Module\MokoSuiteClientCache</namespace>
<files>
<folder module="mod_mokosuiteclient_cache">services</folder>
@@ -4,11 +4,23 @@ namespace Moko\Module\MokoSuiteClientCache\Administrator\Dispatcher;
defined('_JEXEC') or die;
use Joomla\CMS\Dispatcher\AbstractModuleDispatcher;
use Joomla\CMS\Factory;
use Joomla\CMS\Uri\Uri;
use Joomla\Database\DatabaseInterface;
class Dispatcher extends AbstractModuleDispatcher
{
protected function getLayoutData()
{
return parent::getLayoutData();
$data = parent::getLayoutData();
$db = Factory::getContainer()->get(DatabaseInterface::class);
$pinState = \Moko\Component\MokoSuiteClient\Administrator\Helper\SupportPinHelper::getState($db);
$data['supportPinAvailable'] = $pinState['available'];
$data['supportPin'] = $pinState['pin'];
$data['frontendUrl'] = rtrim(Uri::root(), '/');
return $data;
}
}
@@ -2,36 +2,45 @@
/**
* MokoSuiteClient Cache & Temp Cleaner — status bar split button
*
* Displays "Clear: Cache | Temp" as a single header item with two
* clickable halves. Uses native Atum header-item markup.
* 4 buttons: Frontend link | Support PIN | Clear Cache | Clear Temp
*/
defined('_JEXEC') or die;
use Joomla\CMS\Session\Session;
$token = Session::getFormToken();
$cacheUrl = 'index.php?option=com_mokosuiteclient&task=clearCache&format=json';
$tempUrl = 'index.php?option=com_mokosuiteclient&task=clearTemp&format=json';
$token = Session::getFormToken();
$cacheUrl = 'index.php?option=com_mokosuiteclient&task=display.clearCache&format=json';
$tempUrl = 'index.php?option=com_mokosuiteclient&task=display.clearTemp&format=json';
$pinAvailable = $supportPinAvailable ?? false;
$pin = $supportPin ?? '';
$frontendUrl = $frontendUrl ?? '';
?>
<style>
.mokosuiteclient-cleaner { display:flex; align-items:center; gap:0; padding:0 0.25rem; }
.mokosuiteclient-cleaner-label { font-size:0.8rem; color:var(--template-text-dark,#495057); white-space:nowrap; padding-inline-end:0.35rem; }
.mokosuiteclient-cleaner-btn { cursor:pointer; padding:0.2rem 0.5rem; font-size:0.8rem; border-radius:3px; text-decoration:none; color:var(--template-text-dark,#495057); transition:background 0.15s; white-space:nowrap; }
.mokosuiteclient-cleaner-btn:hover { background:rgba(0,0,0,0.08); color:var(--template-text-dark,#212529); text-decoration:none; }
.mokosuiteclient-cleaner-sep { color:var(--template-text-dark,#adb5bd); padding:0 0.1rem; font-size:0.8rem; }
</style>
<div class="header-item-content mokosuiteclient-cleaner">
<span class="mokosuiteclient-cleaner-label">Clear:</span>
<a href="#" class="mokosuiteclient-cleaner-btn" id="mokosuiteclient-clear-cache" title="Clear all Joomla cache">
<span class="icon-bolt" aria-hidden="true" id="mokosuiteclient-cache-icon"></span> Cache
</a>
<span class="mokosuiteclient-cleaner-sep">|</span>
<a href="#" class="mokosuiteclient-cleaner-btn" id="mokosuiteclient-clear-temp" title="Clear temp directory">
<span class="icon-trash" aria-hidden="true" id="mokosuiteclient-temp-icon"></span> Temp
</a>
<div class="header-item">
<div class="header-item-content d-flex align-items-center gap-0" style="padding:0;">
<?php if ($frontendUrl): ?>
<a href="<?php echo htmlspecialchars($frontendUrl); ?>" target="_blank" rel="noopener" class="btn btn-sm btn-outline-success rounded-0 rounded-start border-end-0 d-flex align-items-center gap-1 px-3 py-2" title="Open frontend" style="font-size:0.8rem;">
<span class="icon-external-link-alt" aria-hidden="true"></span> Site
</a>
<?php endif; ?>
<?php if ($pinAvailable):
$pinHtml = \Moko\Component\MokoSuiteClient\Administrator\Helper\SupportPinHelper::renderBadge(
['available' => true, 'pin' => $pin],
$token, 'cache'
);
if (!$frontendUrl) {
$pinHtml = str_replace('rounded-0 border-end-0', 'rounded-0 rounded-start border-end-0', $pinHtml);
}
echo $pinHtml;
endif; ?>
<a href="#" class="btn btn-sm btn-outline-primary <?php echo ($pinAvailable || $frontendUrl) ? 'rounded-0 border-end-0' : 'rounded-0 rounded-start border-end-0'; ?> d-flex align-items-center gap-1 px-3 py-2" id="mokosuiteclient-clear-cache" title="Clear all Joomla cache" style="font-size:0.8rem;">
<span class="icon-bolt" aria-hidden="true" id="mokosuiteclient-cache-icon"></span> Cache
</a>
<a href="#" class="btn btn-sm btn-outline-danger rounded-0 rounded-end d-flex align-items-center gap-1 px-3 py-2" id="mokosuiteclient-clear-temp" title="Clear temp directory" style="font-size:0.8rem;">
<span class="icon-trash" aria-hidden="true" id="mokosuiteclient-temp-icon"></span> Temp
</a>
</div>
</div>
<script>
@@ -85,5 +94,7 @@ document.addEventListener('DOMContentLoaded', function() {
setupCleaner('mokosuiteclient-clear-cache', 'mokosuiteclient-cache-icon', '<?php echo $cacheUrl; ?>', '<?php echo $token; ?>');
setupCleaner('mokosuiteclient-clear-temp', 'mokosuiteclient-temp-icon', '<?php echo $tempUrl; ?>', '<?php echo $token; ?>');
});
</script>
<?php echo \Moko\Component\MokoSuiteClient\Administrator\Helper\SupportPinHelper::renderScript(); ?>
@@ -7,7 +7,7 @@
<license>GPL-3.0-or-later</license>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
<authorUrl>https://mokoconsulting.tech</authorUrl>
<version>02.34.84-dev</version>
<version>02.48.24</version>
<description>MOD_MOKOSUITECLIENT_CATEGORIES_DESC</description>
<namespace path="src">Moko\Module\MokoSuiteClientCategories</namespace>
@@ -7,9 +7,9 @@
<license>GPL-3.0-or-later</license>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
<authorUrl>https://mokoconsulting.tech</authorUrl>
<version>02.34.84-dev</version>
<description>MOD_MOKOSUITE_CPANEL_DESC</description>
<namespace path="src">Moko\Module\MokoSuiteCpanel</namespace>
<version>02.48.24</version>
<description>MOD_MOKOSUITECLIENT_CPANEL_DESC</description>
<namespace path="src">Moko\Module\MokoSuiteClientCpanel</namespace>
<files>
<folder module="mod_mokosuiteclient_cpanel">services</folder>
@@ -25,64 +25,56 @@
<config>
<fields name="params">
<fieldset name="basic"
label="MOD_MOKOSUITE_CPANEL_FIELDSET_DISPLAY"
description="MOD_MOKOSUITE_CPANEL_FIELDSET_DISPLAY_DESC">
<field name="collapsed" type="radio" default="1"
label="MOD_MOKOSUITE_CPANEL_COLLAPSED_LABEL"
description="MOD_MOKOSUITE_CPANEL_COLLAPSED_DESC"
layout="joomla.form.field.radio.switcher">
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
label="MOD_MOKOSUITECLIENT_CPANEL_FIELDSET_DISPLAY"
description="MOD_MOKOSUITECLIENT_CPANEL_FIELDSET_DISPLAY_DESC">
<field name="show_health" type="radio" default="1"
label="MOD_MOKOSUITE_CPANEL_SHOW_HEALTH_LABEL"
label="MOD_MOKOSUITECLIENT_CPANEL_SHOW_HEALTH_LABEL"
layout="joomla.form.field.radio.switcher">
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
</field>
<field name="show_stats" type="radio" default="1"
label="MOD_MOKOSUITE_CPANEL_SHOW_STATS_LABEL"
description="MOD_MOKOSUITE_CPANEL_SHOW_STATS_DESC"
label="MOD_MOKOSUITECLIENT_CPANEL_SHOW_STATS_LABEL"
description="MOD_MOKOSUITECLIENT_CPANEL_SHOW_STATS_DESC"
layout="joomla.form.field.radio.switcher">
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
</field>
<field name="show_disk" type="radio" default="1"
label="MOD_MOKOSUITE_CPANEL_SHOW_DISK_LABEL"
label="MOD_MOKOSUITECLIENT_CPANEL_SHOW_DISK_LABEL"
layout="joomla.form.field.radio.switcher">
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
</field>
<field name="show_ip" type="radio" default="1"
label="MOD_MOKOSUITE_CPANEL_SHOW_IP_LABEL"
label="MOD_MOKOSUITECLIENT_CPANEL_SHOW_IP_LABEL"
layout="joomla.form.field.radio.switcher">
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
</field>
<field name="show_plugins" type="radio" default="1"
label="MOD_MOKOSUITE_CPANEL_SHOW_PLUGINS_LABEL"
label="MOD_MOKOSUITECLIENT_CPANEL_SHOW_PLUGINS_LABEL"
layout="joomla.form.field.radio.switcher">
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
</field>
<field name="show_actions" type="radio" default="1"
label="MOD_MOKOSUITE_CPANEL_SHOW_ACTIONS_LABEL"
description="MOD_MOKOSUITE_CPANEL_SHOW_ACTIONS_DESC"
label="MOD_MOKOSUITECLIENT_CPANEL_SHOW_ACTIONS_LABEL"
description="MOD_MOKOSUITECLIENT_CPANEL_SHOW_ACTIONS_DESC"
layout="joomla.form.field.radio.switcher">
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
</field>
<field name="show_versions" type="radio" default="1"
label="MOD_MOKOSUITE_CPANEL_SHOW_VERSIONS_LABEL"
description="MOD_MOKOSUITE_CPANEL_SHOW_VERSIONS_DESC"
label="MOD_MOKOSUITECLIENT_CPANEL_SHOW_VERSIONS_LABEL"
description="MOD_MOKOSUITECLIENT_CPANEL_SHOW_VERSIONS_DESC"
layout="joomla.form.field.radio.switcher">
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
@@ -47,28 +47,10 @@ class Dispatcher extends AbstractModuleDispatcher implements HelperFactoryAwareI
$data['currentIp'] = $helper->getCurrentIp();
$data['ssl'] = $helper->getSslStatus();
// Support PIN derived from health token
$data['supportPin'] = '';
try
{
$db->setQuery(
$db->getQuery(true)
->select($db->quoteName('params'))
->from($db->quoteName('#__extensions'))
->where($db->quoteName('element') . ' = ' . $db->quote('mokosuiteclient'))
->where($db->quoteName('type') . ' = ' . $db->quote('plugin'))
->where($db->quoteName('folder') . ' = ' . $db->quote('system'))
);
$coreParams = json_decode((string) $db->loadResult());
$token = $coreParams->health_api_token ?? '';
if (!empty($token))
{
$data['supportPin'] = 'MOKO-' . strtoupper(substr($token, 0, 4) . '-' . substr($token, 4, 4));
}
}
catch (\Throwable $e) {}
// Support PIN via shared helper
$pinState = \Moko\Component\MokoSuiteClient\Administrator\Helper\SupportPinHelper::getState($db);
$data['supportPinAvailable'] = $pinState['available'];
$data['supportPin'] = $pinState['pin'];
return $data;
}
@@ -32,9 +32,11 @@ class CpanelHelper
$pkgCache = json_decode($db->loadResult() ?? '{}');
return (object) [
'sitename' => $config->get('sitename', ''),
'mokosuiteclient_version' => $pkgCache->version ?? '',
'joomla_version' => (new Version())->getShortVersion(),
'php_version' => PHP_VERSION,
'db_type' => $config->get('dbtype', 'mysql'),
'debug' => (bool) $config->get('debug'),
'offline' => (bool) $config->get('offline'),
];
@@ -8,6 +8,7 @@
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Session\Session;
@@ -22,7 +23,7 @@ $healthOk = $healthOk ?? true;
$counts = $counts ?? (object) ['articles' => 0, 'users' => 0, 'extensions' => 0, 'updates' => 0];
$disk = $disk ?? (object) ['free_mb' => null, 'total_mb' => null];
$currentIp = $currentIp ?? '';
$collapsed = $params->get('collapsed', 0);
$collapsed = true;
$showHealth = $params->get('show_health', 1);
$showStats = $params->get('show_stats', 1);
$showDisk = $params->get('show_disk', 1);
@@ -44,11 +45,13 @@ foreach ($plugins as $p)
}
$labels = [
'mokosuiteclient' => 'Core',
'mokosuiteclient_firewall' => 'Firewall',
'mokosuiteclient_tenant' => 'Tenant',
'mokosuiteclient_devtools' => 'DevTools',
'mokosuiteclient_monitor' => 'Monitor',
'mokosuiteclient' => 'Core Engine',
'mokosuiteclient_firewall' => 'Web Firewall',
'mokosuiteclient_tenant' => 'Tenant Guard',
'mokosuiteclient_devtools' => 'Dev Tools',
'mokosuiteclient_offline' => 'Offline Bypass',
'mokosuiteclient_dbip' => 'GeoIP Lookup',
'mokosuiteclient_license' => 'License Manager',
];
$diskPct = ($disk->total_mb && $disk->total_mb > 0)
@@ -58,176 +61,32 @@ $diskColor = ($diskPct !== null && $diskPct > 90) ? 'bg-danger' : (($diskPct !==
?>
<div class="mod-mokosuiteclient-cpanel card p-3 mb-4">
<!-- Header row -->
<div class="d-flex align-items-center gap-2">
<button type="button" class="btn btn-sm btn-link p-0 text-muted" data-bs-toggle="collapse" data-bs-target="#mokosuiteclient-cpanel-body" aria-expanded="<?php echo $collapsed ? 'false' : 'true'; ?>" aria-controls="mokosuiteclient-cpanel-body" id="mokosuiteclient-cpanel-toggle" style="font-size:1rem;line-height:1;width:1.5rem;">
<span class="fa-solid fa-caret-<?php echo $collapsed ? 'right' : 'down'; ?>" aria-hidden="true" id="mokosuiteclient-cpanel-caret"></span>
</button>
<span class="icon-shield-alt" aria-hidden="true" style="font-size:1.25rem;color:#1a2744"></span>
<strong>MokoSuiteClient</strong>
<span class="badge bg-primary"><?php echo htmlspecialchars($siteInfo->mokosuiteclient_version ?? ''); ?></span>
<?php if (!empty($supportPin)): ?>
<span class="badge bg-dark" style="font-family:monospace;letter-spacing:0.08em;" title="Support PIN"><?php echo htmlspecialchars($supportPin); ?></span>
<div class="d-flex flex-wrap align-items-center gap-2" style="font-size:0.85rem;">
<?php $canDashboard = Factory::getApplication()->getIdentity()->authorise('core.manage', 'com_mokosuiteclient'); ?>
<?php if ($canDashboard): ?>
<a href="<?php echo Route::_('index.php?option=com_mokosuiteclient'); ?>" style="color:#1a2744;text-decoration:none;" title="MokoSuite Dashboard"><span class="icon-shield-alt" aria-hidden="true" style="font-size:1.1rem"></span></a>
<?php else: ?>
<span class="icon-shield-alt" aria-hidden="true" style="font-size:1.1rem;color:#1a2744"></span>
<?php endif; ?>
<span class="fw-bold"><?php echo htmlspecialchars($siteInfo->sitename ?? ''); ?></span>
<span class="badge bg-primary">MokoSuite <?php echo htmlspecialchars($siteInfo->mokosuiteclient_version ?? ''); ?></span>
<?php echo \Moko\Component\MokoSuiteClient\Administrator\Helper\SupportPinHelper::renderBadge(
['available' => !empty($supportPinAvailable), 'pin' => $supportPin ?? ''],
$token, 'cpanel'
); ?>
<span class="badge bg-secondary">Joomla <?php echo htmlspecialchars($siteInfo->joomla_version ?? ''); ?></span>
<span class="badge bg-secondary">PHP <?php echo htmlspecialchars($siteInfo->php_version ?? ''); ?></span>
<span class="badge bg-secondary"><?php echo htmlspecialchars($siteInfo->db_type ?? ''); ?></span>
<?php if (!empty($siteInfo->debug)): ?>
<span class="badge bg-warning text-dark">Debug</span>
<span class="badge bg-warning text-dark">Debug ON</span>
<?php endif; ?>
<?php if (!empty($siteInfo->offline)): ?>
<span class="badge bg-danger">Offline</span>
<?php endif; ?>
<?php if (($counts->moko_updates ?? 0) > 0): ?>
<a href="<?php echo Route::_('index.php?option=com_installer&view=update'); ?>" class="badge bg-info text-decoration-none" title="MokoSuiteClient updates available">
<span class="icon-upload" aria-hidden="true"></span> <?php echo $counts->moko_updates; ?> MokoSuiteClient update<?php echo $counts->moko_updates > 1 ? 's' : ''; ?>
</a>
<?php endif; ?>
<?php if ($counts->updates > 0 && $counts->updates !== ($counts->moko_updates ?? 0)): ?>
<a href="<?php echo Route::_('index.php?option=com_installer&view=update'); ?>" class="badge bg-warning text-dark text-decoration-none" title="Other updates available">
<span class="icon-upload" aria-hidden="true"></span> <?php echo $counts->updates - ($counts->moko_updates ?? 0); ?> update<?php echo ($counts->updates - ($counts->moko_updates ?? 0)) > 1 ? 's' : ''; ?>
</a>
<?php endif; ?>
<span class="ms-auto">
<a href="<?php echo Route::_('index.php?option=com_mokosuiteclient'); ?>" class="btn btn-sm btn-primary">
<span class="icon-cogs" aria-hidden="true"></span>
<?php echo Text::_('MOD_MOKOSUITECLIENT_CPANEL_OPEN_DASHBOARD'); ?>
</a>
<span class="ms-auto d-flex align-items-center gap-2">
<span class="icon-globe" aria-hidden="true"></span>
<code><?php echo htmlspecialchars($currentIp); ?></code>
</span>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
var target = document.getElementById('mokosuiteclient-cpanel-body');
var caret = document.getElementById('mokosuiteclient-cpanel-caret');
if (target && caret) {
target.addEventListener('show.bs.collapse', function() { caret.className = 'fa-solid fa-caret-down'; });
target.addEventListener('hide.bs.collapse', function() { caret.className = 'fa-solid fa-caret-right'; });
}
});
</script>
<!-- Collapsible body -->
<div class="collapse<?php echo $collapsed ? '' : ' show'; ?> mt-3" id="mokosuiteclient-cpanel-body">
<?php if ($showHealth && $showStats): ?>
<!-- Health + stats row -->
<div class="row g-2 mb-3">
<div class="col-6 col-md-3">
<div class="border rounded p-2 text-center h-100">
<?php if ($healthOk): ?>
<span class="icon-check-circle text-success d-block" style="font-size:1.5rem"></span>
<small class="text-success fw-bold">Healthy</small>
<?php else: ?>
<span class="icon-exclamation-circle text-danger d-block" style="font-size:1.5rem"></span>
<small class="text-danger fw-bold">DB Error</small>
<?php endif; ?>
</div>
</div>
<div class="col-6 col-md-3">
<div class="border rounded p-2 text-center h-100">
<span class="fw-bold d-block" style="font-size:1.25rem"><?php echo $counts->articles; ?></span>
<small class="text-muted">Articles</small>
</div>
</div>
<div class="col-6 col-md-3">
<div class="border rounded p-2 text-center h-100">
<span class="fw-bold d-block" style="font-size:1.25rem"><?php echo $counts->users; ?></span>
<small class="text-muted">Users</small>
</div>
</div>
<div class="col-6 col-md-3">
<div class="border rounded p-2 text-center h-100">
<?php if ($counts->updates > 0): ?>
<span class="fw-bold d-block text-warning" style="font-size:1.25rem"><?php echo $counts->updates; ?></span>
<small class="text-warning">Updates</small>
<?php else: ?>
<span class="icon-check d-block text-success" style="font-size:1.25rem"></span>
<small class="text-muted">Up to date</small>
<?php endif; ?>
</div>
</div>
</div>
<!-- Info + plugins + actions (consolidated) -->
<div class="d-flex flex-wrap align-items-center gap-2">
<?php if ($showDisk && $diskPct !== null): ?>
<span class="text-muted d-inline-flex align-items-center gap-1">
<span class="icon-hdd" aria-hidden="true"></span>
<?php echo $diskPct; ?>%
<span class="progress d-inline-flex" style="width:40px;height:5px"><span class="progress-bar <?php echo $diskColor; ?>" style="width:<?php echo $diskPct; ?>%"></span></span>
<?php echo number_format(($disk->free_mb ?? 0) / 1024, 1); ?>G free
</span>
<?php endif; ?>
<?php if ($showIp && $currentIp): ?>
<span class="text-muted"><span class="icon-globe" aria-hidden="true"></span> <code><?php echo htmlspecialchars($currentIp); ?></code></span>
<?php endif; ?>
<?php $ssl = $ssl ?? null; if ($ssl): ?>
<span class="badge bg-<?php echo $ssl->critical ? 'danger' : ($ssl->warning ? 'warning text-dark' : 'success'); ?>" title="SSL expires <?php echo $ssl->expires; ?>">
<span class="icon-lock" aria-hidden="true"></span>
SSL <?php echo $ssl->days_remaining; ?>d
</span>
<?php endif; ?>
<?php if ($showVersions): ?>
<span class="text-muted">J<?php echo htmlspecialchars($siteInfo->joomla_version ?? ''); ?> / PHP <?php echo htmlspecialchars($siteInfo->php_version ?? ''); ?></span>
<?php endif; ?>
<?php if ($showPlugins && !empty($plugins)): ?>
<span class="border-start ps-2 ms-1"></span>
<?php foreach ($plugins as $p): ?>
<?php
$label = $labels[$p->element] ?? $p->element;
$badge = $p->enabled ? 'bg-success' : 'bg-secondary';
$icon = $p->enabled ? 'icon-check' : 'icon-times';
$configUrl = Route::_('index.php?option=com_plugins&task=plugin.edit&extension_id=' . (int) $p->extension_id);
?>
<a href="<?php echo $configUrl; ?>" class="badge <?php echo $badge; ?> text-decoration-none" title="<?php echo htmlspecialchars($p->name); ?>">
<span class="<?php echo $icon; ?>" aria-hidden="true"></span> <?php echo htmlspecialchars($label); ?>
</a>
<?php endforeach; ?>
<?php endif; ?>
<?php if ($showActions): ?>
<span class="border-start ps-2 ms-1"></span>
<button type="button" class="btn btn-sm btn-outline-secondary" id="mokosuiteclient-cpanel-cache"
data-url="<?php echo Route::_('index.php?option=com_mokosuiteclient&task=display.clearCache&format=json'); ?>"
data-token="<?php echo $token; ?>">
<span class="icon-trash" aria-hidden="true"></span> Clear Cache
</button>
<a href="<?php echo Route::_('index.php?option=com_installer&view=update'); ?>" class="btn btn-sm btn-outline-secondary">
<span class="icon-refresh" aria-hidden="true"></span> Check Updates
</a>
<?php if ($counts->updates > 0): ?>
<a href="<?php echo Route::_('index.php?option=com_installer&view=update'); ?>" class="badge bg-warning text-dark text-decoration-none">
<span class="icon-upload" aria-hidden="true"></span> <?php echo $counts->updates; ?> update<?php echo $counts->updates > 1 ? 's' : ''; ?>
</a>
<?php endif; ?>
<?php endif; ?>
</div>
<?php endif; ?>
</div><!-- /.collapse -->
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
var btn = document.getElementById('mokosuiteclient-cpanel-cache');
if (!btn) return;
btn.addEventListener('click', function() {
var el = this;
var url = el.dataset.url;
var token = el.dataset.token;
el.disabled = true;
var icon = el.querySelector('span');
var origClass = icon ? icon.className : '';
if (icon) icon.className = 'icon-spinner icon-spin';
var fd = new FormData();
fd.append(token, '1');
fetch(url, {method:'POST', body:fd, headers:{'X-Requested-With':'XMLHttpRequest'}})
.then(function(r){return r.json()})
.then(function(d){
if (d.success) Joomla.renderMessages({message:['Cache cleared.']});
else Joomla.renderMessages({error:[d.message||'Failed']});
})
.catch(function(){Joomla.renderMessages({error:['Network error']})})
.finally(function(){
el.disabled = false;
if (icon) icon.className = origClass;
});
});
});
</script>
<?php echo \Moko\Component\MokoSuiteClient\Administrator\Helper\SupportPinHelper::renderScript(); ?>
@@ -7,7 +7,7 @@
<license>GPL-3.0-or-later</license>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
<authorUrl>https://mokoconsulting.tech</authorUrl>
<version>02.34.84-dev</version>
<version>02.48.24</version>
<description>MokoSuiteClient admin sidebar menu — renders a dedicated MokoSuiteClient section in the admin menu before Joomla's default menu.</description>
<namespace path="src">Moko\Module\MokoSuiteClientMenu</namespace>
@@ -3,7 +3,7 @@
* MokoSuiteClient Admin Sidebar Menu
*
* Each installed Moko component gets its own top-level collapsible section.
* com_mokosuiteclienthq is always pinned first. com_mokosuiteclient uses static views
* com_mokosuitehq is always pinned first. com_mokosuiteclient uses static views
* as children. All other components auto-discover their submenu items.
*/
@@ -17,18 +17,26 @@ $app = Factory::getApplication();
$currentOption = $app->getInput()->get('option', '');
$currentView = $app->getInput()->get('view', '');
// ── Static views for com_mokosuiteclient ──────────────────────────────────
$mokosuiteclientStaticViews = [
['icon' => 'icon-cogs', 'title' => 'Dashboard', 'link' => 'index.php?option=com_mokosuiteclient'],
['icon' => 'fa-solid fa-handshake-angle', 'title' => 'Helpdesk', 'link' => 'index.php?option=com_mokosuiteclient&view=tickets'],
['icon' => 'icon-puzzle-piece', 'title' => 'Extensions', 'link' => 'index.php?option=com_mokosuiteclient&view=extensions'],
['icon' => 'fa-solid fa-file-code', 'title' => '.htaccess Maker', 'link' => 'index.php?option=com_mokosuiteclient&view=htaccess'],
['icon' => 'icon-lock', 'title' => 'Privacy Guard', 'link' => 'index.php?option=com_mokosuiteclient&view=privacy'],
['icon' => 'icon-shield-alt', 'title' => 'WAF Log', 'link' => 'index.php?option=com_mokosuiteclient&view=waflog'],
['icon' => 'icon-database', 'title' => 'Database Tools', 'link' => 'index.php?option=com_mokosuiteclient&view=database'],
['icon' => 'icon-trash', 'title' => 'Cache Cleanup', 'link' => 'index.php?option=com_mokosuiteclient&view=cleanup'],
['icon' => 'icon-power-off', 'title' => 'Feature Plugins', 'link' => 'index.php?option=com_plugins&filter[folder]=system&filter[search]=mokosuiteclient'],
// ── Static views for com_mokosuiteclient (ACL-gated) ──────────────────────
$user = $app->getIdentity();
$allViews = [
['icon' => 'icon-cogs', 'title' => 'Dashboard', 'link' => 'index.php?option=com_mokosuiteclient', 'acl' => 'mokosuiteclient.dashboard'],
['icon' => 'icon-puzzle-piece', 'title' => 'Extensions', 'link' => 'index.php?option=com_mokosuiteclient&view=extensions', 'acl' => 'mokosuiteclient.extensions'],
['icon' => 'fa-solid fa-file-code', 'title' => '.htaccess Maker', 'link' => 'index.php?option=com_mokosuiteclient&view=htaccess', 'acl' => 'mokosuiteclient.htaccess'],
['icon' => 'icon-shield-alt', 'title' => 'WAF Log', 'link' => 'index.php?option=com_mokosuiteclient&view=waflog', 'acl' => 'mokosuiteclient.security.waflog'],
['icon' => 'icon-lock', 'title' => 'Privacy Guard', 'link' => 'index.php?option=com_mokosuiteclient&view=privacy', 'acl' => 'core.admin'],
['icon' => 'fa-solid fa-code', 'title' => 'Snippets', 'link' => 'index.php?option=com_mokosuiteclient&view=snippets', 'acl' => 'mokosuiteclient.snippets.manage'],
['icon' => 'fa-solid fa-file-lines', 'title' => 'Templates', 'link' => 'index.php?option=com_mokosuiteclient&view=templates', 'acl' => 'mokosuiteclient.templates.manage'],
['icon' => 'fa-solid fa-right-left', 'title' => 'Replacements', 'link' => 'index.php?option=com_mokosuiteclient&view=replacements','acl' => 'mokosuiteclient.replacements.manage'],
['icon' => 'fa-solid fa-shuffle', 'title' => 'Conditions', 'link' => 'index.php?option=com_mokosuiteclient&view=conditions', 'acl' => 'mokosuiteclient.conditions.manage'],
['icon' => 'icon-database', 'title' => 'Database Tools', 'link' => 'index.php?option=com_mokosuiteclient&view=database', 'acl' => 'core.admin'],
['icon' => 'icon-trash', 'title' => 'Cache Cleanup', 'link' => 'index.php?option=com_mokosuiteclient&view=cleanup', 'acl' => 'mokosuiteclient.cache'],
['icon' => 'icon-power-off', 'title' => 'Feature Plugins', 'link' => 'index.php?option=com_plugins&filter[folder]=system&filter[search]=mokosuiteclient', 'acl' => 'core.admin'],
];
$isSuper = $user->authorise('core.admin', 'com_mokosuiteclient');
$mokosuiteclientStaticViews = array_filter($allViews, function ($v) use ($user, $isSuper) {
return $isSuper || $user->authorise($v['acl'], 'com_mokosuiteclient');
});
// ── Auto-discover all Moko components from #__menu ──────────────────
$mokoComponents = [];
@@ -57,6 +65,15 @@ try
{
$lang->load($m->element . '.sys', JPATH_ADMINISTRATOR);
$lang->load($m->element, JPATH_ADMINISTRATOR);
// Also try component-local language path (Joomla 5/6 pattern)
$compLangPath = JPATH_ADMINISTRATOR . '/components/' . $m->element;
if (is_dir($compLangPath . '/language'))
{
$lang->load($m->element . '.sys', $compLangPath);
$lang->load($m->element, $compLangPath);
}
$loadedLangs[$m->element] = true;
}
}
@@ -101,7 +118,7 @@ else
// com_mokosuiteclient not in admin menu — add it manually
$mokoComponents['com_mokosuiteclient'] = [
'id' => 0,
'title' => 'MokoSuiteClient',
'title' => 'MokoSuite',
'link' => 'index.php?option=com_mokosuiteclient',
'icon' => 'icon-shield-alt',
'element' => 'com_mokosuiteclient',
@@ -109,16 +126,37 @@ else
];
}
// ── Sort: com_mokosuiteclienthq first, then alphabetical by title ─────────
// ── Sort: HQ first, Client second, then alphabetical ─────────
$hq = null;
$client = null;
$rest = [];
foreach ($mokoComponents as $key => $comp)
{
if ($key === 'com_mokosuiteclienthq')
// Shorten display titles:
// MokoSuiteClient → MokoSuite, MokoSuiteHQ → MokoHQ
// Everything else: MokoSuiteBackup → Backup, MokoSuiteOpenGraph → OpenGraph
if ($key === 'com_mokosuiteclient')
{
$comp['title'] = 'MokoSuite';
}
elseif ($key === 'com_mokosuitehq')
{
$comp['title'] = preg_replace('/^MokoSuite/i', 'Moko', $comp['title']);
}
else
{
$comp['title'] = preg_replace('/^MokoSuite\s*/i', '', $comp['title']);
}
if ($key === 'com_mokosuitehq')
{
$hq = $comp;
}
elseif ($key === 'com_mokosuiteclient')
{
$client = $comp;
}
else
{
$rest[$key] = $comp;
@@ -132,6 +170,10 @@ if ($hq !== null)
{
$sorted[] = $hq;
}
if ($client !== null)
{
$sorted[] = $client;
}
foreach ($rest as $comp)
{
$sorted[] = $comp;
@@ -139,8 +181,7 @@ foreach ($rest as $comp)
?>
<style>
.sidebar-wrapper .mokosuiteclient-ext-item > a { padding-inline-start: 1.5rem; }
.sidebar-wrapper .mokosuiteclient-ext-child > a { padding-inline-start: 2.5rem; }
.sidebar-wrapper { padding-right: 0.5rem; }
</style>
<ul class="nav flex-column main-nav">
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,67 @@
<?php
/**
* @package MokoSuiteClient
* @subpackage plg_system_mokosuiteclient
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
* @license GNU General Public License version 3 or later; see LICENSE
*
* FILE INFORMATION
* DEFGROUP: Joomla.Plugin
* INGROUP: MokoSuiteClient
* VERSION: 02.48.24
* PATH: /src/Field/ArticlesField.php
* BRIEF: List field that populates with published Joomla articles
*/
namespace Moko\Plugin\System\MokoSuiteClient\Field;
defined('_JEXEC') or die;
use Joomla\CMS\Form\Field\ListField;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Factory;
use Joomla\Database\DatabaseInterface;
/**
* Form field that renders a dropdown (or multi-select) of all published
* articles, grouped by category name.
*
* Usage in XML:
* <field name="related_article" type="Articles" label="Related Article" multiple="true" />
*
* @since 02.47.62
*/
class ArticlesField extends ListField
{
protected $type = 'Articles';
protected function getOptions(): array
{
$options = parent::getOptions();
$db = Factory::getContainer()->get(DatabaseInterface::class);
$query = $db->getQuery(true)
->select([
$db->quoteName('a.id', 'value'),
$db->quoteName('a.title', 'text'),
$db->quoteName('c.title', 'category'),
])
->from($db->quoteName('#__content', 'a'))
->leftJoin($db->quoteName('#__categories', 'c') . ' ON c.id = a.catid')
->where($db->quoteName('a.state') . ' = 1')
->order($db->quoteName('a.title') . ' ASC');
$db->setQuery($query);
$articles = $db->loadObjectList() ?: [];
foreach ($articles as $article) {
$label = $article->text;
if (!empty($article->category)) {
$label .= ' [' . $article->category . ']';
}
$options[] = HTMLHelper::_('select.option', $article->value, $label);
}
return $options;
}
}
@@ -8,7 +8,7 @@
* FILE INFORMATION
* DEFGROUP: Joomla.Plugin
* INGROUP: MokoSuiteClient
* VERSION: 02.34.84
* VERSION: 02.48.24
* PATH: /src/Field/CopyableTokenField.php
* BRIEF: Read-only token field with a copy-to-clipboard button
*/
@@ -0,0 +1,367 @@
<?php
/**
* @package MokoSuiteClient
* @subpackage plg_system_mokosuiteclient
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
* @license GNU General Public License version 3 or later; see LICENSE
*/
namespace Moko\Plugin\System\MokoSuiteClient\Helper;
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\Database\DatabaseInterface;
/**
* MokoGitea License Validator — core DRM enforcement for the MokoSuite platform.
*
* Validates the site's DLID against MokoGitea, caches the result,
* and provides entitlement checking for all suite modules.
*
* Default Gitea server: git.mokoconsulting.tech
*
* @since 02.45.00
*/
final class LicenseValidator
{
/** @var string Default MokoGitea server address */
private const DEFAULT_GITEA_URL = 'https://git.mokoconsulting.tech';
/** @var int Cache TTL in seconds (24 hours) */
private const CACHE_TTL = 86400;
/** @var int Grace period in days after expiry before deactivation */
private const DEFAULT_GRACE_DAYS = 7;
/** @var object|null Cached license data for current request */
private static ?object $cachedLicense = null;
/**
* Validate the site's DLID against MokoGitea.
* Returns cached result if still valid; calls API if expired.
*/
public static function validate(bool $forceRefresh = false): object
{
if (self::$cachedLicense && !$forceRefresh) {
return self::$cachedLicense;
}
$db = Factory::getContainer()->get(DatabaseInterface::class);
$dlid = self::getDlid();
if (!$dlid) {
return self::$cachedLicense = (object) [
'valid' => false,
'status' => 'no_dlid',
'message' => 'No license key configured',
'entitlements'=> [],
];
}
// Check DB cache first
if (!$forceRefresh) {
$cached = self::getCachedResult($db, $dlid);
if ($cached) {
return self::$cachedLicense = $cached;
}
}
// Call MokoGitea API
$result = self::callGiteaApi($dlid);
// Cache the result
self::cacheResult($db, $dlid, $result);
return self::$cachedLicense = $result;
}
/**
* Check if the current license includes entitlement for a specific extension.
*
* @param string $extension Extension element name (e.g., 'com_mokosuite_crm', 'com_mokosuiterestaurant')
* @return bool
*/
public static function isEntitled(string $extension): bool
{
$license = self::validate();
if (!$license->valid) return false;
// Map extension names to repo identifiers
$repoMap = [
'com_mokosuite' => 'MokoSuite',
'com_mokosuite_crm' => 'MokoSuiteCRM',
'com_mokosuite_erp' => 'MokoSuiteERP',
'com_mokosuitechild' => 'MokoSuiteChild',
'com_mokosuitecreate' => 'MokoSuiteCreate',
'com_mokosuitenpo' => 'MokoSuiteNPO',
'com_mokosuitefield' => 'MokoSuiteField',
'com_mokosuitepos' => 'MokoSuitePOS',
'com_mokoshop' => 'MokoSuiteShop',
'com_mokosuitehrm' => 'MokoSuiteHRM',
'com_mokosuitemrp' => 'MokoSuiteMRP',
'com_mokosuiterestaurant' => 'MokoSuiteRestaurant',
];
$repo = $repoMap[$extension] ?? $extension;
$entitlements = $license->entitlements ?? [];
// Base is always entitled if license is valid
if ($repo === 'MokoSuite') return true;
return in_array($repo, $entitlements, true);
}
/**
* Get the full license status for admin display.
*/
public static function getStatus(): object
{
$license = self::validate();
return (object) [
'valid' => $license->valid ?? false,
'status' => $license->status ?? 'unknown',
'tier' => $license->tier ?? 'none',
'entitlements' => $license->entitlements ?? [],
'expires_at' => $license->expires_at ?? null,
'seats' => $license->seats ?? 0,
'seats_used' => $license->seats_used ?? 0,
'days_remaining'=> self::getDaysRemaining($license),
'in_grace' => self::isInGracePeriod($license),
'gitea_url' => self::getGiteaUrl(),
'dlid_configured' => (bool) self::getDlid(),
];
}
/**
* Get available seat count.
*/
public static function getAvailableSeats(): int
{
$license = self::validate();
$total = (int) ($license->seats ?? 0);
$used = (int) ($license->seats_used ?? 0);
if ($total === 0) return PHP_INT_MAX; // Unlimited seats
return max(0, $total - $used);
}
/**
* Report a heartbeat to MokoGitea (active installation check).
* Called by task scheduler daily.
*/
public static function heartbeat(): object
{
$dlid = self::getDlid();
if (!$dlid) return (object) ['success' => false, 'error' => 'No DLID'];
$giteaUrl = self::getGiteaUrl();
$siteUrl = \Joomla\CMS\Uri\Uri::root();
$joomlaVersion = (new \Joomla\CMS\Version())->getShortVersion();
// Count installed suite modules
$db = Factory::getContainer()->get(DatabaseInterface::class);
$db->setQuery($db->getQuery(true)
->select('element')
->from('#__extensions')
->where($db->quoteName('element') . ' LIKE ' . $db->quote('com_mokosuite%'))
->where($db->quoteName('type') . ' = ' . $db->quote('component'))
->where($db->quoteName('enabled') . ' = 1'));
$installedModules = $db->loadColumn() ?: [];
$response = self::httpPost($giteaUrl . '/api/v1/licenses/heartbeat', [
'dlid' => $dlid,
'site_url' => $siteUrl,
'joomla_version' => $joomlaVersion,
'installed_modules' => $installedModules,
'php_version' => PHP_VERSION,
]);
return $response;
}
// ── Private methods ─────────────────────────────────
/**
* Get the configured DLID from component params.
*/
private static function getDlid(): string
{
try {
$params = Factory::getApplication()->getParams('com_mokosuite');
return trim($params->get('dlid', ''));
} catch (\Throwable $e) {
// Component not installed or params not available
try {
$db = Factory::getContainer()->get(DatabaseInterface::class);
$db->setQuery($db->getQuery(true)
->select('params')
->from('#__extensions')
->where($db->quoteName('element') . ' = ' . $db->quote('com_mokosuite'))
->where($db->quoteName('type') . ' = ' . $db->quote('component')));
$paramsJson = $db->loadResult();
$params = json_decode($paramsJson ?: '{}', false);
return trim($params->dlid ?? '');
} catch (\Throwable $e2) {
return '';
}
}
}
/**
* Get the MokoGitea server URL from config.
*/
private static function getGiteaUrl(): string
{
try {
$params = Factory::getApplication()->getParams('com_mokosuite');
return rtrim($params->get('gitea_url', self::DEFAULT_GITEA_URL), '/');
} catch (\Throwable $e) {
return self::DEFAULT_GITEA_URL;
}
}
/**
* Call MokoGitea license validation API.
*/
private static function callGiteaApi(string $dlid): object
{
$giteaUrl = self::getGiteaUrl();
$response = self::httpGet($giteaUrl . '/api/v1/licenses/validate?dlid=' . urlencode($dlid));
if (isset($response->valid)) {
return (object) [
'valid' => (bool) $response->valid,
'status' => $response->status ?? 'unknown',
'tier' => $response->tier ?? '',
'entitlements' => $response->entitlements ?? $response->repo_scope ?? [],
'expires_at' => $response->expires_at ?? null,
'seats' => (int) ($response->seats ?? 0),
'seats_used' => (int) ($response->seats_used ?? 0),
'message' => $response->message ?? '',
];
}
// API error — use cached result if available, otherwise fail gracefully
return (object) [
'valid' => false,
'status' => 'api_error',
'message' => $response->error ?? 'Could not reach license server',
'entitlements' => [],
];
}
/**
* Get cached validation result from database.
*/
private static function getCachedResult(DatabaseInterface $db, string $dlid): ?object
{
$dlidHash = hash('sha256', $dlid);
try {
$db->setQuery($db->getQuery(true)
->select('response_data, checked_at')
->from('#__mokosuite_license_cache')
->where($db->quoteName('dlid_hash') . ' = ' . $db->quote($dlidHash))
->where('checked_at > DATE_SUB(NOW(), INTERVAL ' . (int) self::CACHE_TTL . ' SECOND)'));
$cached = $db->loadObject();
if ($cached && $cached->response_data) {
$data = json_decode($cached->response_data, false);
if ($data) return $data;
}
} catch (\Throwable $e) {
// Table may not exist yet — that's fine
}
return null;
}
/**
* Cache validation result in database.
*/
private static function cacheResult(DatabaseInterface $db, string $dlid, object $result): void
{
$dlidHash = hash('sha256', $dlid);
try {
// Upsert
$db->setQuery('REPLACE INTO #__mokosuite_license_cache (dlid_hash, response_data, checked_at) VALUES ('
. $db->quote($dlidHash) . ', '
. $db->quote(json_encode($result)) . ', '
. $db->quote(Factory::getDate()->toSql()) . ')');
$db->execute();
} catch (\Throwable $e) {
// Cache table may not exist — non-fatal
}
}
/**
* Calculate days remaining on license.
*/
private static function getDaysRemaining(object $license): ?int
{
if (empty($license->expires_at)) return null;
$now = new \DateTime('today');
$expiry = new \DateTime($license->expires_at);
$diff = (int) $now->diff($expiry)->format('%r%a');
return $diff;
}
/**
* Check if license is in grace period (expired but within grace window).
*/
private static function isInGracePeriod(object $license): bool
{
$days = self::getDaysRemaining($license);
if ($days === null || $days >= 0) return false;
$graceDays = self::DEFAULT_GRACE_DAYS;
try {
$graceDays = (int) Factory::getApplication()->getParams('com_mokosuite')->get('license_grace_days', self::DEFAULT_GRACE_DAYS);
} catch (\Throwable $e) {}
return abs($days) <= $graceDays;
}
/**
* HTTP GET helper.
*/
private static function httpGet(string $url): object
{
$response = file_get_contents($url, false, stream_context_create([
'http' => [
'method' => 'GET',
'header' => 'Accept: application/json',
'ignore_errors' => true,
'timeout' => 10,
],
]));
return json_decode($response ?: '{}', false) ?: (object) ['error' => 'No response'];
}
/**
* HTTP POST helper.
*/
private static function httpPost(string $url, array $data): object
{
$response = file_get_contents($url, false, stream_context_create([
'http' => [
'method' => 'POST',
'header' => "Content-Type: application/json\r\nAccept: application/json",
'ignore_errors' => true,
'timeout' => 10,
'content' => json_encode($data),
],
]));
return json_decode($response ?: '{}', false) ?: (object) ['error' => 'No response'];
}
}
@@ -26,7 +26,7 @@ PLG_SYSTEM_MOKOSUITECLIENT_HEALTH_TOKEN_DESC="Auto-generated bearer token for th
PLG_SYSTEM_MOKOSUITECLIENT_FIELDSET_ALIASES_LABEL="Site Aliases"
PLG_SYSTEM_MOKOSUITECLIENT_FIELDSET_ALIASES_DESC="Configure additional domains that mirror this site. Each alias can have its own offline status, robots directive, and backend redirect behavior."
PLG_SYSTEM_MOKOSUITECLIENT_PRIMARY_DOMAIN_LABEL="Primary Domain"
PLG_SYSTEM_MOKOSUITECLIENT_PRIMARY_DOMAIN_DESC="The primary domain for this site (e.g. waas.dev.mokoconsulting.tech). Used for backend redirect on alias domains. Do not include https:// prefix."
PLG_SYSTEM_MOKOSUITECLIENT_PRIMARY_DOMAIN_DESC="The primary domain for this site (e.g. suite.dev.mokoconsulting.tech). Used for backend redirect on alias domains. Do not include https:// prefix."
PLG_SYSTEM_MOKOSUITECLIENT_SITE_ALIASES_LABEL="Domain Aliases"
PLG_SYSTEM_MOKOSUITECLIENT_SITE_ALIASES_DESC="Add domain aliases that serve as mirrors of this site. Each alias gets its own MokoSuiteClientHQ monitoring datasource."
PLG_SYSTEM_MOKOSUITECLIENT_ALIAS_DOMAIN_LABEL="Domain"
@@ -39,3 +39,11 @@ PLG_SYSTEM_MOKOSUITECLIENT_ALIAS_ROBOTS_LABEL="Robots"
PLG_SYSTEM_MOKOSUITECLIENT_ALIAS_ROBOTS_DESC="Meta robots directive for this alias domain. Use 'noindex, nofollow' to prevent search engines from indexing the alias."
PLG_SYSTEM_MOKOSUITECLIENT_ALIAS_REDIRECT_BACKEND_LABEL="Redirect Backend"
PLG_SYSTEM_MOKOSUITECLIENT_ALIAS_REDIRECT_BACKEND_DESC="Redirect admin panel requests on this alias to the primary domain. Frontend stays on the alias domain."
; ===== Heartbeat Monitor fieldset =====
PLG_SYSTEM_MOKOSUITECLIENT_FIELDSET_MONITOR_LABEL="Heartbeat Monitor"
PLG_SYSTEM_MOKOSUITECLIENT_FIELDSET_MONITOR_DESC="Settings for the MokoSuiteClientHQ heartbeat registration."
PLG_SYSTEM_MOKOSUITECLIENT_HEARTBEAT_LABEL="Enable Heartbeat"
PLG_SYSTEM_MOKOSUITECLIENT_HEARTBEAT_DESC="Send heartbeat data to MokoSuiteClientHQ on install, update, and admin login."
PLG_SYSTEM_MOKOSUITECLIENT_MONITOR_BASE_URL_LABEL="HQ Base URL"
PLG_SYSTEM_MOKOSUITECLIENT_MONITOR_BASE_URL_DESC="Base URL of the MokoSuiteClientHQ instance that receives heartbeat data."
@@ -26,7 +26,7 @@ PLG_SYSTEM_MOKOSUITECLIENT_HEALTH_TOKEN_DESC="Auto-generated bearer token for th
PLG_SYSTEM_MOKOSUITECLIENT_FIELDSET_ALIASES_LABEL="Site Aliases"
PLG_SYSTEM_MOKOSUITECLIENT_FIELDSET_ALIASES_DESC="Configure additional domains that mirror this site. Each alias can have its own offline status, robots directive, and backend redirect behavior."
PLG_SYSTEM_MOKOSUITECLIENT_PRIMARY_DOMAIN_LABEL="Primary Domain"
PLG_SYSTEM_MOKOSUITECLIENT_PRIMARY_DOMAIN_DESC="The primary domain for this site (e.g. waas.dev.mokoconsulting.tech). Used for backend redirect on alias domains. Do not include https:// prefix."
PLG_SYSTEM_MOKOSUITECLIENT_PRIMARY_DOMAIN_DESC="The primary domain for this site (e.g. suite.dev.mokoconsulting.tech). Used for backend redirect on alias domains. Do not include https:// prefix."
PLG_SYSTEM_MOKOSUITECLIENT_SITE_ALIASES_LABEL="Domain Aliases"
PLG_SYSTEM_MOKOSUITECLIENT_SITE_ALIASES_DESC="Add domain aliases that serve as mirrors of this site. Each alias gets its own MokoSuiteClientHQ monitoring datasource."
PLG_SYSTEM_MOKOSUITECLIENT_ALIAS_DOMAIN_LABEL="Domain"
@@ -30,7 +30,7 @@
<license>GNU General Public License version 3 or later; see LICENSE.md</license>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
<authorUrl>https://mokoconsulting.tech</authorUrl>
<version>02.34.84-dev</version>
<version>02.48.24</version>
<description>MokoSuiteClient core system plugin — coordinates feature plugins, heartbeat, health checks, and admin customizations.</description>
<namespace path=".">Moko\Plugin\System\MokoSuiteClient</namespace>
<scriptfile>script.php</scriptfile>
@@ -68,18 +68,128 @@
addfieldprefix="Moko\Plugin\System\MokoSuiteClient\Field"
>
<fieldset name="basic"
label="PLG_SYSTEM_MOKOSUITE_FIELDSET_CORE_LABEL"
description="PLG_SYSTEM_MOKOSUITE_FIELDSET_CORE_DESC">
label="PLG_SYSTEM_MOKOSUITECLIENT_FIELDSET_CORE_LABEL"
description="PLG_SYSTEM_MOKOSUITECLIENT_FIELDSET_CORE_DESC">
<field
name="health_api_token"
type="CopyableToken"
label="PLG_SYSTEM_MOKOSUITE_HEALTH_TOKEN_LABEL"
description="PLG_SYSTEM_MOKOSUITE_HEALTH_TOKEN_DESC"
label="PLG_SYSTEM_MOKOSUITECLIENT_HEALTH_TOKEN_LABEL"
description="PLG_SYSTEM_MOKOSUITECLIENT_HEALTH_TOKEN_DESC"
default=""
filter="raw"
readonly="true"
/>
</fieldset>
<fieldset name="monitor"
label="PLG_SYSTEM_MOKOSUITECLIENT_FIELDSET_MONITOR_LABEL"
description="PLG_SYSTEM_MOKOSUITECLIENT_FIELDSET_MONITOR_DESC">
<field name="heartbeat_enabled" type="radio" default="1"
label="PLG_SYSTEM_MOKOSUITECLIENT_HEARTBEAT_LABEL"
description="PLG_SYSTEM_MOKOSUITECLIENT_HEARTBEAT_DESC"
class="btn-group btn-group-yesno">
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field name="monitor_base_url" type="url"
default="https://suite.dev.mokoconsulting.tech"
label="PLG_SYSTEM_MOKOSUITECLIENT_MONITOR_BASE_URL_LABEL"
description="PLG_SYSTEM_MOKOSUITECLIENT_MONITOR_BASE_URL_DESC"
filter="url" />
<field name="auto_clear_cache" type="radio" default="0"
label="Auto-Clear Cache on Save"
description="Automatically clear Joomla cache when articles, modules, or extensions are saved."
class="btn-group btn-group-yesno">
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field name="protect_emails" type="radio" default="0"
label="Email Protection"
description="Obfuscate email addresses in HTML output to prevent spam bot harvesting. Uses JavaScript decloaking."
class="btn-group btn-group-yesno">
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field name="snippets_enabled" type="radio" default="0"
label="Snippets"
description="Enable {snippet alias=&quot;name&quot;} content tags. Reusable text/HTML blocks stored in the database with variable substitution support."
class="btn-group btn-group-yesno">
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field name="content_templates_enabled" type="radio" default="0"
label="Content Templates"
description="Enable {template alias=&quot;name&quot;} content tags. Loads structured template data from the content_templates table and renders introtext + fulltext."
class="btn-group btn-group-yesno">
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field name="articles_anywhere_enabled" type="radio" default="0"
label="Articles Anywhere"
description="Enable {article id=&quot;42&quot;}[title]{/article} content tags. Insert article data anywhere using template placeholders for title, introtext, author, category, dates, images, and more."
class="btn-group btn-group-yesno">
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field name="users_anywhere_enabled" type="radio" default="0"
label="Users Anywhere"
description="Allow {user} tags to display user information in content. Use {user id=&quot;42&quot;}[name]{/user} for specific users or {user name} for the current logged-in user."
class="btn-group btn-group-yesno">
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field name="users_allow_email" type="radio" default="0"
label="Users: Show Email"
description="Allow the [email] placeholder in {user} tags to display the real email address. When disabled, emails are masked."
class="btn-group btn-group-yesno"
showon="users_anywhere_enabled:1">
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field name="users_allow_username" type="radio" default="1"
label="Users: Show Username"
description="Allow the [username] placeholder in {user} tags to display the real username. When disabled, usernames are masked."
class="btn-group btn-group-yesno"
showon="users_anywhere_enabled:1">
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field name="replacements_enabled" type="radio" default="0"
label="ReReplacer"
description="Enable backend-managed string and regex replacement rules. Published rules from the replacements table are applied to site and/or admin content."
class="btn-group btn-group-yesno">
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field name="sourcerer_enabled" type="radio" default="0"
label="Code Embedding (Sourcerer)"
description="Allow embedding PHP, JavaScript, and CSS code in content via {source} tags. Security restricted."
class="btn-group btn-group-yesno">
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field name="sourcerer_forbidden_functions" type="text" default="exec,system,passthru,shell_exec,popen,proc_open,dl,eval,call_user_func,call_user_func_array,assert,array_map,array_filter,array_walk,usort,uasort,uksort,create_function,preg_replace_callback,ob_start"
label="Forbidden PHP Functions"
description="Comma-separated list of PHP functions blocked in {source} tags. Backtick operator is always blocked."
showon="sourcerer_enabled:1" />
<field name="monitor_signing_key" type="hidden"
default="LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2QUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktZd2dnU2lBZ0VBQW9JQkFRQ2xZNnNzOTZpeTZOOGMKTHRxbndhbnU4eEozdDcrdDhXT3hoY0Yyclc2QmlmOVhNaEpnYkw0c055N0wwV1dTT2tkMmZxalBNcDFtOFNyNAo1VnNycjE3cFc5b0FNMmtmdFdsaTZ1NkhTVEYyN2pVVUJrT3o4MHZMRklMMGNGNkJCUkpYN2JVWkRpamdUMjc1ClREb3dXZy82Zk9GeWFEelBHUkJuYXFacTljU2lEYWoyNlpSTVZIbktQUERWTG92VzRPTDQzL2gwZ3BtN25nUGIKdWJlLzFFTDRUMHFRbm1Xc2FEOFZ6VStoRXFGSDRTVUtMaDVNeklGbUxFZzRlZ0xCbTBXcWdxbzZRQVBnZDVPYgoybXhmQndta3RLVm5hcWR6eG9KSytzaTVuZkYreGpxbWRMZThUdmEyTHNuTUxlZmsrODVoQ3hxS2x1eWRta1lXCjlvUk5qcDhiQWdNQkFBRUNnZ0VBQkZOUS9NSVZaV2gxdlZUMFh3TFBvUEkyZjI4TTBrM0gzN0t4MXBxK2t5QzYKenRyK1pBczBCaEFEWjAwNHJOUmRYaG45N0QxVXBJYVdLeUJFZkNZQUEzWmxneS9WQmdGR21sR3VuMWNvdGdXUQoyYzg0SWhLdzNzVFFqL2dJWUxOelFWMTBLUTJYd0JZVHZ1MWhjRFpLeUxCUGJTQ1F4cEhQUGdVcUNRNFljR3lFClErVmc1dHJUYk8wQ2xCZ1U5bkVnYU1RakRJZ0F3WVZPV203dUxJTW84UC9nT3FuT2tmaFhzdzl3VTJVYWxFeTEKRmRZbGhMbGJ0ZS9MZ3lkYlJ2RStjNEtqZVp0Z3ptc1RneEh2dzM5YVVmZUZTclFRT0FjcXc0alNzUjdMck9UZAp5bDhpelRrZVBrTVFMamFqR0pabWdPbitkRzhtUlpMa3FKcWdGaVpqRVFLQmdRRFV0L0xlU0h5SmhvY3VFL240CkZreEpaclJoWUVsWnc2WlZJUnQzWDlPQ1Nmaklab3I1ZkZlczhvUzZySFhKdGZYeWx4QUxOSjJjTUhKTTViVnUKbUFSUFU4cThBeVc0OE03cHAyNmtVVTMxNXc2OU1SUkhzbWgyekRabEtDeG5GM1NSQ3U4YW95d3hZc3RUZ3hkTgo2bDhLNHZsS1dsN3FYblBhWjZjb3lQSU9od0tCZ1FESENuRmRRdW5SMVI2dkxGaVFZMTRiT3QwT0tzVGJYMUJyCmpvUGZySkxvRm5mSCs4VDVnNUdxYkV5T2p0WG1tRXhmTFFpcDBQVXRtc1E0YXlJRFBZYWZtU3RpK2dtQXZFd1MKZTlKcVYxYlRuazUrYnVRZ2FlOW16REpJWkxaczRJUlhrd1Q5aDZ4Q2xKeS80TGJSRHdBU3dUVGJlY01hN3A4UgpQN0p0bjdsYnpRS0JnQzNOR2FjUTFuZktGb3N1VS9FOTQ5a2VHeEtvWjhMREpLcEp3WjgzYTlRdTF6bFhFdTlhCi9ZbklnaG1yam9VSy85VG0vOVpaMHVIUmNKcnNEdCtzTGFsaThsRC9JSDBzcEhDYzAyN2Y3cmhXc3M2N3BaRTIKY2RXNmJLL2xNWUpWQTQxRFhHNVEyZkFjUklsTHZaWFNNL3FsR21ZUEJVYlRaWUNPTnVqS000dzdBb0dBU1dBdwpLcEZnWVZxUDFVUWo0aGEvdW9vWXRBQlFVZzd4TnJWektDSVdoampDTDVkQkpqcTZtSGtVUC9tb0lUcEQ3VkpNCnYwMnBGUWJaRDNOdk5vS1gvbjRZNElRTXZNaXR3cUtqRDFEalVXQXF6N0ZScUNGbGdDQUc2V2szVnl2dG5kczEKRzhISVgwTXFCaEp4VXVDVXhsVXpoelY4RjVHZ1VsdUpDNkMyVklFQ2dZQkJWSkxpZlNVOTlHWGZtK3dPd0RWcgo2bHZoUFgxOTBGVktWQXY3aVVWTXBwWXg4Y0QxYkcyUjRLT29JbnkxYTlxdjA2ZGFzeGVQOStkVjJVMWU3MWl5CkFXWDRBVHIrYitvSGk2eUk1MXRHRk54RUxiNXZYMVpYM3VNaDlWM29iYUpuSFNjYllpKzBBNjlyRmNuNEZuLzUKWXJybWxLTzRlRHFVZkswbVFJVCtwUT09Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K"
filter="raw" />
</fieldset>
</fields>
</config>
</extension>
@@ -22,7 +22,7 @@
* DEFGROUP: Joomla.Plugin
* INGROUP: MokoSuiteClient
* REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
* VERSION: 02.34.84
* VERSION: 02.48.24
* PATH: /src/script.php
* BRIEF: Installation script for MokoSuiteClient plugin
* NOTE: Handles installation, update, and uninstallation tasks including language override deployment
@@ -527,7 +527,7 @@ class plgSystemMokoSuiteClientInstallerScript implements InstallerScriptInterfac
}
catch (\Exception $e)
{
// Don't break install if email fails
Log::add('Install notification email failed: ' . $e->getMessage(), Log::WARNING, 'mokosuiteclient');
}
}
@@ -767,7 +767,7 @@ class plgSystemMokoSuiteClientInstallerScript implements InstallerScriptInterfac
'id_holder' => '',
'title_holder' => '',
'table_name' => '',
'text_prefix' => 'PLG_SYSTEM_MOKOSUITE',
'text_prefix' => 'PLG_SYSTEM_MOKOSUITECLIENT',
];
$db->insertObject('#__action_log_config', $config);
@@ -22,7 +22,7 @@
* DEFGROUP: Joomla.Plugin
* INGROUP: MokoSuiteClient
* REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
* VERSION: 02.34.84
* VERSION: 02.48.24
* PATH: /src/services/provider.php
* BRIEF: Service provider for dependency injection in Joomla 5.x
* NOTE: Registers the plugin with Joomla's DI container

Some files were not shown because too many files have changed in this diff Show More