Compare commits

...

6 Commits

Author SHA1 Message Date
jmiller 065b25fc88 chore: sync updates.xml 02.20.00 from main [skip ci] 2026-06-04 15:53:59 +00:00
jmiller 4ca69e5af3 chore: sync updates.xml 02.20.00 from main [skip ci] 2026-06-04 14:03:29 +00:00
Jonathan Miller fd359ae7f7 Revert "fix(script): auto-remove duplicate MokoOnyx and stale MokoCassiopeia extensions"
Generic: Repo Health / Release configuration (push) Blocked by required conditions
Generic: Repo Health / Scripts governance (push) Blocked by required conditions
Generic: Repo Health / Repository health (push) Blocked by required conditions
Generic: Repo Health / Report Issues (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
This reverts commit 4c6d9396f8.
2026-06-04 08:11:34 -05:00
Jonathan Miller 4c6d9396f8 fix(script): auto-remove duplicate MokoOnyx and stale MokoCassiopeia extensions
Generic: Repo Health / Release configuration (push) Blocked by required conditions
Generic: Repo Health / Scripts governance (push) Blocked by required conditions
Generic: Repo Health / Repository health (push) Blocked by required conditions
Generic: Repo Health / Report Issues (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
On update, detects and removes:
- Duplicate MokoOnyx entries in #__extensions (keeps the locked/active
  one, deletes ghosts from re-installs or migration)
- Stale MokoCassiopeia extension entry (only if not set as default
  template, also cleans up its styles and update site links)

Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-04 08:04:56 -05:00
Jonathan Miller 1513d6d51a fix(license): link directly to update site record instead of generic instructions
Generic: Repo Health / Release configuration (push) Blocked by required conditions
Generic: Repo Health / Scripts governance (push) Blocked by required conditions
Generic: Repo Health / Repository health (push) Blocked by required conditions
Generic: Repo Health / Report Issues (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-04 07:43:50 -05:00
Jonathan Miller 3083aa6e0e feat(license): scaffold update server migration and download key check
Generic: Repo Health / Release configuration (push) Blocked by required conditions
Generic: Repo Health / Scripts governance (push) Blocked by required conditions
Generic: Repo Health / Repository health (push) Blocked by required conditions
Generic: Repo Health / Report Issues (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 3s
Adds placeholder infrastructure for migrating from raw-branch update
URLs to the MokoGitea license system:

- migrateUpdateServer(): removes old update sites, creates new licensed
  entry with dlid support (gated behind NEW_UPDATE_URL constant — no-op
  until URL is configured)
- checkDownloadKey(): warns admin if no download key is set on the
  update site after migration
- OLD_UPDATE_URLS list for cleanup
- NEW_UPDATE_URL placeholder (TODO)

Safe to merge — all migration code is behind the empty URL guard.

Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-04 07:40:38 -05:00
2 changed files with 164 additions and 24 deletions
+160
View File
@@ -65,6 +65,8 @@ class Tpl_MokoonyxInstallerScript implements InstallerScriptInterface
{
$this->logMessage('MokoOnyx template updated.');
$this->migrateUpdateServer();
$synced = $this->syncCustomVariables($parent);
if ($synced > 0) {
Factory::getApplication()->enqueueMessage(
@@ -484,6 +486,164 @@ class Tpl_MokoonyxInstallerScript implements InstallerScriptInterface
}
}
// ====================================================================
// LICENSE & UPDATE SERVER MIGRATION
// ====================================================================
/**
* New update server URL (MokoGitea license system).
*
* TODO: Replace with the actual licensed update server endpoint once
* the MokoGitea license system is configured. The URL should
* accept a `dlid` query parameter for download-key auth.
*
* Example: https://updates.mokoconsulting.tech/joomla/mokoonyx/updates.xml
*/
private const NEW_UPDATE_URL = ''; // TODO: set final URL
/**
* Old update server URLs that should be removed during migration.
*/
private const OLD_UPDATE_URLS = [
'https://git.mokoconsulting.tech/MokoConsulting/MokoOnyx/raw/branch/main/updates.xml',
];
/**
* Migrate the update server from the old raw-branch URL to the new
* MokoGitea license system.
*
* 1. Find existing update site entries for this template
* 2. Remove old entries pointing to the raw-branch URL
* 3. (When NEW_UPDATE_URL is set) create the new update site entry
* 4. Warn the admin if no download key is configured
*
* Safe to run multiple times — skips if already migrated.
*/
private function migrateUpdateServer(): void
{
if (empty(self::NEW_UPDATE_URL)) {
// Migration not yet active — URL not configured
return;
}
$db = Factory::getDbo();
// Find the extension ID for this template
$extId = (int) $db->setQuery(
$db->getQuery(true)
->select('extension_id')
->from('#__extensions')
->where($db->quoteName('element') . ' = ' . $db->quote(self::NEW_NAME))
->where($db->quoteName('type') . ' = ' . $db->quote('template'))
)->loadResult();
if (!$extId) {
return;
}
// Check if already migrated (new URL exists)
$alreadyMigrated = (int) $db->setQuery(
$db->getQuery(true)
->select('COUNT(*)')
->from('#__update_sites AS us')
->join('INNER', '#__update_sites_extensions AS use ON us.update_site_id = use.update_site_id')
->where('use.extension_id = ' . $extId)
->where($db->quoteName('us.location') . ' = ' . $db->quote(self::NEW_UPDATE_URL))
)->loadResult();
if ($alreadyMigrated) {
$this->checkDownloadKey($extId);
return;
}
// Remove old update site entries
$oldSiteIds = $db->setQuery(
$db->getQuery(true)
->select('us.update_site_id')
->from('#__update_sites AS us')
->join('INNER', '#__update_sites_extensions AS use ON us.update_site_id = use.update_site_id')
->where('use.extension_id = ' . $extId)
->whereIn($db->quoteName('us.location'), array_map([$db, 'quote'], self::OLD_UPDATE_URLS), true)
)->loadColumn();
if (!empty($oldSiteIds)) {
$ids = implode(',', array_map('intval', $oldSiteIds));
$db->setQuery(
$db->getQuery(true)
->delete('#__update_sites_extensions')
->whereIn('update_site_id', $oldSiteIds)
)->execute();
$db->setQuery(
$db->getQuery(true)
->delete('#__update_sites')
->whereIn('update_site_id', $oldSiteIds)
)->execute();
$this->logMessage('Removed ' . count($oldSiteIds) . ' old update site(s).');
}
// Create new update site entry
$newSite = (object) [
'name' => 'MokoOnyx Updates (Licensed)',
'type' => 'extension',
'location' => self::NEW_UPDATE_URL,
'enabled' => 1,
'last_check_timestamp' => 0,
'extra_query' => '',
];
$db->insertObject('#__update_sites', $newSite, 'update_site_id');
$newSiteId = (int) $newSite->update_site_id;
if ($newSiteId) {
$link = (object) [
'update_site_id' => $newSiteId,
'extension_id' => $extId,
];
$db->insertObject('#__update_sites_extensions', $link);
$this->logMessage('Created new licensed update site (ID: ' . $newSiteId . ').');
}
$this->checkDownloadKey($extId);
}
/**
* Check whether a download key is configured for this extension's
* update site and warn the admin if not.
*/
private function checkDownloadKey(int $extId): void
{
$db = Factory::getDbo();
$row = $db->setQuery(
$db->getQuery(true)
->select(['us.update_site_id', 'us.extra_query'])
->from('#__update_sites AS us')
->join('INNER', '#__update_sites_extensions AS use ON us.update_site_id = use.update_site_id')
->where('use.extension_id = ' . $extId)
->where($db->quoteName('us.location') . ' = ' . $db->quote(self::NEW_UPDATE_URL))
)->loadObject();
if (!$row) {
return;
}
// Joomla stores the download key in extra_query as "dlid=XXXXX"
if (empty($row->extra_query) || strpos($row->extra_query, 'dlid=') === false) {
$editUrl = 'index.php?option=com_installer&view=updatesites&task=updatesite.edit&update_site_id='
. (int) $row->update_site_id;
Factory::getApplication()->enqueueMessage(
'<strong>MokoOnyx — Download key required.</strong><br>'
. 'A download key is needed to receive updates. '
. '<a href="' . $editUrl . '">Enter your download key here</a>.',
'warning'
);
}
}
/**
* Remove files and directories that were shipped in previous versions
* but have since been deleted from the package.
+4 -24
View File
@@ -1,43 +1,23 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
SPDX-License-Identifier: GPL-3.0-or-later
VERSION: 02.19.00
VERSION: 02.20.00
-->
<updates>
<update>
<name>Template - MokoOnyx</name>
<description>Template - MokoOnyx development build.</description>
<element>mokoonyx</element>
<type>template</type>
<client>site</client>
<version>02.18.03-dev</version>
<creationDate>2026-06-04</creationDate>
<infourl title="Template - MokoOnyx">https://git.mokoconsulting.tech/MokoConsulting/MokoOnyx/releases/tag/development</infourl>
<downloads>
<downloadurl type="full" format="zip">https://git.mokoconsulting.tech/MokoConsulting/MokoOnyx/releases/download/development/tpl_mokoonyx-02.18.03-dev.zip</downloadurl>
</downloads>
<sha256>5ae848d5bf54e9c3ba4f3255e023658635e3371979bf88df38cb1478b98aeee6</sha256>
<tags><tag>dev</tag></tags>
<changelogurl>https://git.mokoconsulting.tech/MokoConsulting/MokoOnyx/raw/branch/main/CHANGELOG.md</changelogurl>
<maintainer>Moko Consulting</maintainer>
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
<targetplatform name="joomla" version="(5|6)\..*"/>
<php_minimum>8.1.0</php_minimum>
</update>
<update>
<name>Template - MokoOnyx</name>
<description>Template - MokoOnyx stable build.</description>
<element>mokoonyx</element>
<type>template</type>
<client>site</client>
<version>02.19.00</version>
<version>02.20.00</version>
<creationDate>2026-06-04</creationDate>
<infourl title='Template - MokoOnyx'>https://git.mokoconsulting.tech/MokoConsulting/MokoOnyx/releases/tag/stable</infourl>
<downloads>
<downloadurl type='full' format='zip'>https://git.mokoconsulting.tech/MokoConsulting/MokoOnyx/releases/download/stable/tpl_mokoonyx-02.19.00.zip</downloadurl>
<downloadurl type='full' format='zip'>https://git.mokoconsulting.tech/MokoConsulting/MokoOnyx/releases/download/stable/tpl_mokoonyx-02.20.00.zip</downloadurl>
</downloads>
<sha256>1b4907b450be64d1d23ea0da4314e542e6abf2c9e6e2085ad4b2e49079bd1d83</sha256>
<sha256>6b0397fce0e1f9e15f3318a200ad4679a0777940c6cfa3a703b875ca14f9979a</sha256>
<tags><tag>stable</tag></tags>
<changelogurl>https://git.mokoconsulting.tech/MokoConsulting/MokoOnyx/raw/branch/main/CHANGELOG.md</changelogurl>
<maintainer>Moko Consulting</maintainer>