Files
MokoWaaS/source/packages/com_mokowaas/api/src/Controller/PluginsController.php
T
Jonathan Miller e3c15979b8
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 2s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Blocked by required conditions
Platform: moko-platform CI / CI Summary (pull_request) Blocked by required conditions
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Universal: PR Check / Report Issues (pull_request) Blocked by required conditions
Generic: Repo Health / Scripts governance (pull_request) Blocked by required conditions
Generic: Repo Health / Repository health (pull_request) Blocked by required conditions
Generic: Repo Health / Report Issues (pull_request) Blocked by required conditions
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 21s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 26s
Branch Cleanup / Delete merged branch (pull_request) Successful in 2s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || 'development' }}) (pull_request) Failing after 7s
chore: rename src/ to source/ per moko-platform standards (#188)
Rename top-level src/ directory to source/ and update all references
in .gitignore, CLAUDE.md, manifest.xml, docs, and PATH comments.
Internal namespace path="src" attributes within extension packages
are unchanged (they refer to the package-internal src/ folder).

Closes #188

Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-06 07:43:59 -05:00

181 lines
5.0 KiB
PHP

<?php
/**
* @package MokoWaaS
* @subpackage com_mokowaas
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
* @license GNU General Public License version 3 or later; see LICENSE
*/
namespace Moko\Component\MokoWaaS\Api\Controller;
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\MVC\Controller\BaseController;
/**
* Feature plugins API controller.
*
* GET /api/index.php/v1/mokowaas/plugins — list MokoWaaS plugins + status
* POST /api/index.php/v1/mokowaas/plugins/toggle — enable/disable a feature plugin
*
* @since 02.32.00
*/
class PluginsController extends BaseController
{
/**
* List all MokoWaaS feature plugins with their enabled state.
*
* @return void
*/
public function displayList(): void
{
$app = Factory::getApplication();
$user = $app->getIdentity();
if (!$user->authorise('core.manage', 'com_plugins'))
{
$this->sendJson(403, ['error' => 'Not authorized']);
return;
}
$db = Factory::getDbo();
$query = $db->getQuery(true)
->select([
$db->quoteName('extension_id'),
$db->quoteName('name'),
$db->quoteName('element'),
$db->quoteName('folder'),
$db->quoteName('type'),
$db->quoteName('enabled'),
$db->quoteName('protected'),
$db->quoteName('manifest_cache'),
])
->from($db->quoteName('#__extensions'))
->where([
'(' .
'(' . $db->quoteName('type') . ' = ' . $db->quote('plugin')
. ' AND ' . $db->quoteName('folder') . ' = ' . $db->quote('system')
. ' AND (' . $db->quoteName('element') . ' = ' . $db->quote('mokowaas')
. ' OR ' . $db->quoteName('element') . ' LIKE ' . $db->quote('mokowaas\\_%') . '))'
. ' OR (' . $db->quoteName('type') . ' = ' . $db->quote('plugin')
. ' AND ' . $db->quoteName('folder') . ' = ' . $db->quote('webservices')
. ' AND ' . $db->quoteName('element') . ' = ' . $db->quote('mokowaas') . ')'
. ' OR (' . $db->quoteName('type') . ' = ' . $db->quote('plugin')
. ' AND ' . $db->quoteName('folder') . ' = ' . $db->quote('task')
. ' AND ' . $db->quoteName('element') . ' LIKE ' . $db->quote('mokowaas%') . ')'
. ')',
])
->order($db->quoteName('folder') . ' ASC, ' . $db->quoteName('element') . ' ASC');
$db->setQuery($query);
$rows = $db->loadObjectList() ?: [];
$plugins = [];
foreach ($rows as $row)
{
$manifest = json_decode($row->manifest_cache ?? '{}');
$plugins[] = [
'extension_id' => (int) $row->extension_id,
'name' => $row->name,
'element' => $row->element,
'folder' => $row->folder,
'type' => $row->type,
'enabled' => (bool) $row->enabled,
'protected' => (bool) $row->protected,
'version' => $manifest->version ?? '',
];
}
$this->sendJson(200, [
'status' => 'ok',
'count' => \count($plugins),
'plugins' => $plugins,
]);
}
/**
* Toggle a MokoWaaS feature plugin on or off.
*
* Expects JSON body: {"extension_id": 123, "enabled": true}
*
* @return void
*/
public function execute($task = 'plugins'): void
{
$app = Factory::getApplication();
$user = $app->getIdentity();
if (!$user->authorise('core.manage', 'com_plugins'))
{
$this->sendJson(403, ['error' => 'Not authorized']);
return;
}
$input = json_decode(file_get_contents('php://input'), true);
$extensionId = (int) ($input['extension_id'] ?? 0);
$enabled = (bool) ($input['enabled'] ?? false);
if (!$extensionId)
{
$this->sendJson(400, ['error' => 'Missing extension_id']);
return;
}
$db = Factory::getDbo();
// Verify the extension exists and is a MokoWaaS plugin
$query = $db->getQuery(true)
->select([$db->quoteName('element'), $db->quoteName('protected')])
->from($db->quoteName('#__extensions'))
->where($db->quoteName('extension_id') . ' = ' . $extensionId)
->where($db->quoteName('type') . ' = ' . $db->quote('plugin'));
$db->setQuery($query);
$ext = $db->loadObject();
if (!$ext)
{
$this->sendJson(404, ['error' => 'Extension not found']);
return;
}
// Don't allow disabling protected/core plugins
if (!$enabled && ((int) $ext->protected || $ext->element === 'mokowaas'))
{
$this->sendJson(409, ['error' => 'This plugin is protected and cannot be disabled']);
return;
}
$query = $db->getQuery(true)
->update($db->quoteName('#__extensions'))
->set($db->quoteName('enabled') . ' = ' . ($enabled ? 1 : 0))
->where($db->quoteName('extension_id') . ' = ' . $extensionId);
$db->setQuery($query);
$db->execute();
$this->sendJson(200, [
'status' => 'ok',
'extension_id' => $extensionId,
'element' => $ext->element,
'enabled' => $enabled,
]);
}
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();
}
}