diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fd8d4f4..0c8afa94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,8 @@ - RSA-signed heartbeat authentication — private key in monitor plugin manifest, public key on MokoSuiteHQ - 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 → MokoSuite database table migration in install script (create new, copy data, drop old) ### Removed - PerfectPublisher webservices plugin (no longer needed) diff --git a/source/packages/plg_system_mokosuite/Extension/MokoSuite.php b/source/packages/plg_system_mokosuite/Extension/MokoSuite.php index 513b0da5..e3e64aa1 100644 --- a/source/packages/plg_system_mokosuite/Extension/MokoSuite.php +++ b/source/packages/plg_system_mokosuite/Extension/MokoSuite.php @@ -285,9 +285,77 @@ class MokoSuite extends CMSPlugin implements BootableExtensionInterface return; } + $this->loadFontAwesome($doc); $this->redirectHelpMenu($doc); } + /** + * Load Font Awesome 7 in the admin backend. + * + * Picks up the FA7 Kit code from MokoOnyx template params if present. + * Falls back to MokoOnyx's bundled FA7 Free files, then to CDN. + * + * @param \Joomla\CMS\Document\HtmlDocument $doc Document object + * + * @return void + * + * @since 02.35.00 + */ + protected function loadFontAwesome($doc): void + { + try + { + $db = Factory::getDbo(); + + // Check MokoOnyx template params for FA7 Kit code + $query = $db->getQuery(true) + ->select($db->quoteName('params')) + ->from($db->quoteName('#__extensions')) + ->where($db->quoteName('type') . ' = ' . $db->quote('template')) + ->where($db->quoteName('element') . ' = ' . $db->quote('mokoonyx')); + $db->setQuery($query); + $paramsJson = (string) $db->loadResult(); + + if ($paramsJson) + { + $params = json_decode($paramsJson, true); + $kitCode = trim((string) ($params['fA6KitCode'] ?? '')); + + if ($kitCode !== '') + { + $doc->addScript( + 'https://kit.fontawesome.com/' . htmlspecialchars($kitCode, ENT_QUOTES, 'UTF-8') . '.js', + [], + ['crossorigin' => 'anonymous'] + ); + + return; + } + } + + // Try MokoOnyx's bundled FA7 Free files + $localPath = 'media/templates/site/mokoonyx/vendor/fa7free/css/all.min.css'; + + if (is_file(JPATH_ROOT . '/' . $localPath)) + { + $doc->addStyleSheet(Uri::root(true) . '/' . $localPath); + + return; + } + + // Fallback: FA6 Free from cdnjs + $doc->addStyleSheet( + 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css', + [], + ['crossorigin' => 'anonymous', 'referrerpolicy' => 'no-referrer'] + ); + } + catch (\Throwable $e) + { + // Non-fatal — admin works without icons + } + } + /** * Redirect the admin Help menu link to the configured support URL. * diff --git a/source/script.php b/source/script.php index 2c703436..152dd140 100644 --- a/source/script.php +++ b/source/script.php @@ -61,6 +61,9 @@ class Pkg_MokosuiteInstallerScript public function postflight($type, $parent) { + // Migrate MokoWaaS database tables to MokoSuite naming + $this->migrateWaasTables(); + // Remove legacy extensions and migrate settings before retiring $this->cleanupLegacyExtensions(); $this->migrateStandalonePlugins(); @@ -1639,4 +1642,90 @@ class Pkg_MokosuiteInstallerScript // Silent } } + + /** + * Migrate MokoWaaS database tables to MokoSuite naming. + * + * For each table: create new mokosuite_* table → copy data from mokowaas_* → drop old table. + * Safe to run multiple times — skips tables that don't exist or are already migrated. + * + * @return void + * + * @since 02.35.00 + */ + private function migrateWaasTables(): void + { + $tableMap = [ + 'mokowaas_ticket_categories' => 'mokosuite_ticket_categories', + 'mokowaas_tickets' => 'mokosuite_tickets', + 'mokowaas_ticket_replies' => 'mokosuite_ticket_replies', + 'mokowaas_ticket_canned' => 'mokosuite_ticket_canned', + 'mokowaas_ticket_automation' => 'mokosuite_ticket_automation', + 'mokowaas_consent_log' => 'mokosuite_consent_log', + 'mokowaas_data_requests' => 'mokosuite_data_requests', + 'mokowaas_retention_policies' => 'mokosuite_retention_policies', + 'mokowaas_waf_log' => 'mokosuite_waf_log', + ]; + + try + { + $db = Factory::getDbo(); + $prefix = $db->getPrefix(); + $migrated = 0; + + foreach ($tableMap as $oldSuffix => $newSuffix) + { + $oldTable = $prefix . $oldSuffix; + $newTable = $prefix . $newSuffix; + + // Check if old table exists + $db->setQuery("SHOW TABLES LIKE " . $db->quote($oldTable)); + + if (!$db->loadResult()) + { + continue; + } + + // Create new table with same structure if it doesn't exist + $db->setQuery("SHOW TABLES LIKE " . $db->quote($newTable)); + + if (!$db->loadResult()) + { + $db->setQuery("CREATE TABLE " . $db->quoteName('#__' . $newSuffix) + . " LIKE " . $db->quoteName('#__' . $oldSuffix)); + $db->execute(); + } + + // Copy data from old to new (skip duplicates on primary key) + $db->setQuery("INSERT IGNORE INTO " . $db->quoteName('#__' . $newSuffix) + . " SELECT * FROM " . $db->quoteName('#__' . $oldSuffix)); + $db->execute(); + $copied = $db->getAffectedRows(); + + // Drop old table + $db->setQuery("DROP TABLE IF EXISTS " . $db->quoteName('#__' . $oldSuffix)); + $db->execute(); + + $migrated++; + + Log::add( + sprintf('Migrated table %s → %s (%d rows)', $oldSuffix, $newSuffix, $copied), + Log::INFO, + 'mokosuite' + ); + } + + if ($migrated > 0) + { + Factory::getApplication()->enqueueMessage( + sprintf('Migrated %d MokoWaaS database table(s) to MokoSuite naming.', $migrated), + 'message' + ); + } + } + catch (\Throwable $e) + { + Log::add('Table migration error: ' . $e->getMessage(), Log::WARNING, 'mokosuite'); + } + } }