From 6e9af6f1f486ff4e211aef1aab987035479fc8ba Mon Sep 17 00:00:00 2001 From: "Buster \"Silver Eagle\" Neece" Date: Wed, 29 Jun 2022 23:38:46 -0500 Subject: [PATCH] Unify feature checks; simplify station routes. --- config/menus/station.php | 27 +- config/routes/api_station.php | 891 +++++++++++------- config/routes/stations.php | 12 + .../Api/Stations/HlsStreamsController.php | 16 - .../Api/Stations/MountsController.php | 15 - .../Streamers/Art/DeleteArtAction.php | 4 +- .../Stations/Streamers/Art/GetArtAction.php | 6 +- .../Stations/Streamers/Art/PostArtAction.php | 6 +- .../Streamers/BroadcastsController.php | 16 +- .../Api/Stations/StreamersController.php | 21 +- .../Stations/EditLiquidsoapConfigAction.php | 5 - src/Controller/Stations/HlsStreamsAction.php | 7 - src/Enums/StationFeatures.php | 34 + src/Middleware/StationSupportsFeature.php | 28 + .../Functional/Api_Stations_StreamersCest.php | 4 + 15 files changed, 666 insertions(+), 426 deletions(-) create mode 100644 src/Enums/StationFeatures.php create mode 100644 src/Middleware/StationSupportsFeature.php diff --git a/config/menus/station.php b/config/menus/station.php index 4a4010726..5582befa6 100644 --- a/config/menus/station.php +++ b/config/menus/station.php @@ -3,6 +3,7 @@ * Administrative dashboard configuration. */ +use App\Enums\StationFeatures; use App\Enums\StationPermissions; use App\Radio\Enums\AudioProcessingMethods; @@ -13,8 +14,6 @@ return function (App\Event\BuildStationMenu $e) { $backendConfig = $station->getBackendConfig(); $router = $request->getRouter(); - - $backendEnum = $station->getBackendTypeEnum(); $frontendEnum = $station->getFrontendTypeEnum(); $willDisconnectMessage = __('Restart broadcasting? This will disconnect any current listeners.'); @@ -63,33 +62,30 @@ return function (App\Event\BuildStationMenu $e) { 'media' => [ 'label' => __('Media'), 'icon' => 'library_music', + 'visible' => StationFeatures::Media->supportedForStation($station), 'items' => [ 'files' => [ 'label' => __('Music Files'), 'icon' => 'library_music', 'url' => (string)$router->fromHere('stations:files:index'), - 'visible' => $backendEnum->isEnabled(), 'permission' => StationPermissions::Media, ], 'reports_duplicates' => [ 'label' => __('Duplicate Songs'), 'class' => 'text-muted', 'url' => (string)$router->fromHere('stations:files:index') . '#special:duplicates', - 'visible' => $backendEnum->isEnabled(), 'permission' => StationPermissions::Media, ], 'reports_unprocessable' => [ 'label' => __('Unprocessable Files'), 'class' => 'text-muted', 'url' => (string)$router->fromHere('stations:files:index') . '#special:unprocessable', - 'visible' => $backendEnum->isEnabled(), 'permission' => StationPermissions::Media, ], 'reports_unassigned' => [ 'label' => __('Unassigned Files'), 'class' => 'text-muted', 'url' => (string)$router->fromHere('stations:files:index') . '#special:unassigned', - 'visible' => $backendEnum->isEnabled(), 'permission' => StationPermissions::Media, ], 'ondemand' => [ @@ -111,7 +107,6 @@ return function (App\Event\BuildStationMenu $e) { 'label' => __('Bulk Media Import/Export'), 'class' => 'text-muted', 'url' => (string)$router->fromHere('stations:bulk-media'), - 'visible' => $backendEnum->isEnabled(), 'permission' => StationPermissions::Media, ], ], @@ -121,7 +116,7 @@ return function (App\Event\BuildStationMenu $e) { 'label' => __('Playlists'), 'icon' => 'queue_music', 'url' => (string)$router->fromHere('stations:playlists:index'), - 'visible' => $backendEnum->isEnabled(), + 'visible' => StationFeatures::Media->supportedForStation($station), 'permission' => StationPermissions::Media, ], @@ -129,18 +124,19 @@ return function (App\Event\BuildStationMenu $e) { 'label' => __('Podcasts'), 'icon' => 'cast', 'url' => (string)$router->fromHere('stations:podcasts:index'), + 'visible' => StationFeatures::Podcasts->supportedForStation($station), 'permission' => StationPermissions::Podcasts, ], 'live_streaming' => [ 'label' => __('Live Streaming'), 'icon' => 'mic', + 'visible' => StationFeatures::Streamers->supportedForStation($station), 'items' => [ 'streamers' => [ 'label' => __('Streamer/DJ Accounts'), 'icon' => 'mic', 'url' => (string)$router->fromHere('stations:streamers:index'), - 'visible' => $backendEnum->isEnabled() && $station->getEnableStreamers(), 'permission' => StationPermissions::Streamers, ], @@ -154,7 +150,7 @@ return function (App\Event\BuildStationMenu $e) { true ) ->withScheme('https'), - 'visible' => $station->getEnablePublicPage() && $station->getEnableStreamers(), + 'visible' => $station->getEnablePublicPage(), 'external' => true, ], ], @@ -164,6 +160,7 @@ return function (App\Event\BuildStationMenu $e) { 'label' => __('Web Hooks'), 'icon' => 'code', 'url' => (string)$router->fromHere('stations:webhooks:index'), + 'visible' => StationFeatures::Webhooks->supportedForStation($station), 'permission' => StationPermissions::WebHooks, ], @@ -204,32 +201,34 @@ return function (App\Event\BuildStationMenu $e) { 'label' => __('Mount Points'), 'icon' => 'wifi_tethering', 'url' => (string)$router->fromHere('stations:mounts:index'), - 'visible' => $frontendEnum->supportsMounts(), + 'visible' => StationFeatures::MountPoints->supportedForStation($station), 'permission' => StationPermissions::MountPoints, ], 'hls_streams' => [ 'label' => __('HLS Streams'), 'url' => (string)$router->fromHere('stations:hls_streams:index'), - 'visible' => $backendEnum->isEnabled() && $station->getEnableHls(), + 'visible' => StationFeatures::HlsStreams->supportedForStation($station), 'permission' => StationPermissions::MountPoints, ], 'remotes' => [ 'label' => __('Remote Relays'), 'icon' => 'router', 'url' => (string)$router->fromHere('stations:remotes:index'), + 'visible' => StationFeatures::RemoteRelays->supportedForStation($station), 'permission' => StationPermissions::RemoteRelays, ], 'fallback' => [ 'label' => __('Custom Fallback File'), 'class' => 'text-muted', 'url' => (string)$router->fromHere('stations:fallback'), + 'visible' => StationFeatures::Media->supportedForStation($station), 'permission' => StationPermissions::Broadcasting, ], 'ls_config' => [ 'label' => __('Edit Liquidsoap Configuration'), 'class' => 'text-muted', 'url' => (string)$router->fromHere('stations:util:ls_config'), - 'visible' => $settings->getEnableAdvancedFeatures() && $backendEnum->isEnabled(), + 'visible' => StationFeatures::CustomLiquidsoapConfig->supportedForStation($station), 'permission' => StationPermissions::Broadcasting, ], 'stations:stereo_tool_config' => [ @@ -237,7 +236,7 @@ return function (App\Event\BuildStationMenu $e) { 'class' => 'text-muted', 'url' => (string)$router->fromHere('stations:stereo_tool_config'), 'visible' => $settings->getEnableAdvancedFeatures() - && App\Radio\Enums\BackendAdapters::Liquidsoap === $backendEnum + && StationFeatures::Media->supportedForStation($station) && AudioProcessingMethods::StereoTool === $backendConfig->getAudioProcessingMethodEnum(), 'permission' => StationPermissions::Broadcasting, ], diff --git a/config/routes/api_station.php b/config/routes/api_station.php index a8ac5efa7..b75938b2e 100644 --- a/config/routes/api_station.php +++ b/config/routes/api_station.php @@ -1,6 +1,7 @@ get( '/waveform/{media_id:[a-zA-Z0-9\-]+}.json', Controller\Api\Stations\Waveform\GetWaveformAction::class - ) - ->setName('api:stations:media:waveform'); + )->setName('api:stations:media:waveform'); $group->get('/art/{media_id:[a-zA-Z0-9\-]+}.jpg', Controller\Api\Stations\Art\GetArtAction::class) ->setName('api:stations:media:art'); @@ -102,42 +102,9 @@ return static function (RouteCollectorProxy $group) { $group->delete('/art/{media_id:[a-zA-Z0-9]+}', Controller\Api\Stations\Art\DeleteArtAction::class) ->add(new Middleware\Permissions(StationPermissions::Media, true)); - $group->group( - '/liquidsoap-config', - function (RouteCollectorProxy $group) { - $group->get( - '', - Controller\Api\Stations\LiquidsoapConfig\GetAction::class - )->setName('api:stations:liquidsoap-config'); - - $group->put( - '', - Controller\Api\Stations\LiquidsoapConfig\PutAction::class - ); - } - )->add(new Middleware\Permissions(StationPermissions::Broadcasting, true)); - - $group->group( - '/stereo_tool_config', - function (RouteCollectorProxy $group) { - $group->get( - '', - Controller\Api\Stations\StereoTool\GetStereoToolConfigurationAction::class - )->setName('api:stations:stereo_tool_config'); - - $group->post( - '', - Controller\Api\Stations\StereoTool\PostStereoToolConfigurationAction::class - ); - - $group->delete( - '', - Controller\Api\Stations\StereoTool\DeleteStereoToolConfigurationAction::class - ); - } - )->add(new Middleware\Permissions(StationPermissions::Broadcasting, true)); - - // Public and private podcast pages + /* + * Podcast Public Pages + */ $group->group( '/podcast/{podcast_id}', function (RouteCollectorProxy $group) { @@ -176,304 +143,424 @@ return static function (RouteCollectorProxy $group) { } )->add(Middleware\RequirePublishedPodcastEpisodeMiddleware::class); - // Private-only podcast pages + /* + * Podcast Private Pates + */ $group->group( - '/podcasts', + '', function (RouteCollectorProxy $group) { - $group->get('', Controller\Api\Stations\PodcastsController::class . ':listAction') + $group->get('/podcasts', Controller\Api\Stations\PodcastsController::class . ':listAction') ->setName('api:stations:podcasts'); - $group->post('', Controller\Api\Stations\PodcastsController::class . ':createAction'); + $group->post('/podcasts', Controller\Api\Stations\PodcastsController::class . ':createAction'); - $group->post('/art', Controller\Api\Stations\Podcasts\Art\PostArtAction::class) + $group->post('/podcasts/art', Controller\Api\Stations\Podcasts\Art\PostArtAction::class) ->setName('api:stations:podcasts:new-art'); - } - )->add(new Middleware\Permissions(StationPermissions::Podcasts, true)); - - $group->group( - '/podcast/{podcast_id}', - function (RouteCollectorProxy $group) { - $group->put('', Controller\Api\Stations\PodcastsController::class . ':editAction'); - - $group->delete('', Controller\Api\Stations\PodcastsController::class . ':deleteAction'); - - $group->post( - '/art', - Controller\Api\Stations\Podcasts\Art\PostArtAction::class - )->setName('api:stations:podcast:art-internal'); - - $group->delete( - '/art', - Controller\Api\Stations\Podcasts\Art\DeleteArtAction::class - ); - - $group->post( - '/episodes', - Controller\Api\Stations\PodcastEpisodesController::class . ':createAction' - ); - - $group->post( - '/episodes/art', - Controller\Api\Stations\Podcasts\Episodes\Art\PostArtAction::class - )->setName('api:stations:podcast:episodes:new-art'); - - $group->post( - '/episodes/media', - Controller\Api\Stations\Podcasts\Episodes\Media\PostMediaAction::class - )->setName('api:stations:podcast:episodes:new-media'); $group->group( - '/episode/{episode_id}', + '/podcast/{podcast_id}', function (RouteCollectorProxy $group) { - $group->put( - '', - Controller\Api\Stations\PodcastEpisodesController::class . ':editAction' - ); + $group->put('', Controller\Api\Stations\PodcastsController::class . ':editAction'); - $group->delete( - '', - Controller\Api\Stations\PodcastEpisodesController::class . ':deleteAction' - ); + $group->delete('', Controller\Api\Stations\PodcastsController::class . ':deleteAction'); $group->post( '/art', + Controller\Api\Stations\Podcasts\Art\PostArtAction::class + )->setName('api:stations:podcast:art-internal'); + + $group->delete( + '/art', + Controller\Api\Stations\Podcasts\Art\DeleteArtAction::class + ); + + $group->post( + '/episodes', + Controller\Api\Stations\PodcastEpisodesController::class . ':createAction' + ); + + $group->post( + '/episodes/art', Controller\Api\Stations\Podcasts\Episodes\Art\PostArtAction::class - )->setName('api:stations:podcast:episode:art-internal'); - - $group->delete( - '/art', - Controller\Api\Stations\Podcasts\Episodes\Art\DeleteArtAction::class - ); + )->setName('api:stations:podcast:episodes:new-art'); $group->post( - '/media', + '/episodes/media', Controller\Api\Stations\Podcasts\Episodes\Media\PostMediaAction::class - )->setName('api:stations:podcast:episode:media-internal'); + )->setName('api:stations:podcast:episodes:new-media'); - $group->delete( - '/media', - Controller\Api\Stations\Podcasts\Episodes\Media\DeleteMediaAction::class + $group->group( + '/episode/{episode_id}', + function (RouteCollectorProxy $group) { + $group->put( + '', + Controller\Api\Stations\PodcastEpisodesController::class . ':editAction' + ); + + $group->delete( + '', + Controller\Api\Stations\PodcastEpisodesController::class . ':deleteAction' + ); + + $group->post( + '/art', + Controller\Api\Stations\Podcasts\Episodes\Art\PostArtAction::class + )->setName('api:stations:podcast:episode:art-internal'); + + $group->delete( + '/art', + Controller\Api\Stations\Podcasts\Episodes\Art\DeleteArtAction::class + ); + + $group->post( + '/media', + Controller\Api\Stations\Podcasts\Episodes\Media\PostMediaAction::class + )->setName('api:stations:podcast:episode:media-internal'); + + $group->delete( + '/media', + Controller\Api\Stations\Podcasts\Episodes\Media\DeleteMediaAction::class + ); + } ); } ); } )->add(new Middleware\Permissions(StationPermissions::Podcasts, true)); - // Streamers public pages - $group->get( - '/streamer/{streamer_id}/art', - Controller\Api\Stations\Streamers\Art\GetArtAction::class - )->setName('api:stations:streamer:art'); - - // Streamers internal pages - $group->post('/streamers/art', Controller\Api\Stations\Streamers\Art\PostArtAction::class) - ->setName('api:stations:streamers:new-art') - ->add(new Middleware\Permissions(StationPermissions::Streamers, true)); - + /* + * Files/Media + */ $group->group( - '/streamer/{streamer_id}', + '', function (RouteCollectorProxy $group) { - $group->post( - '/art', - Controller\Api\Stations\Streamers\Art\PostArtAction::class - )->setName('api:stations:streamer:art-internal'); + $group->group( + '/files', + function (RouteCollectorProxy $group) { + $group->get( + '', + Controller\Api\Stations\FilesController::class . ':listAction' + )->setName('api:stations:files'); - $group->delete( - '/art', - Controller\Api\Stations\Streamers\Art\DeleteArtAction::class + $group->post( + '', + Controller\Api\Stations\FilesController::class . ':createAction' + ); + + $group->get('/list', Controller\Api\Stations\Files\ListAction::class) + ->setName('api:stations:files:list'); + + $group->get('/directories', Controller\Api\Stations\Files\ListDirectoriesAction::class) + ->setName('api:stations:files:directories'); + + $group->put('/rename', Controller\Api\Stations\Files\RenameAction::class) + ->setName('api:stations:files:rename'); + + $group->put('/batch', Controller\Api\Stations\Files\BatchAction::class) + ->setName('api:stations:files:batch'); + + $group->post('/mkdir', Controller\Api\Stations\Files\MakeDirectoryAction::class) + ->setName('api:stations:files:mkdir'); + + $group->get('/bulk', Controller\Api\Stations\BulkMedia\DownloadAction::class) + ->setName('api:stations:files:bulk'); + + $group->post('/bulk', Controller\Api\Stations\BulkMedia\UploadAction::class); + + $group->get('/download', Controller\Api\Stations\Files\DownloadAction::class) + ->setName('api:stations:files:download'); + + $group->map( + ['GET', 'POST'], + '/upload', + Controller\Api\Stations\Files\FlowUploadAction::class + )->setName('api:stations:files:upload'); + } + ); + + $group->group( + '/file/{id}', + function (RouteCollectorProxy $group) { + $group->get( + '', + Controller\Api\Stations\FilesController::class . ':getAction' + )->setName('api:stations:file'); + + $group->put( + '', + Controller\Api\Stations\FilesController::class . ':editAction' + ); + + $group->delete( + '', + Controller\Api\Stations\FilesController::class . ':deleteAction' + ); + + $group->get('/play', Controller\Api\Stations\Files\PlayAction::class) + ->setName('api:stations:files:play'); + } ); } - )->add(new Middleware\Permissions(StationPermissions::Streamers, true)); - - $station_api_endpoints = [ - [ - 'file', - 'files', - Controller\Api\Stations\FilesController::class, - StationPermissions::Media, - ], - [ - 'hls_stream', - 'hls_streams', - Controller\Api\Stations\HlsStreamsController::class, - StationPermissions::MountPoints, - ], - [ - 'mount', - 'mounts', - Controller\Api\Stations\MountsController::class, - StationPermissions::MountPoints, - ], - [ - 'playlist', - 'playlists', - Controller\Api\Stations\PlaylistsController::class, - StationPermissions::Media, - ], - [ - 'remote', - 'remotes', - Controller\Api\Stations\RemotesController::class, - StationPermissions::RemoteRelays, - ], - [ - 'sftp-user', - 'sftp-users', - Controller\Api\Stations\SftpUsersController::class, - StationPermissions::Media, - ], - [ - 'streamer', - 'streamers', - Controller\Api\Stations\StreamersController::class, - StationPermissions::Streamers, - ], - [ - 'webhook', - 'webhooks', - Controller\Api\Stations\WebhooksController::class, - StationPermissions::WebHooks, - ], - ]; - - foreach ($station_api_endpoints as [$singular, $plural, $class, $permission]) { - $group->group( - '', - function (RouteCollectorProxy $group) use ($singular, $plural, $class) { - $group->get('/' . $plural, $class . ':listAction') - ->setName('api:stations:' . $plural); - $group->post('/' . $plural, $class . ':createAction'); - - $group->get('/' . $singular . '/{id}', $class . ':getAction') - ->setName('api:stations:' . $singular); - $group->put('/' . $singular . '/{id}', $class . ':editAction'); - $group->delete('/' . $singular . '/{id}', $class . ':deleteAction'); - } - )->add(new Middleware\Permissions($permission, true)); - } - - $group->group( - '/files', - function (RouteCollectorProxy $group) { - $group->get('/list', Controller\Api\Stations\Files\ListAction::class) - ->setName('api:stations:files:list'); - - $group->get('/directories', Controller\Api\Stations\Files\ListDirectoriesAction::class) - ->setName('api:stations:files:directories'); - - $group->put('/rename', Controller\Api\Stations\Files\RenameAction::class) - ->setName('api:stations:files:rename'); - - $group->put('/batch', Controller\Api\Stations\Files\BatchAction::class) - ->setName('api:stations:files:batch'); - - $group->post('/mkdir', Controller\Api\Stations\Files\MakeDirectoryAction::class) - ->setName('api:stations:files:mkdir'); - - $group->get('/play/{id}', Controller\Api\Stations\Files\PlayAction::class) - ->setName('api:stations:files:play'); - - $group->get('/download', Controller\Api\Stations\Files\DownloadAction::class) - ->setName('api:stations:files:download'); - - $group->get('/bulk', Controller\Api\Stations\BulkMedia\DownloadAction::class) - ->setName('api:stations:files:bulk'); - - $group->post('/bulk', Controller\Api\Stations\BulkMedia\UploadAction::class); - - $group->map( - ['GET', 'POST'], - '/upload', - Controller\Api\Stations\Files\FlowUploadAction::class - )->setName('api:stations:files:upload'); - } - ) - ->add(Middleware\Module\StationFiles::class) + )->add(new Middleware\StationSupportsFeature(StationFeatures::Media)) ->add(new Middleware\Permissions(StationPermissions::Media, true)); - $group->post( - '/mounts/intro', - Controller\Api\Stations\Mounts\Intro\PostIntroAction::class - )->setName('api:stations:mounts:new-intro') + /* + * SFTP Users + */ + $group->group( + '', + function (RouteCollectorProxy $group) { + $group->get( + '/sftp-users', + Controller\Api\Stations\SftpUsersController::class . ':listAction' + )->setName('api:stations:sftp-users'); + + $group->post( + '/sftp-users', + Controller\Api\Stations\SftpUsersController::class . ':createAction' + ); + + $group->get( + '/sftp-user/{id}', + Controller\Api\Stations\SftpUsersController::class . ':getAction' + )->setName('api:stations:sftp-user'); + + $group->put( + '/sftp-user/{id}', + Controller\Api\Stations\SftpUsersController::class . ':editAction' + ); + $group->delete( + '/sftp-user/{id}', + Controller\Api\Stations\SftpUsersController::class . ':deleteAction' + ); + } + )->add(new Middleware\StationSupportsFeature(StationFeatures::Sftp)) + ->add(new Middleware\Permissions(StationPermissions::Media, true)); + + /* + * Mount Points + */ + $group->group( + '', + function (RouteCollectorProxy $group) { + $group->group( + '/mounts', + function (RouteCollectorProxy $group) { + $group->get( + '', + Controller\Api\Stations\MountsController::class . ':listAction' + )->setName('api:stations:mounts'); + + $group->post( + '', + Controller\Api\Stations\MountsController::class . ':createAction' + ); + + $group->post( + '/intro', + Controller\Api\Stations\Mounts\Intro\PostIntroAction::class + )->setName('api:stations:mounts:new-intro'); + } + ); + + $group->group( + '/mount/{id}', + function (RouteCollectorProxy $group) { + $group->get( + '', + Controller\Api\Stations\MountsController::class . ':getAction' + )->setName('api:stations:mount'); + + $group->put( + '', + Controller\Api\Stations\MountsController::class . ':editAction' + ); + + $group->delete( + '', + Controller\Api\Stations\MountsController::class . ':deleteAction' + ); + + $group->get( + '/intro', + Controller\Api\Stations\Mounts\Intro\GetIntroAction::class + )->setName('api:stations:mounts:intro'); + + $group->post( + '/intro', + Controller\Api\Stations\Mounts\Intro\PostIntroAction::class + ); + + $group->delete( + '/intro', + Controller\Api\Stations\Mounts\Intro\DeleteIntroAction::class + ); + } + ); + } + )->add(new Middleware\StationSupportsFeature(StationFeatures::MountPoints)) ->add(new Middleware\Permissions(StationPermissions::MountPoints, true)); + /* + * Remote Relays + */ $group->group( - '/mount/{id}', + '', function (RouteCollectorProxy $group) { $group->get( - '/intro', - Controller\Api\Stations\Mounts\Intro\GetIntroAction::class - )->setName('api:stations:mounts:intro'); + '/remotes', + Controller\Api\Stations\RemotesController::class . ':listAction' + )->setName('api:stations:remotes'); $group->post( - '/intro', - Controller\Api\Stations\Mounts\Intro\PostIntroAction::class + '/remotes', + Controller\Api\Stations\RemotesController::class . ':createAction' + ); + + $group->get( + '/remote/{id}', + Controller\Api\Stations\RemotesController::class . ':getAction' + )->setName('api:stations:remote'); + + $group->put( + '/remote/{id}', + Controller\Api\Stations\RemotesController::class . ':editAction' ); $group->delete( - '/intro', - Controller\Api\Stations\Mounts\Intro\DeleteIntroAction::class + '/remote/{id}', + Controller\Api\Stations\RemotesController::class . ':deleteAction' ); } - )->add(new Middleware\Permissions(StationPermissions::MountPoints, true)); + )->add(new Middleware\StationSupportsFeature(StationFeatures::RemoteRelays)) + ->add(new Middleware\Permissions(StationPermissions::RemoteRelays, true)); - $group->get( - '/playlists/schedule', - Controller\Api\Stations\PlaylistsController::class . ':scheduleAction' - ) - ->setName('api:stations:playlists:schedule') + /* + * HLS Streams + */ + $group->group( + '', + function (RouteCollectorProxy $group) { + $group->get( + '/hls_streams', + Controller\Api\Stations\HlsStreamsController::class . ':listAction' + )->setName('api:stations:hls_streams'); + + $group->post( + '/hls_streams', + Controller\Api\Stations\HlsStreamsController::class . ':createAction' + ); + + $group->get( + '/hls_stream/{id}', + Controller\Api\Stations\HlsStreamsController::class . ':getAction' + )->setName('api:stations:hls_stream'); + + $group->put( + '/hls_stream/{id}', + Controller\Api\Stations\HlsStreamsController::class . ':editAction' + ); + + $group->delete( + '/hls_stream/{id}', + Controller\Api\Stations\HlsStreamsController::class . ':deleteAction' + ); + } + )->add(new Middleware\StationSupportsFeature(StationFeatures::HlsStreams)) + ->add(new Middleware\Permissions(StationPermissions::MountPoints, true)); + + /* + * Playlist + */ + $group->group( + '', + function (RouteCollectorProxy $group) { + $group->get( + '/playlists', + Controller\Api\Stations\PlaylistsController::class . ':listAction' + )->setName('api:stations:playlists'); + + $group->post( + '/playlists', + Controller\Api\Stations\PlaylistsController::class . ':createAction' + ); + + $group->get( + '/playlists/schedule', + Controller\Api\Stations\PlaylistsController::class . ':scheduleAction' + )->setName('api:stations:playlists:schedule'); + + $group->group( + '/playlist/{id}', + function (RouteCollectorProxy $group) { + $group->get( + '', + Controller\Api\Stations\PlaylistsController::class . ':getAction' + )->setName('api:stations:playlist'); + + $group->put( + '', + Controller\Api\Stations\PlaylistsController::class . ':editAction' + ); + + $group->delete( + '', + Controller\Api\Stations\PlaylistsController::class . ':deleteAction' + ); + + $group->put( + '/toggle', + Controller\Api\Stations\Playlists\ToggleAction::class + )->setName('api:stations:playlist:toggle'); + + $group->put( + '/reshuffle', + Controller\Api\Stations\Playlists\ReshuffleAction::class + )->setName('api:stations:playlist:reshuffle'); + + $group->get( + '/order', + Controller\Api\Stations\Playlists\GetOrderAction::class + )->setName('api:stations:playlist:order'); + + $group->put( + '/order', + Controller\Api\Stations\Playlists\PutOrderAction::class + ); + + $group->get( + '/queue', + Controller\Api\Stations\Playlists\GetQueueAction::class + )->setName('api:stations:playlist:queue'); + + $group->delete( + '/queue', + Controller\Api\Stations\Playlists\DeleteQueueAction::class + ); + + $group->post( + '/clone', + Controller\Api\Stations\Playlists\CloneAction::class + )->setName('api:stations:playlist:clone'); + + $group->post( + '/import', + Controller\Api\Stations\Playlists\ImportAction::class + )->setName('api:stations:playlist:import'); + + $group->get( + '/export[/{format}]', + Controller\Api\Stations\Playlists\ExportAction::class + )->setName('api:stations:playlist:export'); + } + ); + } + )->add(new Middleware\StationSupportsFeature(StationFeatures::Media)) ->add(new Middleware\Permissions(StationPermissions::Media, true)); - $group->group( - '/playlist/{id}', - function (RouteCollectorProxy $group) { - $group->put( - '/toggle', - Controller\Api\Stations\Playlists\ToggleAction::class - )->setName('api:stations:playlist:toggle'); - - $group->put( - '/reshuffle', - Controller\Api\Stations\Playlists\ReshuffleAction::class - )->setName('api:stations:playlist:reshuffle'); - - $group->get( - '/order', - Controller\Api\Stations\Playlists\GetOrderAction::class - )->setName('api:stations:playlist:order'); - - $group->put( - '/order', - Controller\Api\Stations\Playlists\PutOrderAction::class - ); - - $group->get( - '/queue', - Controller\Api\Stations\Playlists\GetQueueAction::class - )->setName('api:stations:playlist:queue'); - - $group->delete( - '/queue', - Controller\Api\Stations\Playlists\DeleteQueueAction::class - ); - - $group->post( - '/clone', - Controller\Api\Stations\Playlists\CloneAction::class - )->setName('api:stations:playlist:clone'); - - $group->post( - '/import', - Controller\Api\Stations\Playlists\ImportAction::class - )->setName('api:stations:playlist:import'); - - $group->get( - '/export[/{format}]', - Controller\Api\Stations\Playlists\ExportAction::class - )->setName('api:stations:playlist:export'); - } - )->add(new Middleware\Permissions(StationPermissions::Media, true)); - + /* + * Reports + */ $group->group( '/reports', function (RouteCollectorProxy $group) { @@ -539,40 +626,94 @@ return static function (RouteCollectorProxy $group) { } )->add(new Middleware\Permissions(StationPermissions::Reports, true)); + /* + * Streamers Extras + */ $group->get( - '/streamers/schedule', - Controller\Api\Stations\StreamersController::class . ':scheduleAction' - ) - ->setName('api:stations:streamers:schedule') - ->add(new Middleware\Permissions(StationPermissions::Streamers, true)); - - $group->get( - '/streamers/broadcasts', - Controller\Api\Stations\Streamers\BroadcastsController::class . ':listAction' - ) - ->setName('api:stations:streamers:broadcasts') - ->add(new Middleware\Permissions(StationPermissions::Streamers, true)); + '/streamer/{id}/art', + Controller\Api\Stations\Streamers\Art\GetArtAction::class + )->setName('api:stations:streamer:art'); $group->group( - '/streamer/{streamer_id}', + '', function (RouteCollectorProxy $group) { - $group->get( - '/broadcasts', - Controller\Api\Stations\Streamers\BroadcastsController::class . ':listAction' - )->setName('api:stations:streamer:broadcasts'); + $group->group( + '/streamers', + function (RouteCollectorProxy $group) { + $group->get( + '', + Controller\Api\Stations\StreamersController::class . ':listAction' + )->setName('api:stations:streamers'); - $group->get( - '/broadcast/{broadcast_id}/download', - Controller\Api\Stations\Streamers\BroadcastsController::class . ':downloadAction' - )->setName('api:stations:streamer:broadcast:download'); + $group->post( + '', + Controller\Api\Stations\StreamersController::class . ':createAction' + ); - $group->delete( - '/broadcast/{broadcast_id}', - Controller\Api\Stations\Streamers\BroadcastsController::class . ':deleteAction' - ) - ->setName('api:stations:streamer:broadcast:delete'); + $group->get( + '/schedule', + Controller\Api\Stations\StreamersController::class . ':scheduleAction' + )->setName('api:stations:streamers:schedule'); + + $group->get( + '/broadcasts', + Controller\Api\Stations\Streamers\BroadcastsController::class . ':listAction' + )->setName('api:stations:streamers:broadcasts'); + + $group->post( + '/art', + Controller\Api\Stations\Streamers\Art\PostArtAction::class + )->setName('api:stations:streamers:new-art'); + } + ); + + $group->group( + '/streamer/{id}', + function (RouteCollectorProxy $group) { + $group->get( + '', + Controller\Api\Stations\StreamersController::class . ':getAction' + )->setName('api:stations:streamer'); + + $group->put( + '', + Controller\Api\Stations\StreamersController::class . ':editAction' + ); + + $group->delete( + '', + Controller\Api\Stations\StreamersController::class . ':deleteAction' + ); + + $group->get( + '/broadcasts', + Controller\Api\Stations\Streamers\BroadcastsController::class . ':listAction' + )->setName('api:stations:streamer:broadcasts'); + + $group->get( + '/broadcast/{broadcast_id}/download', + Controller\Api\Stations\Streamers\BroadcastsController::class . ':downloadAction' + )->setName('api:stations:streamer:broadcast:download'); + + $group->delete( + '/broadcast/{broadcast_id}', + Controller\Api\Stations\Streamers\BroadcastsController::class . ':deleteAction' + )->setName('api:stations:streamer:broadcast:delete'); + + $group->post( + '/art', + Controller\Api\Stations\Streamers\Art\PostArtAction::class + )->setName('api:stations:streamer:art-internal'); + + $group->delete( + '/art', + Controller\Api\Stations\Streamers\Art\DeleteArtAction::class + ); + } + ); } - )->add(new Middleware\Permissions(StationPermissions::Streamers, true)); + )->add(new Middleware\StationSupportsFeature(StationFeatures::Streamers)) + ->add(new Middleware\Permissions(StationPermissions::Streamers, true)); $group->get('/restart-status', Controller\Api\Stations\GetRestartStatusAction::class) ->setName('api:stations:restart-status') @@ -589,8 +730,7 @@ return static function (RouteCollectorProxy $group) { $group->post( '/frontend/{do}', Controller\Api\Stations\ServicesController::class . ':frontendAction' - ) - ->setName('api:stations:frontend') + )->setName('api:stations:frontend') ->add(new Middleware\Permissions(StationPermissions::Broadcasting, true)); $group->post('/reload', Controller\Api\Stations\ServicesController::class . ':reloadAction') @@ -601,6 +741,9 @@ return static function (RouteCollectorProxy $group) { ->setName('api:stations:restart') ->add(new Middleware\Permissions(StationPermissions::Broadcasting, true)); + /* + * Custom Fallback File + */ $group->group( '/fallback', function (RouteCollectorProxy $group) { @@ -621,26 +764,104 @@ return static function (RouteCollectorProxy $group) { } )->add(new Middleware\Permissions(StationPermissions::Broadcasting, true)); + /* + * Webhook Extras + */ $group->group( - '/webhook/{id}', + '', function (RouteCollectorProxy $group) { - $group->put( - '/toggle', - Controller\Api\Stations\Webhooks\ToggleAction::class - )->setName('api:stations:webhook:toggle'); - - $group->put( - '/test', - Controller\Api\Stations\Webhooks\TestAction::class - )->setName('api:stations:webhook:test'); - $group->get( - '/test-log/{path}', - Controller\Api\Stations\Webhooks\TestLogAction::class - )->setName('api:stations:webhook:test-log'); - } - )->add(new Middleware\Permissions(StationPermissions::WebHooks, true)); + '/webhooks', + Controller\Api\Stations\WebhooksController::class . ':listAction' + )->setName('api:stations:webhooks'); + $group->post( + '/webhooks', + Controller\Api\Stations\WebhooksController::class . ':createAction' + ); + + $group->group( + '/webhook/{id}', + function (RouteCollectorProxy $group) { + $group->get( + '', + Controller\Api\Stations\WebhooksController::class . ':getAction' + )->setName('api:stations:webhook'); + + $group->put( + '', + Controller\Api\Stations\WebhooksController::class . ':editAction' + ); + + $group->delete( + '', + Controller\Api\Stations\WebhooksController::class . ':deleteAction' + ); + + $group->put( + '/toggle', + Controller\Api\Stations\Webhooks\ToggleAction::class + )->setName('api:stations:webhook:toggle'); + + $group->put( + '/test', + Controller\Api\Stations\Webhooks\TestAction::class + )->setName('api:stations:webhook:test'); + + $group->get( + '/test-log/{path}', + Controller\Api\Stations\Webhooks\TestLogAction::class + )->setName('api:stations:webhook:test-log'); + } + ); + } + )->add(new Middleware\StationSupportsFeature(StationFeatures::Webhooks)) + ->add(new Middleware\Permissions(StationPermissions::WebHooks, true)); + + /* + * Custom Liquidsoap Configuration + */ + $group->group( + '/liquidsoap-config', + function (RouteCollectorProxy $group) { + $group->get( + '', + Controller\Api\Stations\LiquidsoapConfig\GetAction::class + )->setName('api:stations:liquidsoap-config'); + + $group->put( + '', + Controller\Api\Stations\LiquidsoapConfig\PutAction::class + ); + } + )->add(new Middleware\Permissions(StationPermissions::Broadcasting, true)); + + /* + * StereoTool Configuration + */ + $group->group( + '/stereo_tool_config', + function (RouteCollectorProxy $group) { + $group->get( + '', + Controller\Api\Stations\StereoTool\GetStereoToolConfigurationAction::class + )->setName('api:stations:stereo_tool_config'); + + $group->post( + '', + Controller\Api\Stations\StereoTool\PostStereoToolConfigurationAction::class + ); + + $group->delete( + '', + Controller\Api\Stations\StereoTool\DeleteStereoToolConfigurationAction::class + ); + } + )->add(new Middleware\Permissions(StationPermissions::Broadcasting, true)); + + /* + * Logs + */ $group->group( '', function (RouteCollectorProxy $group) { diff --git a/config/routes/stations.php b/config/routes/stations.php index 27a1f1a5d..f149ab29a 100644 --- a/config/routes/stations.php +++ b/config/routes/stations.php @@ -1,6 +1,7 @@ get('/files', Controller\Stations\FilesAction::class) ->setName('stations:files:index') + ->add(new Middleware\StationSupportsFeature(StationFeatures::Media)) ->add(new Middleware\Permissions(StationPermissions::Media, true)); $group->get('/hls_streams', Controller\Stations\HlsStreamsAction::class) ->setName('stations:hls_streams:index') + ->add(new Middleware\StationSupportsFeature(StationFeatures::HlsStreams)) ->add(new Middleware\Permissions(StationPermissions::MountPoints, true)); $group->get('/ls_config', Controller\Stations\EditLiquidsoapConfigAction::class) ->setName('stations:util:ls_config') + ->add(new Middleware\StationSupportsFeature(StationFeatures::CustomLiquidsoapConfig)) ->add(new Middleware\Permissions(StationPermissions::Broadcasting, true)); $group->get('/stereo_tool_config', Controller\Stations\UploadStereoToolConfigAction::class) @@ -50,14 +54,17 @@ return static function (RouteCollectorProxy $app) { $group->get('/playlists', Controller\Stations\PlaylistsAction::class) ->setName('stations:playlists:index') + ->add(new Middleware\StationSupportsFeature(StationFeatures::Media)) ->add(new Middleware\Permissions(StationPermissions::Media, true)); $group->get('/podcasts', Controller\Stations\PodcastsAction::class) ->setName('stations:podcasts:index') + ->add(new Middleware\StationSupportsFeature(StationFeatures::Podcasts)) ->add(new Middleware\Permissions(StationPermissions::Podcasts, true)); $group->get('/mounts', Controller\Stations\MountsAction::class) ->setName('stations:mounts:index') + ->add(new Middleware\StationSupportsFeature(StationFeatures::MountPoints)) ->add(new Middleware\Permissions(StationPermissions::MountPoints, true)); $group->get('/profile', Controller\Stations\ProfileController::class) @@ -76,10 +83,12 @@ return static function (RouteCollectorProxy $app) { $group->get('/queue', Controller\Stations\QueueAction::class) ->setName('stations:queue:index') + ->add(new Middleware\StationSupportsFeature(StationFeatures::Media)) ->add(new Middleware\Permissions(StationPermissions::Broadcasting, true)); $group->get('/remotes', Controller\Stations\RemotesAction::class) ->setName('stations:remotes:index') + ->add(new Middleware\StationSupportsFeature(StationFeatures::RemoteRelays)) ->add(new Middleware\Permissions(StationPermissions::RemoteRelays, true)); $group->group( @@ -108,14 +117,17 @@ return static function (RouteCollectorProxy $app) { $group->get('/sftp_users', Controller\Stations\SftpUsersAction::class) ->setName('stations:sftp_users:index') + ->add(new Middleware\StationSupportsFeature(StationFeatures::Sftp)) ->add(new Middleware\Permissions(StationPermissions::Media, true)); $group->get('/streamers', Controller\Stations\StreamersAction::class) ->setName('stations:streamers:index') + ->add(new Middleware\StationSupportsFeature(StationFeatures::Streamers)) ->add(new Middleware\Permissions(StationPermissions::Streamers, true)); $group->get('/webhooks', Controller\Stations\WebhooksAction::class) ->setName('stations:webhooks:index') + ->add(new Middleware\StationSupportsFeature(StationFeatures::Webhooks)) ->add(new Middleware\Permissions(StationPermissions::WebHooks, true)); } ) diff --git a/src/Controller/Api/Stations/HlsStreamsController.php b/src/Controller/Api/Stations/HlsStreamsController.php index 98107287e..33b22deeb 100644 --- a/src/Controller/Api/Stations/HlsStreamsController.php +++ b/src/Controller/Api/Stations/HlsStreamsController.php @@ -5,8 +5,6 @@ declare(strict_types=1); namespace App\Controller\Api\Stations; use App\Entity; -use App\Exception\StationUnsupportedException; -use App\Http\ServerRequest; use App\OpenApi; use OpenApi\Attributes as OA; @@ -137,18 +135,4 @@ final class HlsStreamsController extends AbstractStationApiCrudController { protected string $entityClass = Entity\StationHlsStream::class; protected string $resourceRouteName = 'api:stations:hls_stream'; - - /** - * @inheritDoc - */ - protected function getStation(ServerRequest $request): Entity\Station - { - $station = parent::getStation($request); - - if (!$station->getBackendTypeEnum()->isEnabled()) { - throw new StationUnsupportedException(); - } - - return $station; - } } diff --git a/src/Controller/Api/Stations/MountsController.php b/src/Controller/Api/Stations/MountsController.php index a62c396bc..309573fc4 100644 --- a/src/Controller/Api/Stations/MountsController.php +++ b/src/Controller/Api/Stations/MountsController.php @@ -7,7 +7,6 @@ namespace App\Controller\Api\Stations; use App\Controller\Api\Traits\CanSortResults; use App\Doctrine\ReloadableEntityManagerInterface; use App\Entity; -use App\Exception\StationUnsupportedException; use App\Http\Response; use App\Http\Router; use App\Http\ServerRequest; @@ -256,18 +255,4 @@ final class MountsController extends AbstractStationApiCrudController return $response->withJson(Entity\Api\Status::deleted()); } - - /** - * @inheritDoc - */ - protected function getStation(ServerRequest $request): Entity\Station - { - $station = parent::getStation($request); - - if (!$station->getFrontendTypeEnum()->supportsMounts()) { - throw new StationUnsupportedException(); - } - - return $station; - } } diff --git a/src/Controller/Api/Stations/Streamers/Art/DeleteArtAction.php b/src/Controller/Api/Stations/Streamers/Art/DeleteArtAction.php index 880d94f95..3900abe47 100644 --- a/src/Controller/Api/Stations/Streamers/Art/DeleteArtAction.php +++ b/src/Controller/Api/Stations/Streamers/Art/DeleteArtAction.php @@ -21,11 +21,11 @@ final class DeleteArtAction ServerRequest $request, Response $response, string $station_id, - string $streamer_id + string $id ): ResponseInterface { $station = $request->getStation(); - $streamer = $this->streamerRepo->requireForStation($streamer_id, $station); + $streamer = $this->streamerRepo->requireForStation($id, $station); $this->streamerRepo->removeArtwork($streamer); $this->streamerRepo->getEntityManager() diff --git a/src/Controller/Api/Stations/Streamers/Art/GetArtAction.php b/src/Controller/Api/Stations/Streamers/Art/GetArtAction.php index 27c613ab4..9d0aeb855 100644 --- a/src/Controller/Api/Stations/Streamers/Art/GetArtAction.php +++ b/src/Controller/Api/Stations/Streamers/Art/GetArtAction.php @@ -21,14 +21,14 @@ final class GetArtAction ServerRequest $request, Response $response, string $station_id, - string $streamer_id + string $id ): ResponseInterface { // If a timestamp delimiter is added, strip it automatically. - $streamer_id = explode('|', $streamer_id, 2)[0]; + $id = explode('|', $id, 2)[0]; $station = $request->getStation(); - $artworkPath = Entity\StationStreamer::getArtworkPath($streamer_id); + $artworkPath = Entity\StationStreamer::getArtworkPath($id); $fsConfig = (new StationFilesystems($station))->getConfigFilesystem(); if ($fsConfig->fileExists($artworkPath)) { diff --git a/src/Controller/Api/Stations/Streamers/Art/PostArtAction.php b/src/Controller/Api/Stations/Streamers/Art/PostArtAction.php index 359aa3491..a7f0b950c 100644 --- a/src/Controller/Api/Stations/Streamers/Art/PostArtAction.php +++ b/src/Controller/Api/Stations/Streamers/Art/PostArtAction.php @@ -21,7 +21,7 @@ final class PostArtAction ServerRequest $request, Response $response, string $station_id, - ?string $streamer_id = null + ?string $id = null ): ResponseInterface { $station = $request->getStation(); @@ -30,8 +30,8 @@ final class PostArtAction return $flowResponse; } - if (null !== $streamer_id) { - $streamer = $this->streamerRepo->requireForStation($streamer_id, $station); + if (null !== $id) { + $streamer = $this->streamerRepo->requireForStation($id, $station); $this->streamerRepo->writeArtwork( $streamer, diff --git a/src/Controller/Api/Stations/Streamers/BroadcastsController.php b/src/Controller/Api/Stations/Streamers/BroadcastsController.php index cc60dd820..19ff22c88 100644 --- a/src/Controller/Api/Stations/Streamers/BroadcastsController.php +++ b/src/Controller/Api/Stations/Streamers/BroadcastsController.php @@ -25,12 +25,12 @@ final class BroadcastsController extends AbstractApiCrudController ServerRequest $request, Response $response, string $station_id, - ?string $streamer_id = null + ?string $id = null ): ResponseInterface { $station = $request->getStation(); - if (null !== $streamer_id) { - $streamer = $this->getStreamer($station, $streamer_id); + if (null !== $id) { + $streamer = $this->getStreamer($station, $id); if (null === $streamer) { return $response->withStatus(404) @@ -66,13 +66,13 @@ final class BroadcastsController extends AbstractApiCrudController $fsRecordings = (new StationFilesystems($station))->getRecordingsFilesystem(); $paginator->setPostprocessor( - function ($row) use ($streamer_id, $is_bootgrid, $router, $fsRecordings) { + function ($row) use ($id, $is_bootgrid, $router, $fsRecordings) { $return = $this->toArray($row); unset($return['recordingPath']); $recordingPath = $row->getRecordingPath(); - if (null === $streamer_id) { + if (null === $id) { $streamer = $row->getStreamer(); $return['streamer'] = [ 'id' => $streamer->getId(), @@ -85,7 +85,7 @@ final class BroadcastsController extends AbstractApiCrudController $routeParams = [ 'broadcast_id' => $row->getId(), ]; - if (null === $streamer_id) { + if (null === $id) { $routeParams['id'] = $row->getStreamer()->getId(); } @@ -126,7 +126,7 @@ final class BroadcastsController extends AbstractApiCrudController ServerRequest $request, Response $response, string $station_id, - string $streamer_id, + string $id, string $broadcast_id ): ResponseInterface { $station = $request->getStation(); @@ -159,7 +159,7 @@ final class BroadcastsController extends AbstractApiCrudController ServerRequest $request, Response $response, string $station_id, - string $streamer_id, + string $id, string $broadcast_id ): ResponseInterface { $station = $request->getStation(); diff --git a/src/Controller/Api/Stations/StreamersController.php b/src/Controller/Api/Stations/StreamersController.php index b58beaf75..44e806640 100644 --- a/src/Controller/Api/Stations/StreamersController.php +++ b/src/Controller/Api/Stations/StreamersController.php @@ -7,7 +7,6 @@ namespace App\Controller\Api\Stations; use App\Controller\Api\Traits\CanSortResults; use App\Doctrine\ReloadableEntityManagerInterface; use App\Entity; -use App\Exception\StationUnsupportedException; use App\Http\Response; use App\Http\ServerRequest; use App\OpenApi; @@ -286,38 +285,24 @@ final class StreamersController extends AbstractScheduledEntityController $return['has_custom_art'] = (0 !== $record->getArtUpdatedAt()); $return['art'] = (string)$router->fromHere( route_name: 'api:stations:streamer:art', - route_params: ['streamer_id' => $record->getIdRequired() . '|' . $record->getArtUpdatedAt()], + route_params: ['id' => $record->getIdRequired() . '|' . $record->getArtUpdatedAt()], absolute: !$isInternal ); $return['links']['broadcasts'] = (string)$router->fromHere( route_name: 'api:stations:streamer:broadcasts', - route_params: ['streamer_id' => $record->getId()], + route_params: ['id' => $record->getId()], absolute: !$isInternal ); $return['links']['art'] = (string)$router->fromHere( route_name: 'api:stations:streamer:art-internal', - route_params: ['streamer_id' => $record->getId()], + route_params: ['id' => $record->getId()], absolute: !$isInternal ); return $return; } - /** - * @inheritDoc - */ - protected function getStation(ServerRequest $request): Entity\Station - { - $station = parent::getStation($request); - - if (!$station->getBackendTypeEnum()->isEnabled()) { - throw new StationUnsupportedException(); - } - - return $station; - } - protected function deleteRecord(object $record): void { if (!($record instanceof Entity\StationStreamer)) { diff --git a/src/Controller/Stations/EditLiquidsoapConfigAction.php b/src/Controller/Stations/EditLiquidsoapConfigAction.php index 6753349ef..a6a59266d 100644 --- a/src/Controller/Stations/EditLiquidsoapConfigAction.php +++ b/src/Controller/Stations/EditLiquidsoapConfigAction.php @@ -6,7 +6,6 @@ namespace App\Controller\Stations; use App\Entity\StationBackendConfiguration; use App\Event\Radio\WriteLiquidsoapConfiguration; -use App\Exception\StationUnsupportedException; use App\Http\Response; use App\Http\ServerRequest; use App\Radio\Backend\Liquidsoap; @@ -27,10 +26,6 @@ final class EditLiquidsoapConfigAction ): ResponseInterface { $station = $request->getStation(); - if (!$station->getBackendTypeEnum()->isEnabled()) { - throw new StationUnsupportedException(); - } - $configSections = StationBackendConfiguration::getCustomConfigurationSections(); $tokens = Liquidsoap\ConfigWriter::getDividerString(); diff --git a/src/Controller/Stations/HlsStreamsAction.php b/src/Controller/Stations/HlsStreamsAction.php index a4892aef4..f796ad41e 100644 --- a/src/Controller/Stations/HlsStreamsAction.php +++ b/src/Controller/Stations/HlsStreamsAction.php @@ -4,7 +4,6 @@ declare(strict_types=1); namespace App\Controller\Stations; -use App\Exception\StationUnsupportedException; use App\Http\Response; use App\Http\ServerRequest; use Psr\Http\Message\ResponseInterface; @@ -16,12 +15,6 @@ final class HlsStreamsAction Response $response, string $station_id ): ResponseInterface { - $station = $request->getStation(); - - if (!$station->getBackendTypeEnum()->isEnabled() || !$station->getEnableHls()) { - throw new StationUnsupportedException(); - } - $router = $request->getRouter(); return $request->getView()->renderVuePage( response: $response, diff --git a/src/Enums/StationFeatures.php b/src/Enums/StationFeatures.php new file mode 100644 index 000000000..9435ab38d --- /dev/null +++ b/src/Enums/StationFeatures.php @@ -0,0 +1,34 @@ +getBackendTypeEnum()->isEnabled(); + + return match ($this) { + self::Media, self::RemoteRelays, self::CustomLiquidsoapConfig => $backendEnabled, + self::Streamers => $backendEnabled && $station->getEnableStreamers(), + self::Sftp => $backendEnabled && $station->getMediaStorageLocation()->isLocal(), + self::MountPoints => $station->getFrontendTypeEnum()->supportsMounts(), + self::HlsStreams => $backendEnabled && $station->getEnableHls(), + self::Webhooks, self::Podcasts => true, + }; + } +} diff --git a/src/Middleware/StationSupportsFeature.php b/src/Middleware/StationSupportsFeature.php new file mode 100644 index 000000000..6900333c7 --- /dev/null +++ b/src/Middleware/StationSupportsFeature.php @@ -0,0 +1,28 @@ +feature->supportedForStation($request->getStation())) { + throw new Exception\StationUnsupportedException(); + } + + return $handler->handle($request); + } +} diff --git a/tests/Functional/Api_Stations_StreamersCest.php b/tests/Functional/Api_Stations_StreamersCest.php index b00d69c7c..49ca9091b 100644 --- a/tests/Functional/Api_Stations_StreamersCest.php +++ b/tests/Functional/Api_Stations_StreamersCest.php @@ -14,6 +14,10 @@ class Api_Stations_StreamersCest extends CestAbstract // Create new record $station = $this->getTestStation(); + $station->setEnableStreamers(true); + $this->em->persist($station); + $this->em->flush(); + $listUrl = '/api/station/' . $station->getId() . '/streamers'; $I->sendPOST(