Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions app/Controllers/PluginController.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,36 @@ public function index(Request $request, Response $response): Response

$plugins = $this->pluginManager->getAllPlugins();
$pluginSettings = [];
// Which plugins expose a settings page (so the list can show a generic
// "Impostazioni" button for ANY such plugin, not just a hardcoded few —
// otherwise e.g. the Mobile API gate is unreachable from the UI).
$pluginHasSettings = [];
foreach ($plugins as $plugin) {
$settings = $this->pluginManager->getSettings((int) $plugin['id']);

// Settings-page detection: only meaningful for active plugins (the
// instance must be loaded). Mirror the settings-route guard.
$hasSettingsPage = false;
if (!empty($plugin['is_active'])) {
try {
$instance = $this->pluginManager->getPluginInstance((int) $plugin['id']);
if ($instance !== null
&& is_callable([$instance, 'hasSettingsPage'])
&& $instance->hasSettingsPage()
&& is_callable([$instance, 'getSettingsViewPath'])
) {
// Mirror settingsPage()'s guard exactly: a declared view
// path that doesn't exist on disk must NOT surface a button
// (the click would 404).
$viewPath = $instance->getSettingsViewPath();
$hasSettingsPage = is_string($viewPath) && is_file($viewPath);
}
} catch (\Throwable $e) {
$hasSettingsPage = false;
}
}
$pluginHasSettings[$plugin['id']] = $hasSettingsPage;

// Handle Google Books API key
if (array_key_exists('google_books_api_key', $settings)) {
$settings['google_books_api_key_exists'] = $settings['google_books_api_key'] !== '';
Expand Down Expand Up @@ -300,6 +327,16 @@ public function updateSettings(Request $request, Response $response, array $args
return $response->withHeader('Content-Type', 'application/json')->withStatus(404);
}

// Self-rendering settings pages (e.g. Mobile API) post flat form fields and
// handle their OWN POST inside the view — CSRF, persistence via the plugin's
// saveSettings(), success message, re-render. The legacy AJAX handlers below
// require a nested `settings` payload; when it's absent, this is such a
// self-handling form, so render the settings page (which runs that logic)
// instead of falling through to "questo plugin non supporta impostazioni".
if (!is_array($body) || !array_key_exists('settings', $body)) {
return $this->settingsPage($request, $response, $args);
}

error_log('[PluginController] Plugin name: ' . $plugin['name']);

$settings = $body['settings'] ?? [];
Expand Down
12 changes: 11 additions & 1 deletion app/Views/admin/plugins.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

$pageTitle = __('Gestione Plugin');
$pluginSettings = $pluginSettings ?? [];
/** @var array<int,bool> $pluginHasSettings */
$pluginHasSettings = $pluginHasSettings ?? [];
?>

<div class="container mx-auto px-4 sm:px-6 lg:px-8 py-8">
Expand Down Expand Up @@ -296,7 +298,15 @@ class="px-4 py-2 bg-purple-100 text-purple-700 rounded-lg hover:bg-purple-200 tr
<?= __("Configura Fonti") ?>
</button>
<?php endif; ?>
<?php if ($plugin['name'] === 'discogs'): ?>
<?php
// Generic settings button: shown for ANY active plugin that exposes
// a settings page and isn't already handled by a custom button above
// (open-library / api-book-scraper / goodlib use their own modals).
// Without this, plugins like Mobile API have a working settings page
// (/admin/plugins/{id}/settings) that is unreachable from the UI.
$hasCustomSettingsButton = $isOpenLibrary || $isApiBookScraper || $isGoodLib;
?>
<?php if (!$hasCustomSettingsButton && !empty($pluginHasSettings[$plugin['id']])): ?>
<a href="<?= htmlspecialchars(url('/admin/plugins') . '/' . (int) $plugin['id'] . '/settings', ENT_QUOTES, 'UTF-8') ?>"
class="px-4 py-2 bg-indigo-100 text-indigo-700 rounded-lg hover:bg-indigo-200 transition-all duration-200 text-sm font-medium inline-flex items-center">
<i class="fas fa-cog mr-1"></i>
Expand Down
Loading