saveDownloadKey(); return true; } public function postflight(string $type, InstallerAdapter $parent): void { $app = Factory::getApplication(); $app->enqueueMessage( 'MokoWaaS → MokoSuite Migration
' . 'Beginning migration from MokoWaaS to MokoSuite. ' . 'Downloading MokoSuite package...', 'notice' ); // Download the MokoSuite package $tmpPath = $app->get('tmp_path', sys_get_temp_dir()); $zipFile = $tmpPath . '/pkg_mokosuite_migration.zip'; // Append dlid if we have one $url = self::MOKOSUITE_URL; if ($this->savedDownloadKey) { $url .= (strpos($url, '?') === false ? '?' : '&') . $this->savedDownloadKey; } try { $http = \Joomla\CMS\Http\HttpFactory::getHttp(); $response = $http->get($url, [], 60); if ($response->code !== 200) { $app->enqueueMessage( 'Migration Failed — Could not download MokoSuite package (HTTP ' . $response->code . '). ' . 'Please install MokoSuite manually from the Joomla extension manager.', 'error' ); return; } file_put_contents($zipFile, $response->body); } catch (\Throwable $e) { $app->enqueueMessage( 'Migration Failed — Download error: ' . $e->getMessage() . '. ' . 'Please install MokoSuite manually.', 'error' ); return; } // Install the MokoSuite package (its postflight handles all migration) try { $installer = Installer::getInstance(); $result = $installer->install($zipFile); if ($result) { // Transfer the download key to the new MokoSuite update site $this->restoreDownloadKey(); $app->enqueueMessage( '
' . '

✓ Migration Complete!

' . '

' . 'Your MokoWaaS installation has been successfully migrated to MokoSuite.
' . '• All plugin settings have been preserved
' . '• Database tables have been migrated
' . '• Helpdesk tickets and data are intact
' . '• Your license key has been transferred

' . 'MokoWaaS extensions have been removed. Future updates will come from MokoSuite.' . '

', 'message' ); Log::add('MokoWaaS → MokoSuite migration completed successfully', Log::INFO, 'mokosuite'); } else { $app->enqueueMessage( 'Migration Warning — MokoSuite package install returned false. ' . 'Please check the Joomla installer log and install MokoSuite manually if needed.', 'warning' ); } } catch (\Throwable $e) { $app->enqueueMessage( 'Migration Failed — Install error: ' . $e->getMessage(), 'error' ); } finally { if (is_file($zipFile)) { @unlink($zipFile); } } } /** * Save the download key from whichever update site exists. */ private function saveDownloadKey(): void { try { $db = Factory::getDbo(); foreach (['pkg_mokosuite', 'pkg_mokowaas'] as $element) { $db->setQuery( $db->getQuery(true) ->select($db->quoteName('us.extra_query')) ->from($db->quoteName('#__update_sites', 'us')) ->join('INNER', $db->quoteName('#__update_sites_extensions', 'use') . ' ON use.update_site_id = us.update_site_id') ->join('INNER', $db->quoteName('#__extensions', 'e') . ' ON e.extension_id = use.extension_id') ->where($db->quoteName('e.element') . ' = ' . $db->quote($element)) ->setLimit(1) ); $key = $db->loadResult(); if (!empty($key) && strpos($key, 'dlid=') !== false) { $this->savedDownloadKey = $key; break; } } } catch (\Throwable $e) {} } /** * Copy the download key to the MokoSuite update site. */ private function restoreDownloadKey(): void { if ($this->savedDownloadKey === null) { return; } try { $db = Factory::getDbo(); $db->setQuery( $db->getQuery(true) ->select($db->quoteName('us.update_site_id')) ->from($db->quoteName('#__update_sites', 'us')) ->join('INNER', $db->quoteName('#__update_sites_extensions', 'use') . ' ON use.update_site_id = us.update_site_id') ->join('INNER', $db->quoteName('#__extensions', 'e') . ' ON e.extension_id = use.extension_id') ->where($db->quoteName('e.element') . ' = ' . $db->quote('pkg_mokosuite')) ->setLimit(1) ); $siteId = (int) $db->loadResult(); if ($siteId > 0) { $db->setQuery( $db->getQuery(true) ->update($db->quoteName('#__update_sites')) ->set($db->quoteName('extra_query') . ' = ' . $db->quote($this->savedDownloadKey)) ->where($db->quoteName('update_site_id') . ' = ' . $siteId) )->execute(); Log::add('Migrated download key to MokoSuite update site', Log::INFO, 'mokosuite'); } } catch (\Throwable $e) {} } }