feat(plugins): abstract settings form for general, podcast and episode types

update filter permission logic for replacing router param
This commit is contained in:
Yassine Doghri 2024-05-13 16:17:18 +00:00
parent 8917bdb655
commit adbc7e78c0
19 changed files with 236 additions and 309 deletions

View File

@ -231,7 +231,7 @@ $routes->get('/pages/(:slug)', 'PageController::index/$1', [
$routes->group('@(:podcastHandle)', static function ($routes): void {
$routes->post('posts/new', 'PostController::attemptCreate/$1', [
'as' => 'post-attempt-create',
'filter' => 'permission:podcast#.manage-publications',
'filter' => 'permission:podcast$1.manage-publications',
]);
// Post
$routes->group('posts/(:uuid)', static function ($routes): void {
@ -268,7 +268,7 @@ $routes->group('@(:podcastHandle)', static function ($routes): void {
// Actions
$routes->post('action', 'PostController::attemptAction/$1/$2', [
'as' => 'post-attempt-action',
'filter' => 'permission:podcast#.interact-as',
'filter' => 'permission:podcast$1.interact-as',
]);
$routes->post(
'block-actor',
@ -288,7 +288,7 @@ $routes->group('@(:podcastHandle)', static function ($routes): void {
);
$routes->post('delete', 'PostController::attemptDelete/$1/$2', [
'as' => 'post-attempt-delete',
'filter' => 'permission:podcast#.manage-publications',
'filter' => 'permission:podcast$1.manage-publications',
]);
$routes->get(
'remote/(:postAction)',

View File

@ -26,7 +26,7 @@ if (! function_exists('render_breadcrumb')) {
if (! function_exists('replace_breadcrumb_params')) {
/**
* @param string[] $newParams
* @param array<string|int,string> $newParams
*/
function replace_breadcrumb_params(array $newParams): void
{

View File

@ -58,7 +58,7 @@ class Breadcrumb
*
* The breadcrumb is now `Home / podcasts / foo / episodes / bar / I Pity The Foo`
*
* @param string[] $newParams
* @param array<string|int,string> $newParams
*/
public function replaceParams(array $newParams): void
{

View File

@ -101,28 +101,28 @@ $routes->group(
$routes->group('(:num)', static function ($routes): void {
$routes->get('/', 'PodcastController::view/$1', [
'as' => 'podcast-view',
'filter' => 'permission:podcast#.view',
'filter' => 'permission:podcast$1.view',
]);
$routes->get('edit', 'PodcastController::edit/$1', [
'as' => 'podcast-edit',
'filter' => 'permission:podcast#.edit',
'filter' => 'permission:podcast$1.edit',
]);
$routes->post('edit', 'PodcastController::attemptEdit/$1', [
'filter' => 'permission:podcast#.edit',
'filter' => 'permission:podcast$1.edit',
]);
$routes->get(
'publish',
'PodcastController::publish/$1',
[
'as' => 'podcast-publish',
'filter' => 'permission:podcast#.manage-publications',
'filter' => 'permission:podcast$1.manage-publications',
],
);
$routes->post(
'publish',
'PodcastController::attemptPublish/$1',
[
'filter' => 'permission:podcast#.manage-publications',
'filter' => 'permission:podcast$1.manage-publications',
],
);
$routes->get(
@ -130,14 +130,14 @@ $routes->group(
'PodcastController::publishEdit/$1',
[
'as' => 'podcast-publish_edit',
'filter' => 'permission:podcast#.manage-publications',
'filter' => 'permission:podcast$1.manage-publications',
],
);
$routes->post(
'publish-edit',
'PodcastController::attemptPublishEdit/$1',
[
'filter' => 'permission:podcast#.manage-publications',
'filter' => 'permission:podcast$1.manage-publications',
],
);
$routes->get(
@ -145,30 +145,30 @@ $routes->group(
'PodcastController::publishCancel/$1',
[
'as' => 'podcast-publish-cancel',
'filter' => 'permission:podcast#.manage-publications',
'filter' => 'permission:podcast$1.manage-publications',
],
);
$routes->get('edit/delete-banner', 'PodcastController::deleteBanner/$1', [
'as' => 'podcast-banner-delete',
'filter' => 'permission:podcast#.edit',
'filter' => 'permission:podcast$1.edit',
]);
$routes->get('delete', 'PodcastController::delete/$1', [
'as' => 'podcast-delete',
'filter' => 'permission:podcast#.delete',
'filter' => 'permission:podcast$1.delete',
]);
$routes->post('delete', 'PodcastController::attemptDelete/$1', [
'filter' => 'permission:podcast#.delete',
'filter' => 'permission:podcast$1.delete',
]);
$routes->group('persons', static function ($routes): void {
$routes->get('/', 'PodcastPersonController::index/$1', [
'as' => 'podcast-persons-manage',
'filter' => 'permission:podcast#.manage-persons',
'filter' => 'permission:podcast$1.manage-persons',
]);
$routes->post(
'/',
'PodcastPersonController::attemptCreate/$1',
[
'filter' => 'permission:podcast#.manage-persons',
'filter' => 'permission:podcast$1.manage-persons',
],
);
$routes->get(
@ -176,29 +176,29 @@ $routes->group(
'PodcastPersonController::remove/$1/$2',
[
'as' => 'podcast-person-remove',
'filter' => 'permission:podcast#.manage-persons',
'filter' => 'permission:podcast$1.manage-persons',
],
);
});
$routes->get('monetization-other', 'PodcastController::monetizationOther/$1', [
'as' => 'podcast-monetization-other',
'filter' => 'permission:podcast#.edit',
'filter' => 'permission:podcast$1.edit',
]);
$routes->post('monetization-other', 'PodcastController::monetizationOtherAction/$1', [
'as' => 'podcast-monetization-other',
'filter' => 'permission:podcast#.edit',
'filter' => 'permission:podcast$1.edit',
]);
$routes->group('analytics', static function ($routes): void {
$routes->get('/', 'PodcastController::viewAnalytics/$1', [
'as' => 'podcast-analytics',
'filter' => 'permission:podcast#.view',
'filter' => 'permission:podcast$1.view',
]);
$routes->get(
'webpages',
'PodcastController::viewAnalyticsWebpages/$1',
[
'as' => 'podcast-analytics-webpages',
'filter' => 'permission:podcast#.view',
'filter' => 'permission:podcast$1.view',
],
);
$routes->get(
@ -206,7 +206,7 @@ $routes->group(
'PodcastController::viewAnalyticsLocations/$1',
[
'as' => 'podcast-analytics-locations',
'filter' => 'permission:podcast#.view',
'filter' => 'permission:podcast$1.view',
],
);
$routes->get(
@ -214,7 +214,7 @@ $routes->group(
'PodcastController::viewAnalyticsUniqueListeners/$1',
[
'as' => 'podcast-analytics-unique-listeners',
'filter' => 'permission:podcast#.view',
'filter' => 'permission:podcast$1.view',
],
);
$routes->get(
@ -222,7 +222,7 @@ $routes->group(
'PodcastController::viewAnalyticsListeningTime/$1',
[
'as' => 'podcast-analytics-listening-time',
'filter' => 'permission:podcast#.view',
'filter' => 'permission:podcast$1.view',
],
);
$routes->get(
@ -230,7 +230,7 @@ $routes->group(
'PodcastController::viewAnalyticsTimePeriods/$1',
[
'as' => 'podcast-analytics-time-periods',
'filter' => 'permission:podcast#.view',
'filter' => 'permission:podcast$1.view',
],
);
$routes->get(
@ -238,7 +238,7 @@ $routes->group(
'PodcastController::viewAnalyticsPlayers/$1',
[
'as' => 'podcast-analytics-players',
'filter' => 'permission:podcast#.view',
'filter' => 'permission:podcast$1.view',
],
);
});
@ -246,34 +246,34 @@ $routes->group(
$routes->group('episodes', static function ($routes): void {
$routes->get('/', 'EpisodeController::list/$1', [
'as' => 'episode-list',
'filter' => 'permission:podcast#.episodes.view',
'filter' => 'permission:podcast$1.episodes.view',
]);
$routes->get('new', 'EpisodeController::create/$1', [
'as' => 'episode-create',
'filter' => 'permission:podcast#.episodes.create',
'filter' => 'permission:podcast$1.episodes.create',
]);
$routes->post(
'new',
'EpisodeController::attemptCreate/$1',
[
'filter' => 'permission:podcast#.episodes.create',
'filter' => 'permission:podcast$1.episodes.create',
],
);
// Episode
$routes->group('(:num)', static function ($routes): void {
$routes->get('/', 'EpisodeController::view/$1/$2', [
'as' => 'episode-view',
'filter' => 'permission:podcast#.episodes.view',
'filter' => 'permission:podcast$1.episodes.view',
]);
$routes->get('edit', 'EpisodeController::edit/$1/$2', [
'as' => 'episode-edit',
'filter' => 'permission:podcast#.episodes.edit',
'filter' => 'permission:podcast$1.episodes.edit',
]);
$routes->post(
'edit',
'EpisodeController::attemptEdit/$1/$2',
[
'filter' => 'permission:podcast#.episodes.edit',
'filter' => 'permission:podcast$1.episodes.edit',
],
);
$routes->get(
@ -281,14 +281,14 @@ $routes->group(
'EpisodeController::publish/$1/$2',
[
'as' => 'episode-publish',
'filter' => 'permission:podcast#.episodes.manage-publications',
'filter' => 'permission:podcast$1.episodes.manage-publications',
],
);
$routes->post(
'publish',
'EpisodeController::attemptPublish/$1/$2',
[
'filter' => 'permission:podcast#.episodes.manage-publications',
'filter' => 'permission:podcast$1.episodes.manage-publications',
],
);
$routes->get(
@ -296,14 +296,14 @@ $routes->group(
'EpisodeController::publishEdit/$1/$2',
[
'as' => 'episode-publish_edit',
'filter' => 'permission:podcast#.episodes.manage-publications',
'filter' => 'permission:podcast$1.episodes.manage-publications',
],
);
$routes->post(
'publish-edit',
'EpisodeController::attemptPublishEdit/$1/$2',
[
'filter' => 'permission:podcast#.episodes.manage-publications',
'filter' => 'permission:podcast$1.episodes.manage-publications',
],
);
$routes->get(
@ -311,7 +311,7 @@ $routes->group(
'EpisodeController::publishCancel/$1/$2',
[
'as' => 'episode-publish-cancel',
'filter' => 'permission:podcast#.episodes.manage-publications',
'filter' => 'permission:podcast$1.episodes.manage-publications',
],
);
$routes->get(
@ -319,14 +319,14 @@ $routes->group(
'EpisodeController::publishDateEdit/$1/$2',
[
'as' => 'episode-publish_date_edit',
'filter' => 'permission:podcast#.episodes.manage-publications',
'filter' => 'permission:podcast$1.episodes.manage-publications',
],
);
$routes->post(
'publish-date-edit',
'EpisodeController::attemptPublishDateEdit/$1/$2',
[
'filter' => 'permission:podcast#.episodes.manage-publications',
'filter' => 'permission:podcast$1.episodes.manage-publications',
],
);
$routes->get(
@ -334,14 +334,14 @@ $routes->group(
'EpisodeController::unpublish/$1/$2',
[
'as' => 'episode-unpublish',
'filter' => 'permission:podcast#.episodes.manage-publications',
'filter' => 'permission:podcast$1.episodes.manage-publications',
],
);
$routes->post(
'unpublish',
'EpisodeController::attemptUnpublish/$1/$2',
[
'filter' => 'permission:podcast#.episodes.manage-publications',
'filter' => 'permission:podcast$1.episodes.manage-publications',
],
);
$routes->get(
@ -349,14 +349,14 @@ $routes->group(
'EpisodeController::delete/$1/$2',
[
'as' => 'episode-delete',
'filter' => 'permission:podcast#.episodes.delete',
'filter' => 'permission:podcast$1.episodes.delete',
],
);
$routes->post(
'delete',
'EpisodeController::attemptDelete/$1/$2',
[
'filter' => 'permission:podcast#.episodes.delete',
'filter' => 'permission:podcast$1.episodes.delete',
],
);
$routes->get(
@ -364,7 +364,7 @@ $routes->group(
'EpisodeController::transcriptDelete/$1/$2',
[
'as' => 'transcript-delete',
'filter' => 'permission:podcast#.episodes.edit',
'filter' => 'permission:podcast$1.episodes.edit',
],
);
$routes->get(
@ -372,7 +372,7 @@ $routes->group(
'EpisodeController::chaptersDelete/$1/$2',
[
'as' => 'chapters-delete',
'filter' => 'permission:podcast#.episodes.edit',
'filter' => 'permission:podcast$1.episodes.edit',
],
);
$routes->get(
@ -380,7 +380,7 @@ $routes->group(
'SoundbiteController::list/$1/$2',
[
'as' => 'soundbites-list',
'filter' => 'permission:podcast#.episodes.manage-clips',
'filter' => 'permission:podcast$1.episodes.manage-clips',
],
);
$routes->get(
@ -388,7 +388,7 @@ $routes->group(
'SoundbiteController::create/$1/$2',
[
'as' => 'soundbites-create',
'filter' => 'permission:podcast#.episodes.manage-clips',
'filter' => 'permission:podcast$1.episodes.manage-clips',
],
);
$routes->post(
@ -396,7 +396,7 @@ $routes->group(
'SoundbiteController::attemptCreate/$1/$2',
[
'as' => 'soundbites-create',
'filter' => 'permission:podcast#.episodes.manage-clips',
'filter' => 'permission:podcast$1.episodes.manage-clips',
],
);
$routes->get(
@ -404,7 +404,7 @@ $routes->group(
'SoundbiteController::delete/$1/$2/$3',
[
'as' => 'soundbites-delete',
'filter' => 'permission:podcast#.episodes.manage-clips',
'filter' => 'permission:podcast$1.episodes.manage-clips',
],
);
$routes->get(
@ -412,7 +412,7 @@ $routes->group(
'VideoClipsController::list/$1/$2',
[
'as' => 'video-clips-list',
'filter' => 'permission:podcast#.episodes.manage-clips',
'filter' => 'permission:podcast$1.episodes.manage-clips',
],
);
$routes->get(
@ -420,7 +420,7 @@ $routes->group(
'VideoClipsController::create/$1/$2',
[
'as' => 'video-clips-create',
'filter' => 'permission:podcast#.episodes.manage-clips',
'filter' => 'permission:podcast$1.episodes.manage-clips',
],
);
$routes->post(
@ -428,7 +428,7 @@ $routes->group(
'VideoClipsController::attemptCreate/$1/$2',
[
'as' => 'video-clips-create',
'filter' => 'permission:podcast#.episodes.manage-clips',
'filter' => 'permission:podcast$1.episodes.manage-clips',
],
);
$routes->get(
@ -436,7 +436,7 @@ $routes->group(
'VideoClipsController::view/$1/$2/$3',
[
'as' => 'video-clip',
'filter' => 'permission:podcast#.episodes.manage-clips',
'filter' => 'permission:podcast$1.episodes.manage-clips',
],
);
$routes->get(
@ -444,7 +444,7 @@ $routes->group(
'VideoClipsController::retry/$1/$2/$3',
[
'as' => 'video-clip-retry',
'filter' => 'permission:podcast#.episodes.manage-clips',
'filter' => 'permission:podcast$1.episodes.manage-clips',
],
);
$routes->get(
@ -452,7 +452,7 @@ $routes->group(
'VideoClipsController::delete/$1/$2/$3',
[
'as' => 'video-clip-delete',
'filter' => 'permission:podcast#.episodes.manage-clips',
'filter' => 'permission:podcast$1.episodes.manage-clips',
],
);
$routes->get(
@ -460,19 +460,19 @@ $routes->group(
'EpisodeController::embed/$1/$2',
[
'as' => 'embed-add',
'filter' => 'permission:podcast#.episodes.edit',
'filter' => 'permission:podcast$1.episodes.edit',
],
);
$routes->group('persons', static function ($routes): void {
$routes->get('/', 'EpisodePersonController::index/$1/$2', [
'as' => 'episode-persons-manage',
'filter' => 'permission:podcast#.episodes.manage-persons',
'filter' => 'permission:podcast$1.episodes.manage-persons',
]);
$routes->post(
'/',
'EpisodePersonController::attemptCreate/$1/$2',
[
'filter' => 'permission:podcast#.episodes.manage-persons',
'filter' => 'permission:podcast$1.episodes.manage-persons',
],
);
$routes->get(
@ -480,7 +480,7 @@ $routes->group(
'EpisodePersonController::remove/$1/$2/$3',
[
'as' => 'episode-person-remove',
'filter' => 'permission:podcast#.episodes.manage-persons',
'filter' => 'permission:podcast$1.episodes.manage-persons',
],
);
});
@ -490,7 +490,7 @@ $routes->group(
'EpisodeController::attemptCommentCreate/$1/$2',
[
'as' => 'comment-attempt-create',
'filter' => 'permission:podcast#.episodes.manage-comments',
'filter' => 'permission:podcast$1.episodes.manage-comments',
]
);
$routes->post(
@ -498,7 +498,7 @@ $routes->group(
'EpisodeController::attemptCommentReply/$1/$2/$3',
[
'as' => 'comment-attempt-reply',
'filter' => 'permission:podcast#.episodes.manage-comments',
'filter' => 'permission:podcast$1.episodes.manage-comments',
]
);
$routes->post(
@ -506,7 +506,7 @@ $routes->group(
'EpisodeController::attemptCommentDelete/$1/$2',
[
'as' => 'comment-attempt-delete',
'filter' => 'permission:podcast#.episodes.manage-comments',
'filter' => 'permission:podcast$1.episodes.manage-comments',
]
);
});
@ -516,15 +516,15 @@ $routes->group(
$routes->group('notifications', static function ($routes): void {
$routes->get('/', 'NotificationController::list/$1', [
'as' => 'notification-list',
'filter' => 'permission:podcast#.manage-notifications',
'filter' => 'permission:podcast$1.manage-notifications',
]);
$routes->get('(:num)/mark-as-read', 'NotificationController::markAsRead/$1/$2', [
'as' => 'notification-mark-as-read',
'filter' => 'permission:podcast#.manage-notifications',
'filter' => 'permission:podcast$1.manage-notifications',
]);
$routes->get('mark-all-as-read', 'NotificationController::markAllAsRead/$1', [
'as' => 'notification-mark-all-as-read',
'filter' => 'permission:podcast#.manage-notifications',
'filter' => 'permission:podcast$1.manage-notifications',
]);
});
});

View File

@ -81,38 +81,38 @@ $routes->group(
$routes->group('podcasts/(:num)/contributors', static function ($routes): void {
$routes->get('/', 'ContributorController::list/$1', [
'as' => 'contributor-list',
'filter' => 'permission:podcast#.manage-contributors',
'filter' => 'permission:podcast$1.manage-contributors',
]);
$routes->get('add', 'ContributorController::create/$1', [
'as' => 'contributor-add',
'filter' => 'permission:podcast#.manage-contributors',
'filter' => 'permission:podcast$1.manage-contributors',
]);
$routes->post(
'add',
'ContributorController::attemptCreate/$1',
[
'filter' => 'permission:podcast#.manage-contributors',
'filter' => 'permission:podcast$1.manage-contributors',
],
);
// Contributor
$routes->group('(:num)', static function ($routes): void {
$routes->get('/', 'ContributorController::view/$1/$2', [
'as' => 'contributor-view',
'filter' => 'permission:podcast#.manage-contributors',
'filter' => 'permission:podcast$1.manage-contributors',
]);
$routes->get(
'edit',
'ContributorController::edit/$1/$2',
[
'as' => 'contributor-edit',
'filter' => 'permission:podcast#.manage-contributors',
'filter' => 'permission:podcast$1.manage-contributors',
],
);
$routes->post(
'edit',
'ContributorController::attemptEdit/$1/$2',
[
'filter' => 'permission:podcast#.manage-contributors',
'filter' => 'permission:podcast$1.manage-contributors',
],
);
$routes->get(
@ -120,14 +120,14 @@ $routes->group(
'ContributorController::remove/$1/$2',
[
'as' => 'contributor-remove',
'filter' => 'permission:podcast#.manage-contributors',
'filter' => 'permission:podcast$1.manage-contributors',
],
);
$routes->post(
'remove',
'ContributorController::attemptRemove/$1/$2',
[
'filter' => 'permission:podcast#.manage-contributors',
'filter' => 'permission:podcast$1.manage-contributors',
],
);
});

View File

@ -58,23 +58,37 @@ class PermissionFilter implements FilterInterface
foreach ($arguments as $permission) {
// is permission specific to a podcast?
if (str_contains($permission, '#')) {
if (str_contains($permission, '$')) {
$router = Services::router();
$routerParams = $router->params();
if (! preg_match('/\$(\d+)\./', $permission, $match)) {
throw new RuntimeException(sprintf(
'Could not get podcast identifier from permission %s',
$permission
), 1);
}
$paramKey = ((int) $match[1]) - 1;
if (! array_key_exists($paramKey, $routerParams)) {
throw new RuntimeException(sprintf('Router param does not exist at key %s', $match[1]), 1);
}
$podcastParam = $routerParams[$paramKey];
// get podcast id
$podcastId = null;
if (is_numeric($routerParams[0])) {
$podcastId = (int) $routerParams[0];
if (is_numeric($podcastParam)) {
$podcastId = (int) $podcastParam;
} else {
$podcast = (new PodcastModel())->getPodcastByHandle($routerParams[0]);
$podcast = (new PodcastModel())->getPodcastByHandle($podcastParam);
if ($podcast instanceof Podcast) {
$podcastId = $podcast->id;
}
}
if ($podcastId !== null) {
$permission = str_replace('#', '#' . $podcastId, $permission);
$permission = str_replace('$' . $match[1], '#' . $podcastId, $permission);
}
}

View File

@ -24,7 +24,7 @@ $routes->group(
'PlatformController::platforms/$1/podcasting',
[
'as' => 'platforms-podcasting',
'filter' => 'permission:podcast#.manage-platforms',
'filter' => 'permission:podcast$1.manage-platforms',
],
);
$routes->get(
@ -32,7 +32,7 @@ $routes->group(
'PlatformController::platforms/$1/social',
[
'as' => 'platforms-social',
'filter' => 'permission:podcast#.manage-platforms',
'filter' => 'permission:podcast$1.manage-platforms',
],
);
$routes->get(
@ -40,7 +40,7 @@ $routes->group(
'PlatformController::platforms/$1/funding',
[
'as' => 'platforms-funding',
'filter' => 'permission:podcast#.manage-platforms',
'filter' => 'permission:podcast$1.manage-platforms',
],
);
$routes->post(
@ -48,7 +48,7 @@ $routes->group(
'PlatformController::attemptPlatformsUpdate/$1/$2',
[
'as' => 'platforms-save',
'filter' => 'permission:podcast#.manage-platforms',
'filter' => 'permission:podcast$1.manage-platforms',
],
);
$routes->get(
@ -56,7 +56,7 @@ $routes->group(
'PlatformController::removePlatform/$1/$2/$3',
[
'as' => 'podcast-platform-remove',
'filter' => 'permission:podcast#.manage-platforms',
'filter' => 'permission:podcast$1.manage-platforms',
],
);
});

View File

@ -5,8 +5,6 @@ declare(strict_types=1);
use CodeIgniter\Router\RouteCollection;
/** @var RouteCollection $routes */
$routes->addPlaceholder('pluginVendor', '[a-z0-9]([_.-]?[a-z0-9]+)*');
$routes->addPlaceholder('pluginKey', PLUGINS_KEY_PATTERN);
$routes->group(
config('Admin')
@ -20,23 +18,39 @@ $routes->group(
'as' => 'plugins-installed',
'filter' => 'permission:plugins.manage',
]);
$routes->get('(:pluginVendor)', 'PluginController::vendor/$1', [
$routes->get('(:segment)', 'PluginController::vendor/$1', [
'as' => 'plugins-vendor',
'filter' => 'permission:plugins.manage',
]);
$routes->group('(:pluginKey)', static function ($routes): void {
$routes->group('(:segment)/(:segment)', static function ($routes): void {
$routes->get('/', 'PluginController::view/$1/$2', [
'as' => 'plugins-view',
'filter' => 'permission:plugins.manage',
]);
$routes->get('settings', 'PluginController::generalSettings/$1/$2', [
'as' => 'plugins-general-settings',
$routes->get('settings', 'PluginController::settings/$1/$2', [
'as' => 'plugins-settings-general',
'filter' => 'permission:plugins.manage',
]);
$routes->post('settings', 'PluginController::generalSettingsAction/$1/$2', [
'as' => 'plugins-general-settings-action',
$routes->post('settings', 'PluginController::settingsAction/$1/$2', [
'as' => 'plugins-settings-general-action',
'filter' => 'permission:plugins.manage',
]);
$routes->get('(:num)', 'PluginController::settings/$1/$2/$3', [
'as' => 'plugins-settings-podcast',
'filter' => 'permission:podcast$3.edit',
]);
$routes->post('(:num)', 'PluginController::settingsAction/$1/$2/$3', [
'as' => 'plugins-settings-podcast-action',
'filter' => 'permission:podcast$3.edit',
]);
$routes->get('(:num)/(:num)', 'PluginController::settings/$1/$2/$3/$4', [
'as' => 'plugins-settings-episode',
'filter' => 'permission:podcast$3.episodes.edit',
]);
$routes->post('(:num)/(:num)', 'PluginController::settingsAction/$1/$2/$3/$4', [
'as' => 'plugins-settings-episode-action',
'filter' => 'permission:podcast$3.episodes.edit',
]);
$routes->post('activate', 'PluginController::activate/$1/$2', [
'as' => 'plugins-activate',
'filter' => 'permission:plugins.manage',
@ -52,25 +66,5 @@ $routes->group(
]);
});
});
$routes->group('podcasts/(:num)/plugins', static function ($routes): void {
$routes->get('(:pluginKey)', 'PluginController::podcastSettings/$1/$2/$3', [
'as' => 'plugins-podcast-settings',
'filter' => 'permission:podcast#.edit',
]);
$routes->post('(:pluginKey)', 'PluginController::podcastSettingsAction/$1/$2/$3', [
'as' => 'plugins-podcast-settings-action',
'filter' => 'permission:podcast#.edit',
]);
});
$routes->group('podcasts/(:num)/episodes/(:num)/plugins', static function ($routes): void {
$routes->get('(:pluginKey)', 'PluginController::episodeSettings/$1/$2/$3/$4', [
'as' => 'plugins-episode-settings',
'filter' => 'permission:podcast#.edit',
]);
$routes->post('(:pluginKey)', 'PluginController::episodeSettingsAction/$1/$2/$3/$4', [
'as' => 'plugins-episode-settings-action',
'filter' => 'permission:podcast#.edit',
]);
});
}
);

View File

@ -74,8 +74,12 @@ class PluginController extends BaseController
]);
}
public function generalSettings(string $vendor, string $package): string
{
public function settings(
string $vendor,
string $package,
string $podcastId = null,
string $episodeId = null
): string {
/** @var Plugins $plugins */
$plugins = service('plugins');
@ -85,18 +89,56 @@ class PluginController extends BaseController
throw PageNotFoundException::forPageNotFound();
}
helper('form');
replace_breadcrumb_params([
$type = 'general';
$context = null;
$breadcrumbReplacements = [
$vendor => $vendor,
$package => $package,
]);
return view('plugins/settings_general', [
];
$data = [
'plugin' => $plugin,
]);
];
if ($podcastId !== null) {
$podcast = (new PodcastModel())->getPodcastById((int) $podcastId);
if (! $podcast instanceof Podcast) {
throw PageNotFoundException::forPageNotFound();
}
$type = 'podcast';
$context = ['podcast', (int) $podcastId];
$breadcrumbReplacements[0] = $podcast->handle;
$data['podcast'] = $podcast;
}
if ($episodeId !== null) {
$episode = (new EpisodeModel())->getEpisodeById((int) $episodeId);
if (! $episode instanceof Episode) {
throw PageNotFoundException::forPageNotFound();
}
$type = 'episode';
$context = ['episode', (int) $episodeId];
$breadcrumbReplacements[1] = $episode->title;
$data['episode'] = $episode;
}
$data['type'] = $type;
$data['context'] = $context;
helper('form');
replace_breadcrumb_params($breadcrumbReplacements);
return view('plugins/settings', $data);
}
public function generalSettingsAction(string $vendor, string $package): RedirectResponse
{
public function settingsAction(
string $vendor,
string $package,
string $podcastId = null,
string $episodeId = null
): RedirectResponse {
/** @var Plugins $plugins */
$plugins = service('plugins');
@ -106,9 +148,21 @@ class PluginController extends BaseController
throw PageNotFoundException::forPageNotFound();
}
$type = 'general';
$context = null;
if ($podcastId !== null) {
$type = 'podcast';
$context = ['podcast', (int) $podcastId];
}
if ($episodeId !== null) {
$type = 'episode';
$context = ['episode', (int) $episodeId];
}
// construct validation rules first
$rules = [];
foreach ($plugin->getSettingsFields('general') as $field) {
foreach ($plugin->getSettingsFields($type) as $field) {
$typeRules = $plugins::FIELDS_VALIDATIONS[$field->type];
if (! in_array('permit_empty', $typeRules, true) && ! $field->optional) {
$typeRules[] = 'required';
@ -140,115 +194,7 @@ class PluginController extends BaseController
'markdown' => new Markdown($value),
default => $value === '' ? null : $value,
};
$plugins->setOption($plugin, $field->key, $fieldValue);
}
return redirect()->back()
->with('message', lang('Plugins.messages.saveSettingsSuccess', [
'pluginName' => $plugin->getName(),
]));
}
public function podcastSettings(string $podcastId, string $vendor, string $package): string
{
$podcast = (new PodcastModel())->getPodcastById((int) $podcastId);
if (! $podcast instanceof Podcast) {
throw PageNotFoundException::forPageNotFound();
}
/** @var Plugins $plugins */
$plugins = service('plugins');
$plugin = $plugins->getPlugin($vendor, $package);
if ($plugin === null) {
throw PageNotFoundException::forPageNotFound();
}
helper('form');
replace_breadcrumb_params([
0 => $podcast->handle,
$vendor => $vendor,
$package => $package,
]);
return view('plugins/settings_podcast', [
'podcast' => $podcast,
'plugin' => $plugin,
]);
}
public function podcastSettingsAction(string $podcastId, string $vendor, string $package): RedirectResponse
{
/** @var Plugins $plugins */
$plugins = service('plugins');
$plugin = $plugins->getPlugin($vendor, $package);
if ($plugin === null) {
throw PageNotFoundException::forPageNotFound();
}
foreach ($plugin->getSettingsFields('podcast') as $field) {
$settingValue = $this->request->getPost($field->key);
$plugins->setOption($plugin, $field->key, $settingValue, ['podcast', (int) $podcastId]);
}
return redirect()->back()
->with('message', lang('Plugins.messages.saveSettingsSuccess', [
'pluginName' => $plugin->getName(),
]));
}
public function episodeSettings(string $podcastId, string $episodeId, string $vendor, string $package): string
{
$episode = (new EpisodeModel())->getEpisodeById((int) $episodeId);
if (! $episode instanceof Episode) {
throw PageNotFoundException::forPageNotFound();
}
/** @var Plugins $plugins */
$plugins = service('plugins');
$plugin = $plugins->getPlugin($vendor, $package);
if ($plugin === null) {
throw PageNotFoundException::forPageNotFound();
}
helper('form');
replace_breadcrumb_params([
0 => $episode->podcast->handle,
1 => $episode->title,
$vendor => $vendor,
$package => $package,
]);
return view('plugins/settings_episode', [
'podcast' => $episode->podcast,
'episode' => $episode,
'plugin' => $plugin,
]);
}
public function episodeSettingsAction(
string $podcastId,
string $episodeId,
string $vendor,
string $package
): RedirectResponse {
/** @var Plugins $plugins */
$plugins = service('plugins');
$plugin = $plugins->getPlugin($vendor, $package);
if ($plugin === null) {
throw PageNotFoundException::forPageNotFound();
}
foreach ($plugin->getSettingsFields('episode') as $field) {
$settingValue = $this->request->getPost($field->key);
$plugins->setOption($plugin, $field->key, $settingValue, ['episode', (int) $episodeId]);
$plugins->setOption($plugin, $field->key, $fieldValue, $context);
}
return redirect()->back()

View File

@ -35,15 +35,15 @@ $routes->group(
$routes->group('podcasts/(:num)', static function ($routes): void {
$routes->get('imports', 'PodcastImportController::podcastList/$1', [
'as' => 'podcast-imports',
'filter' => 'permission:podcast#.manage-import',
'filter' => 'permission:podcast$1.manage-import',
]);
$routes->get('sync-feeds', 'PodcastImportController::syncImport/$1', [
'as' => 'podcast-imports-sync',
'filter' => 'permission:podcast#.manage-import',
'filter' => 'permission:podcast$1.manage-import',
]);
$routes->post('sync-feeds', 'PodcastImportController::syncImportAttempt/$1', [
'as' => 'podcast-imports-sync',
'filter' => 'permission:podcast#.manage-import',
'filter' => 'permission:podcast$1.manage-import',
]);
});
}

View File

@ -21,35 +21,35 @@ $routes->group(
$routes->group('podcasts/(:num)/subscriptions', static function ($routes): void {
$routes->get('/', 'SubscriptionController::list/$1', [
'as' => 'subscription-list',
'filter' => 'permission:podcast#.manage-subscriptions',
'filter' => 'permission:podcast$1.manage-subscriptions',
]);
$routes->get('new', 'SubscriptionController::create/$1', [
'as' => 'subscription-create',
'filter' => 'permission:podcast#.manage-subscriptions',
'filter' => 'permission:podcast$1.manage-subscriptions',
]);
$routes->post(
'new',
'SubscriptionController::attemptCreate/$1',
[
'filter' => 'permission:podcast#.manage-subscriptions',
'filter' => 'permission:podcast$1.manage-subscriptions',
],
);
$routes->post('save-link', 'SubscriptionController::attemptLinkSave/$1', [
'as' => 'subscription-link-save',
'filter' => 'permission:podcast#.manage-subscriptions',
'filter' => 'permission:podcast$1.manage-subscriptions',
]);
// Subscription
$routes->group('(:num)', static function ($routes): void {
$routes->get('/', 'SubscriptionController::view/$1/$2', [
'as' => 'subscription-view',
'filter' => 'permission:podcast#.manage-subscriptions',
'filter' => 'permission:podcast$1.manage-subscriptions',
]);
$routes->get(
'edit',
'SubscriptionController::edit/$1/$2',
[
'as' => 'subscription-edit',
'filter' => 'permission:podcast#.manage-subscriptions',
'filter' => 'permission:podcast$1.manage-subscriptions',
],
);
$routes->post(
@ -57,7 +57,7 @@ $routes->group(
'SubscriptionController::attemptEdit/$1/$2',
[
'as' => 'subscription-edit',
'filter' => 'permission:podcast#.manage-subscriptions',
'filter' => 'permission:podcast$1.manage-subscriptions',
],
);
$routes->get(
@ -65,7 +65,7 @@ $routes->group(
'SubscriptionController::regenerateToken/$1/$2',
[
'as' => 'subscription-regenerate-token',
'filter' => 'permission:podcast#.manage-subscriptions',
'filter' => 'permission:podcast$1.manage-subscriptions',
]
);
$routes->get(
@ -73,14 +73,14 @@ $routes->group(
'SubscriptionController::suspend/$1/$2',
[
'as' => 'subscription-suspend',
'filter' => 'permission:podcast#.manage-subscriptions',
'filter' => 'permission:podcast$1.manage-subscriptions',
],
);
$routes->post(
'suspend',
'SubscriptionController::attemptSuspend/$1/$2',
[
'filter' => 'permission:podcast#.manage-subscriptions',
'filter' => 'permission:podcast$1.manage-subscriptions',
],
);
$routes->get(
@ -88,7 +88,7 @@ $routes->group(
'SubscriptionController::resume/$1/$2',
[
'as' => 'subscription-resume',
'filter' => 'permission:podcast#.manage-subscriptions',
'filter' => 'permission:podcast$1.manage-subscriptions',
],
);
$routes->get(
@ -96,14 +96,14 @@ $routes->group(
'SubscriptionController::delete/$1/$2',
[
'as' => 'subscription-delete',
'filter' => 'permission:podcast#.manage-subscriptions',
'filter' => 'permission:podcast$1.manage-subscriptions',
],
);
$routes->post(
'delete',
'SubscriptionController::attemptDelete/$1/$2',
[
'filter' => 'permission:podcast#.manage-subscriptions',
'filter' => 'permission:podcast$1.manage-subscriptions',
],
);
});

View File

@ -86,7 +86,7 @@ $navigation = [
];
foreach (plugins()->getActivePlugins() as $plugin) {
$route = route_to('plugins-view', $plugin->getKey());
$route = route_to('plugins-view', $plugin->getVendor(), $plugin->getPackage());
$navigation['plugins']['items'][] = $route;
$navigation['plugins']['items-labels'][$route] = $plugin->getName();
$navigation['plugins']['items-permissions'][$route] = 'plugins.manage';

View File

@ -33,7 +33,7 @@ $episodeNavigation = [
];
foreach (plugins()->getPluginsWithEpisodeSettings() as $plugin) {
$route = route_to('plugins-episode-settings', $podcast->id, $episode->id, $plugin->getKey());
$route = route_to('plugins-settings-episode', $plugin->getVendor(), $plugin->getPackage(), $podcast->id, $episode->id);
$episodeNavigation['plugins']['items'][] = $route;
$episodeNavigation['plugins']['items-labels'][$route] = $plugin->getName();
$episodeNavigation['plugins']['items-permissions'][$route] = 'episodes.edit';

View File

@ -8,12 +8,12 @@
</div>
<img class="rounded-full min-w-16 max-w-16 aspect-square" src="<?= $plugin->getIconSrc() ?>">
<div class="flex flex-col items-start mt-2">
<h2 class="flex items-center text-xl font-bold font-display gap-x-2"><a href="<?= route_to('plugins-view', $plugin->getKey()) ?>" class="hover:underline decoration-accent"><?= $plugin->getName() ?></a></h2>
<h2 class="flex items-center text-xl font-bold font-display gap-x-2"><a href="<?= route_to('plugins-view', $plugin->getVendor(), $plugin->getPackage()) ?>" class="hover:underline decoration-accent"><?= $plugin->getName() ?></a></h2>
<p class="inline-flex font-mono text-xs">
<span class="inline-flex tracking-wide bg-gray-100">
<a href="<?= route_to('plugins-vendor', $plugin->getVendor()) ?>" class="underline underline-offset-2 decoration-2 decoration-dotted hover:decoration-solid decoration-accent"><?= $plugin->getVendor() ?></a>
<span>/</span>
<a class="underline underline-offset-2 decoration-2 decoration-dotted hover:decoration-solid decoration-accent" href="<?= route_to('plugins-view', $plugin->getKey()) ?>"><?= $plugin->getPackage() ?></a></span>
<a class="underline underline-offset-2 decoration-2 decoration-dotted hover:decoration-solid decoration-accent" href="<?= route_to('plugins-view', $plugin->getVendor(), $plugin->getPackage()) ?>"><?= $plugin->getPackage() ?></a></span>
<span class="mx-1"></span><span class="px-1 font-mono text-xs"><?= $plugin->getVersion() ?></span>
</p>
<p class="mt-2 text-gray-600"><?= $plugin->getDescription() ?></p>
@ -31,26 +31,26 @@
</div>
<div class="flex gap-x-2">
<?php if($plugin->isActive()): ?>
<form class="flex justify-end" method="POST" action="<?= route_to('plugins-deactivate', $plugin->getKey()) ?>">
<form class="flex justify-end" method="POST" action="<?= route_to('plugins-deactivate', $plugin->getVendor(), $plugin->getPackage()) ?>">
<?= csrf_field() ?>
<x-Button type="submit" variant="danger" size="small"><?= lang('Plugins.deactivate') ?></x-Button>
</form>
<?php else: ?>
<form class="flex flex-col items-end justify-end gap-2" method="POST" action="<?= route_to('plugins-activate', $plugin->getKey()) ?>">
<form class="flex flex-col items-end justify-end gap-2" method="POST" action="<?= route_to('plugins-activate', $plugin->getVendor(), $plugin->getPackage()) ?>">
<?= csrf_field() ?>
<x-Button type="submit" variant="secondary" size="small"><?= lang('Plugins.activate') ?></x-Button>
</form>
<?php endif; ?>
<?php if ($plugin->getSettings() !== []): ?>
<?php // @icon('equalizer-fill')?>
<x-IconButton uri="<?= route_to('plugins-general-settings', $plugin->getKey()) ?>" glyph="equalizer-fill"><?= lang('Plugins.settings') ?></x-IconButton>
<x-IconButton uri="<?= route_to('plugins-general-settings', $plugin->getVendor(), $plugin->getPackage()) ?>" glyph="equalizer-fill"><?= lang('Plugins.settings') ?></x-IconButton>
<?php endif; ?>
<button class="p-2 rounded-full" id="more-dropdown-<?= $plugin->getKey() ?>" data-dropdown="button" data-dropdown-target="more-dropdown-<?= $plugin->getKey() ?>-menu" aria-haspopup="true" aria-expanded="false" title="<?= lang('Common.more') ?>"><?= icon('more-2-fill') ?></button>
<?php $items = [
[
'type' => 'link',
'title' => lang('Plugins.view'),
'uri' => route_to('plugins-view', $plugin->getKey()),
'uri' => route_to('plugins-view', $plugin->getVendor(), $plugin->getPackage()),
],
[
'type' => 'separator',
@ -60,7 +60,7 @@
'title' => icon('delete-bin-fill', [
'class' => 'text-gray-500',
]) . lang('Plugins.uninstall'),
'uri' => route_to('plugins-uninstall', $plugin->getKey()),
'uri' => route_to('plugins-uninstall', $plugin->getVendor(), $plugin->getPackage()),
'class' => 'font-semibold text-red-600',
],
]; ?>

View File

@ -3,20 +3,37 @@
<?= $this->section('title') ?>
<?= lang('Plugins.settings', [
'pluginName' => $plugin->getName(),
'type' => $type,
]) ?>
<?= $this->endSection() ?>
<?= $this->section('pageTitle') ?>
<?= lang('Plugins.settings', [
'pluginName' => $plugin->getName(),
'type' => $type,
]) ?>
<?= $this->endSection() ?>
<?php
$params = [
$plugin->getVendor(),
$plugin->getPackage(),
];
if (isset($podcast)) {
$params[] = $podcast->id;
}
if (isset($episode)) {
$params[] = $episode->id;
}
?>
<?= $this->section('content') ?>
<?= view('plugins/_settings', [
'plugin' => $plugin,
'action' => route_to('plugins-episode-settings-action', $podcast->id, $episode->id, $plugin->getKey()),
'type' => 'episode',
'context' => ['episode', $episode->id],
'action' => route_to(sprintf('plugins-settings-%s-action', $type), ...$params),
'type' => $type,
'context' => $context,
]) ?>
<?= $this->endSection() ?>

View File

@ -1,22 +0,0 @@
<?= $this->extend('_layout') ?>
<?= $this->section('title') ?>
<?= lang('Plugins.settings', [
'pluginName' => $plugin->getName(),
]) ?>
<?= $this->endSection() ?>
<?= $this->section('pageTitle') ?>
<?= lang('Plugins.settings', [
'pluginName' => $plugin->getName(),
]) ?>
<?= $this->endSection() ?>
<?= $this->section('content') ?>
<?= view('plugins/_settings', [
'plugin' => $plugin,
'action' => route_to('plugins-general-settings-action', $plugin->getKey()),
'type' => 'general',
'context' => null,
]) ?>
<?= $this->endSection() ?>

View File

@ -1,22 +0,0 @@
<?= $this->extend('_layout') ?>
<?= $this->section('title') ?>
<?= lang('Plugins.settings', [
'pluginName' => $plugin->getName(),
]) ?>
<?= $this->endSection() ?>
<?= $this->section('pageTitle') ?>
<?= lang('Plugins.settings', [
'pluginName' => $plugin->getName(),
]) ?>
<?= $this->endSection() ?>
<?= $this->section('content') ?>
<?= view('plugins/_settings', [
'plugin' => $plugin,
'action' => route_to('plugins-podcast-settings-action', $podcast->id, $plugin->getKey()),
'type' => 'podcast',
'context' => ['podcast', $podcast->id],
]) ?>
<?= $this->endSection() ?>

View File

@ -18,12 +18,12 @@
<?= $this->section('headerRight') ?>
<?php if($plugin->isActive()): ?>
<form class="flex justify-end" method="POST" action="<?= route_to('plugins-deactivate', $plugin->getKey()) ?>">
<form class="flex justify-end" method="POST" action="<?= route_to('plugins-deactivate', $plugin->getVendor(), $plugin->getPackage()) ?>">
<?= csrf_field() ?>
<x-Button type="submit" variant="danger"><?= lang('Plugins.deactivate') ?></x-Button>
</form>
<?php else: ?>
<form class="flex justify-end" method="POST" action="<?= route_to('plugins-activate', $plugin->getKey()) ?>">
<form class="flex justify-end" method="POST" action="<?= route_to('plugins-activate', $plugin->getVendor(), $plugin->getPackage()) ?>">
<?= csrf_field() ?>
<x-Button type="submit" variant="secondary"><?= lang('Plugins.activate') ?></x-Button>
</form>
@ -31,8 +31,8 @@
<?= $this->endSection() ?>
<?= $this->section('content') ?>
<div class="flex flex-col items-start justify-center gap-8 mx-auto lg:flex-row-reverse">
<aside class="w-full pb-8 border-b lg:sticky lg:max-w-xs top-28 border-subtle lg:border-none">
<div class="flex flex-col items-start justify-center gap-8 mx-auto xl:flex-row-reverse">
<aside class="w-full pb-8 border-b xl:sticky xl:max-w-xs top-28 border-subtle xl:border-none">
<h2 class="mb-2 text-2xl font-bold font-display"><?= lang('Plugins.about') ?></h2>
<p><?= $plugin->getDescription() ?></p>
<a href="<?= $plugin->getHomepage() ?>" class="inline-flex items-center mt-2 font-semibold hover:underline gap-x-2"><?= icon('link') . $plugin->getHomepage() ?></a>

View File

@ -90,7 +90,7 @@ $podcastNavigation = [
];
foreach (plugins()->getPluginsWithPodcastSettings() as $plugin) {
$route = route_to('plugins-podcast-settings', $podcast->id, $plugin->getKey());
$route = route_to('plugins-settings-podcast', $plugin->getVendor(), $plugin->getPackage(), $podcast->id);
$podcastNavigation['plugins']['items'][] = $route;
$podcastNavigation['plugins']['items-labels'][$route] = $plugin->getName();
$podcastNavigation['plugins']['items-permissions'][$route] = 'edit';