diff --git a/src/packages/com_mokowaas/admin/language/en-GB/com_mokowaas.sys.ini b/src/packages/com_mokowaas/admin/language/en-GB/com_mokowaas.sys.ini
index 0218a06c..3c71dbd1 100644
--- a/src/packages/com_mokowaas/admin/language/en-GB/com_mokowaas.sys.ini
+++ b/src/packages/com_mokowaas/admin/language/en-GB/com_mokowaas.sys.ini
@@ -14,4 +14,6 @@ COM_MOKOWAAS_MENU_TICKETS="Helpdesk"
COM_MOKOWAAS_MENU_HTACCESS=".htaccess Maker"
COM_MOKOWAAS_MENU_PRIVACY="Privacy Guard"
COM_MOKOWAAS_MENU_WAFLOG="WAF Log"
+COM_MOKOWAAS_MENU_DATABASE="Database Tools"
+COM_MOKOWAAS_MENU_CLEANUP="Cache Cleanup"
COM_MOKOWAAS_MENU_CACHE="Cache Management"
diff --git a/src/packages/com_mokowaas/admin/src/Controller/DisplayController.php b/src/packages/com_mokowaas/admin/src/Controller/DisplayController.php
index c9eaa008..dd77f61f 100644
--- a/src/packages/com_mokowaas/admin/src/Controller/DisplayController.php
+++ b/src/packages/com_mokowaas/admin/src/Controller/DisplayController.php
@@ -34,6 +34,8 @@ class DisplayController extends BaseController
'categories' => 'mokowaas.tickets',
'canned' => 'mokowaas.tickets',
'automation' => 'core.admin',
+ 'database' => 'core.admin',
+ 'cleanup' => 'mokowaas.cache',
];
public function display($cachable = false, $urlparams = [])
@@ -282,6 +284,43 @@ class DisplayController extends BaseController
}
}
+ // ==================================================================
+ // Maintenance (#127, #128)
+ // ==================================================================
+
+ public function optimizeDb()
+ {
+ Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
+ if (!$this->checkAcl('core.admin')) { $this->jsonForbidden(); return; }
+ $model = new \Moko\Component\MokoWaaS\Administrator\Model\MaintenanceModel();
+ $this->jsonResponse($model->optimizeTables());
+ }
+
+ public function repairDb()
+ {
+ Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
+ if (!$this->checkAcl('core.admin')) { $this->jsonForbidden(); return; }
+ $model = new \Moko\Component\MokoWaaS\Administrator\Model\MaintenanceModel();
+ $this->jsonResponse($model->repairTables());
+ }
+
+ public function purgeSessions()
+ {
+ Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
+ if (!$this->checkAcl('core.admin')) { $this->jsonForbidden(); return; }
+ $model = new \Moko\Component\MokoWaaS\Administrator\Model\MaintenanceModel();
+ $this->jsonResponse($model->purgeSessions());
+ }
+
+ public function cleanDirectory()
+ {
+ Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
+ if (!$this->checkAcl('mokowaas.cache')) { $this->jsonForbidden(); return; }
+ $dirKey = Factory::getApplication()->getInput()->getString('dir_key', '');
+ $model = new \Moko\Component\MokoWaaS\Administrator\Model\MaintenanceModel();
+ $this->jsonResponse($model->cleanDirectory($dirKey));
+ }
+
// ==================================================================
// Helpdesk CRUD (#137, #138, #139)
// ==================================================================
diff --git a/src/packages/com_mokowaas/admin/tmpl/cleanup/default.php b/src/packages/com_mokowaas/admin/tmpl/cleanup/default.php
new file mode 100644
index 00000000..073c623d
--- /dev/null
+++ b/src/packages/com_mokowaas/admin/tmpl/cleanup/default.php
@@ -0,0 +1,63 @@
+dirs;
+$token = Session::getFormToken();
+$cleanUrl = Route::_('index.php?option=com_mokowaas&task=display.cleanDirectory&format=json');
+
+$dirKeys = ['site_cache', 'admin_cache', 'tmp', 'logs'];
+$totalMb = 0;
+$totalFiles = 0;
+foreach ($dirs as $d) { $totalMb += $d->size_mb; $totalFiles += $d->files; }
+?>
+
+
+
+
+
+ $d): ?>
+
+
+
+
label); ?>
+
size_mb, 1); ?> MB
+
files); ?> files
+ writable): ?>
+
Not writable
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/packages/com_mokowaas/admin/tmpl/database/default.php b/src/packages/com_mokowaas/admin/tmpl/database/default.php
new file mode 100644
index 00000000..0d0c9357
--- /dev/null
+++ b/src/packages/com_mokowaas/admin/tmpl/database/default.php
@@ -0,0 +1,72 @@
+tableData;
+$tables = $data['tables'] ?? [];
+$token = Session::getFormToken();
+$optimizeUrl = Route::_('index.php?option=com_mokowaas&task=display.optimizeDb&format=json');
+$repairUrl = Route::_('index.php?option=com_mokowaas&task=display.repairDb&format=json');
+$purgeUrl = Route::_('index.php?option=com_mokowaas&task=display.purgeSessions&format=json');
+?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | Table | Engine | Rows | Size | Overhead |
+
+
+
+ | name); ?> |
+ engine); ?> |
+ rows); ?> |
+ size_mb; ?> MB |
+ overhead_kb > 0 ? $t->overhead_kb . ' KB' : '—'; ?> |
+
+
+
+
+
+
+
+
+
diff --git a/src/packages/com_mokowaas/mokowaas.xml b/src/packages/com_mokowaas/mokowaas.xml
index 4a50cfc5..d88f93e1 100644
--- a/src/packages/com_mokowaas/mokowaas.xml
+++ b/src/packages/com_mokowaas/mokowaas.xml
@@ -34,6 +34,8 @@
+
+
diff --git a/src/packages/mod_mokowaas_cpanel/src/Helper/CpanelHelper.php b/src/packages/mod_mokowaas_cpanel/src/Helper/CpanelHelper.php
index a50d895e..87fff882 100644
--- a/src/packages/mod_mokowaas_cpanel/src/Helper/CpanelHelper.php
+++ b/src/packages/mod_mokowaas_cpanel/src/Helper/CpanelHelper.php
@@ -87,10 +87,11 @@ class CpanelHelper
public function getCounts(DatabaseInterface $db): object
{
$counts = (object) [
- 'articles' => 0,
- 'users' => 0,
- 'extensions' => 0,
- 'updates' => 0,
+ 'articles' => 0,
+ 'users' => 0,
+ 'extensions' => 0,
+ 'updates' => 0,
+ 'moko_updates' => 0,
];
try
@@ -106,6 +107,20 @@ class CpanelHelper
$db->setQuery($db->getQuery(true)->select('COUNT(*)')->from($db->quoteName('#__updates'))->where($db->quoteName('extension_id') . ' != 0'));
$counts->updates = (int) $db->loadResult();
+
+ // MokoWaaS-specific updates
+ $db->setQuery(
+ $db->getQuery(true)
+ ->select('COUNT(*)')
+ ->from($db->quoteName('#__updates', 'u'))
+ ->join('INNER', $db->quoteName('#__extensions', 'e') . ' ON e.extension_id = u.extension_id')
+ ->where('(' . $db->quoteName('e.element') . ' LIKE ' . $db->quote('mokowaas%')
+ . ' OR ' . $db->quoteName('e.element') . ' LIKE ' . $db->quote('pkg_mokowaas%')
+ . ' OR ' . $db->quoteName('e.element') . ' LIKE ' . $db->quote('com_mokowaas%')
+ . ' OR ' . $db->quoteName('e.element') . ' LIKE ' . $db->quote('mod_mokowaas%')
+ . ' OR ' . $db->quoteName('e.element') . ' = ' . $db->quote('mokoonyx') . ')')
+ );
+ $counts->moko_updates = (int) $db->loadResult();
}
catch (\Throwable $e)
{
diff --git a/src/packages/mod_mokowaas_cpanel/tmpl/default.php b/src/packages/mod_mokowaas_cpanel/tmpl/default.php
index a65553f5..66eea9f4 100644
--- a/src/packages/mod_mokowaas_cpanel/tmpl/default.php
+++ b/src/packages/mod_mokowaas_cpanel/tmpl/default.php
@@ -67,6 +67,16 @@ $diskColor = ($diskPct !== null && $diskPct > 90) ? 'bg-danger' : (($diskPct !==
offline)): ?>
Offline
+ moko_updates ?? 0) > 0): ?>
+
+ moko_updates; ?> MokoWaaS updatemoko_updates > 1 ? 's' : ''; ?>
+
+
+ updates > 0 && $counts->updates !== ($counts->moko_updates ?? 0)): ?>
+
+ updates - ($counts->moko_updates ?? 0); ?> updateupdates - ($counts->moko_updates ?? 0)) > 1 ? 's' : ''; ?>
+
+
diff --git a/src/packages/mod_mokowaas_menu/tmpl/default.php b/src/packages/mod_mokowaas_menu/tmpl/default.php
index 0c7eca76..d95b4df2 100644
--- a/src/packages/mod_mokowaas_menu/tmpl/default.php
+++ b/src/packages/mod_mokowaas_menu/tmpl/default.php
@@ -17,6 +17,8 @@ $items = [
['icon' => 'icon-file-code', 'title' => '.htaccess Maker', 'link' => 'index.php?option=com_mokowaas&view=htaccess'],
['icon' => 'icon-lock', 'title' => 'Privacy Guard', 'link' => 'index.php?option=com_mokowaas&view=privacy'],
['icon' => 'icon-shield-alt', 'title' => 'WAF Log', 'link' => 'index.php?option=com_mokowaas&view=waflog'],
+ ['icon' => 'icon-database', 'title' => 'Database Tools', 'link' => 'index.php?option=com_mokowaas&view=database'],
+ ['icon' => 'icon-trash', 'title' => 'Cache Cleanup', 'link' => 'index.php?option=com_mokowaas&view=cleanup'],
['icon' => 'icon-power-off', 'title' => 'Feature Plugins', 'link' => 'index.php?option=com_plugins&filter[folder]=system&filter[search]=mokowaas'],
];
diff --git a/src/packages/plg_system_mokowaas/Extension/MokoWaaS.php b/src/packages/plg_system_mokowaas/Extension/MokoWaaS.php
index 0000d4ad..3d03f803 100644
--- a/src/packages/plg_system_mokowaas/Extension/MokoWaaS.php
+++ b/src/packages/plg_system_mokowaas/Extension/MokoWaaS.php
@@ -939,55 +939,6 @@ class MokoWaaS extends CMSPlugin implements BootableExtensionInterface
}
$this->protectPlugin();
- $this->warnMissingLicenseKey();
- }
-
- /**
- * Warn on every admin page load if no license key is configured.
- * Non-dismissable — shows on every request, not cached per session.
- */
- protected function warnMissingLicenseKey(): void
- {
- if (!$this->isMasterUser())
- {
- return;
- }
-
- try
- {
- $db = Factory::getDbo();
-
- $query = $db->getQuery(true)
- ->select($db->quoteName('extra_query'))
- ->from($db->quoteName('#__update_sites'))
- ->where('(' . $db->quoteName('name') . ' LIKE ' . $db->quote('%MokoWaaS%')
- . ' OR ' . $db->quoteName('location') . ' LIKE ' . $db->quote('%MokoWaaS%') . ')')
- ->setLimit(1);
- $db->setQuery($query);
- $extraQuery = (string) $db->loadResult();
-
- if (!empty($extraQuery) && strpos($extraQuery, 'dlid=') !== false)
- {
- parse_str($extraQuery, $parsed);
-
- if (!empty($parsed['dlid']))
- {
- return;
- }
- }
-
- $this->app->enqueueMessage(
- 'Moko Consulting License Key Required — '
- . 'No download key is configured. Updates will not be available until a valid license key is entered. '
- . 'Go to System → Update Sites '
- . 'and enter your license key in the Download Key field for the MokoWaaS update site.',
- 'warning'
- );
- }
- catch (\Throwable $e)
- {
- // Silent
- }
}
// ------------------------------------------------------------------
diff --git a/src/script.php b/src/script.php
index 9a2a541c..8d659f98 100644
--- a/src/script.php
+++ b/src/script.php
@@ -69,6 +69,9 @@ class Pkg_MokowaasInstallerScript
// Trigger heartbeat registration
$this->sendHeartbeat();
+
+ // Warn if no license key is configured
+ $this->warnMissingLicenseKey();
}
/**
@@ -996,4 +999,57 @@ class Pkg_MokowaasInstallerScript
Log::add('Feature param migration error: ' . $e->getMessage(), Log::WARNING, 'mokowaas');
}
}
+
+ /**
+ * Warn after install/update if no license key (dlid) is configured on the update site.
+ */
+ private function warnMissingLicenseKey(): void
+ {
+ try
+ {
+ $db = Factory::getDbo();
+ $app = Factory::getApplication();
+
+ $query = $db->getQuery(true)
+ ->select([$db->quoteName('update_site_id'), $db->quoteName('extra_query')])
+ ->from($db->quoteName('#__update_sites'))
+ ->where('(' . $db->quoteName('name') . ' LIKE ' . $db->quote('%MokoWaaS%')
+ . ' OR ' . $db->quoteName('location') . ' LIKE ' . $db->quote('%MokoWaaS%') . ')')
+ ->setLimit(1);
+ $db->setQuery($query);
+ $site = $db->loadObject();
+
+ if ($site)
+ {
+ $extraQuery = (string) ($site->extra_query ?? '');
+
+ if (!empty($extraQuery) && strpos($extraQuery, 'dlid=') !== false)
+ {
+ parse_str($extraQuery, $parsed);
+
+ if (!empty($parsed['dlid']))
+ {
+ return;
+ }
+ }
+
+ $editUrl = 'index.php?option=com_installer&task=updatesite.edit&update_site_id=' . (int) $site->update_site_id;
+ }
+ else
+ {
+ $editUrl = 'index.php?option=com_installer&view=updatesites';
+ }
+
+ $app->enqueueMessage(
+ 'Moko Consulting License Key Required — '
+ . 'No download key is configured. Updates will not be available until a valid license key is entered. '
+ . 'Enter License Key',
+ 'warning'
+ );
+ }
+ catch (\Throwable $e)
+ {
+ // Silent
+ }
+ }
}