Files
MokoSuite/source/packages/com_mokosuite/api/src/Controller/ExtensionsController.php
T
Jonathan Miller 00d44256b4 refactor: rename MokoWaaS to MokoSuite across entire codebase
Rebrand all 17 sub-extensions from mokowaas to mokosuite naming,
including component, plugins, modules, task plugins, and webservices.
Updates package manifest, workflows, docs, wiki, and issue templates.
Adds new plg_system_mokosuite_license extension.
2026-06-07 09:25:45 -05:00

188 lines
5.0 KiB
PHP

<?php
/**
* @package MokoSuite
* @subpackage com_mokosuite
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
* @license GNU General Public License version 3 or later; see LICENSE
*/
namespace Moko\Component\MokoSuite\Api\Controller;
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\MVC\Controller\BaseController;
/**
* Extensions list API controller.
*
* GET /api/index.php/v1/mokosuite/extensions
*
* Returns all installed extensions with type, element, folder, version,
* enabled/protected/locked status, and update server info.
*
* Optional filters via query params:
* ?type=plugin — filter by extension type
* ?search=moko — search name or element
* ?enabled=1 — only enabled/disabled
*
* @since 02.21.00
*/
class ExtensionsController extends BaseController
{
/**
* List installed extensions.
*
* @return void
*
* @since 02.21.00
*/
public function displayList(): void
{
$app = Factory::getApplication();
$user = $app->getIdentity();
if (!$user->authorise('core.manage', 'com_installer'))
{
$this->sendJson(403, ['error' => 'Not authorized — requires core.manage on com_installer']);
return;
}
try
{
$db = Factory::getDbo();
$query = $db->getQuery(true)
->select([
$db->quoteName('e.extension_id'),
$db->quoteName('e.name'),
$db->quoteName('e.type'),
$db->quoteName('e.element'),
$db->quoteName('e.folder'),
$db->quoteName('e.client_id'),
$db->quoteName('e.enabled'),
$db->quoteName('e.protected'),
$db->quoteName('e.locked'),
$db->quoteName('e.manifest_cache'),
])
->from($db->quoteName('#__extensions', 'e'))
->order($db->quoteName('e.type') . ' ASC, ' . $db->quoteName('e.name') . ' ASC');
// Filter by type
$typeFilter = $app->input->get('type', '', 'CMD');
if ($typeFilter !== '')
{
$query->where($db->quoteName('e.type') . ' = ' . $db->quote($typeFilter));
}
// Filter by enabled
$enabledFilter = $app->input->get('enabled', '', 'CMD');
if ($enabledFilter !== '')
{
$query->where($db->quoteName('e.enabled') . ' = ' . (int) $enabledFilter);
}
// Search name or element
$search = $app->input->get('search', '', 'STRING');
if ($search !== '')
{
$searchQuoted = $db->quote('%' . $db->escape($search, true) . '%');
$query->where(
'(' . $db->quoteName('e.name') . ' LIKE ' . $searchQuoted
. ' OR ' . $db->quoteName('e.element') . ' LIKE ' . $searchQuoted . ')'
);
}
$db->setQuery($query);
$rows = $db->loadAssocList();
// Get update sites for cross-reference
$usQuery = $db->getQuery(true)
->select([
$db->quoteName('us.update_site_id'),
$db->quoteName('us.name', 'site_name'),
$db->quoteName('us.location'),
$db->quoteName('us.enabled', 'site_enabled'),
$db->quoteName('usm.extension_id'),
])
->from($db->quoteName('#__update_sites', 'us'))
->innerJoin(
$db->quoteName('#__update_sites_extensions', 'usm')
. ' ON ' . $db->quoteName('us.update_site_id')
. ' = ' . $db->quoteName('usm.update_site_id')
);
$db->setQuery($usQuery);
$updateSites = [];
foreach ($db->loadAssocList() ?: [] as $us)
{
$updateSites[(int) $us['extension_id']] = [
'name' => $us['site_name'],
'location' => $us['location'],
'enabled' => (bool) $us['site_enabled'],
];
}
// Build response
$extensions = [];
foreach ($rows as $row)
{
$manifest = json_decode($row['manifest_cache'] ?: '{}', true);
$extId = (int) $row['extension_id'];
$ext = [
'extension_id' => $extId,
'name' => $row['name'],
'type' => $row['type'],
'element' => $row['element'],
'folder' => $row['folder'] ?: null,
'client_id' => (int) $row['client_id'],
'enabled' => (bool) $row['enabled'],
'protected' => (bool) $row['protected'],
'locked' => (bool) $row['locked'],
'version' => $manifest['version'] ?? null,
'author' => $manifest['author'] ?? null,
'description' => $manifest['description'] ?? null,
];
if (isset($updateSites[$extId]))
{
$ext['update_server'] = $updateSites[$extId];
}
$extensions[] = $ext;
}
$this->sendJson(200, [
'status' => 'ok',
'count' => count($extensions),
'extensions' => $extensions,
]);
}
catch (\Throwable $e)
{
$this->sendJson(500, [
'error' => 'Failed to list extensions',
'message' => $e->getMessage(),
]);
}
}
/**
* @param int $code HTTP status code
* @param array $payload Response data
* @return void
*/
private function sendJson(int $code, array $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 | JSON_PRETTY_PRINT);
$app->close();
}
}