From 8cfeae603f45a0a35e99dc57039ec95af91d0069 Mon Sep 17 00:00:00 2001 From: JVT038 <47184046+JVT038@users.noreply.github.com> Date: Sun, 3 Sep 2023 21:55:39 +0200 Subject: [PATCH 01/11] Added middleware logic and a couple of basic ones. --- bootstrap.php | 1 + public/index.php | 18 ++++++- settings/routes.php | 33 ++++++------ src/Factory.php | 6 +++ .../Middleware/DoesNotHaveUsers.php | 21 ++++++++ .../Middleware/HasJellyfinToken.php | 25 +++++++++ .../Middleware/HasPlexAccessToken.php | 23 ++++++++ .../Middleware/HasUsersCheck.php | 21 ++++++++ src/HttpController/Middleware/IsAdmin.php | 21 ++++++++ .../Middleware/RegistrationEnabledCheck.php | 20 +++++++ .../Middleware/isAuthenticated.php | 22 ++++++++ .../Middleware/isUnauthenticated.php | 21 ++++++++ .../Web/AuthenticationController.php | 8 --- .../Web/CreateUserController.php | 17 ------ src/HttpController/Web/JobController.php | 53 ------------------- .../Web/LandingPageController.php | 14 ++--- src/HttpController/Web/SettingsController.php | 6 +-- .../Web/TwoFactorAuthenticationController.php | 8 --- src/Service/MiddlewareService.php | 11 ++++ src/Service/RouterService.php | 30 +++++++++++ src/ValueObject/Http/Request.php | 2 +- .../settings-integration-jellyfin.html.twig | 14 ++--- 22 files changed, 271 insertions(+), 124 deletions(-) create mode 100644 src/HttpController/Middleware/DoesNotHaveUsers.php create mode 100644 src/HttpController/Middleware/HasJellyfinToken.php create mode 100644 src/HttpController/Middleware/HasPlexAccessToken.php create mode 100644 src/HttpController/Middleware/HasUsersCheck.php create mode 100644 src/HttpController/Middleware/IsAdmin.php create mode 100644 src/HttpController/Middleware/RegistrationEnabledCheck.php create mode 100644 src/HttpController/Middleware/isAuthenticated.php create mode 100644 src/HttpController/Middleware/isUnauthenticated.php create mode 100644 src/Service/MiddlewareService.php create mode 100644 src/Service/RouterService.php diff --git a/bootstrap.php b/bootstrap.php index bd3a081f..1585c1c6 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -19,6 +19,7 @@ \Movary\HttpController\Web\JobController::class => DI\factory([Factory::class, 'createJobController']), \Movary\HttpController\Web\LandingPageController::class => DI\factory([Factory::class, 'createLandingPageController']), \Movary\HttpController\Web\SettingsController::class => DI\factory([Factory::class, 'createSettingsController']), + \Movary\HttpController\Middleware\RegistrationEnabledCheck::class => DI\factory([Factory::class, 'createRegistrationEnabledCheck']), \Movary\ValueObject\Http\Request::class => DI\factory([Factory::class, 'createCurrentHttpRequest']), \Movary\Command\CreatePublicStorageLink::class => DI\factory([Factory::class, 'createCreatePublicStorageLink']), \Movary\Command\DatabaseMigrationStatus::class => DI\factory([Factory::class, 'createDatabaseMigrationStatusCommand']), diff --git a/public/index.php b/public/index.php index dbbc03aa..db94e3a3 100644 --- a/public/index.php +++ b/public/index.php @@ -34,9 +34,23 @@ $response = Response::createMethodNotAllowed(); break; case FastRoute\Dispatcher::FOUND: - $handler = $routeInfo[1]; + $handler = is_array($routeInfo[1][0]) ? $routeInfo[1][0] : $routeInfo[1]; $httpRequest->addRouteParameters($routeInfo[2]); - + + if(array_key_exists('middleware', $routeInfo[1])) { + foreach($routeInfo[1]['middleware'] as $middleware) { + if(class_exists($middleware)) { + $middlewareResponse = $container->call([$middleware, 'main']); + if($middlewareResponse instanceof Response) { + $response = $middlewareResponse; + break 2; + } + } else { + $container->get(LoggerInterface::class)->warning('The class '. $middleware . 'does not exist!'); + } + } + } + $response = $container->call($handler, [$httpRequest]); break; default: diff --git a/settings/routes.php b/settings/routes.php index 1c145d50..a53c50ea 100644 --- a/settings/routes.php +++ b/settings/routes.php @@ -2,6 +2,7 @@ use Movary\HttpController\Api; use Movary\HttpController\Web; +use Movary\HttpController\Middleware; return static function (FastRoute\RouteCollector $routeCollector) { $routeCollector->addGroup('', fn(FastRoute\RouteCollector $routeCollector) => addWebRoutes($routeCollector)); @@ -10,13 +11,13 @@ function addWebRoutes(FastRoute\RouteCollector $routeCollector) : void { - $routeCollector->addRoute('GET', '/', [Web\LandingPageController::class, 'render']); + $routeCollector->addRoute('GET', '/', [[Web\LandingPageController::class, 'render'], 'middleware' => [Middleware\isUnauthenticated::class, Middleware\DoesNotHaveUsers::class]]); $routeCollector->addRoute('POST', '/login', [Web\AuthenticationController::class, 'login']); - $routeCollector->addRoute('GET', '/login', [Web\AuthenticationController::class, 'renderLoginPage']); - $routeCollector->addRoute('POST', '/verify-totp', [Web\TwoFactorAuthenticationController::class, 'verifyTotp']); + $routeCollector->addRoute('GET', '/login', [[Web\AuthenticationController::class, 'renderLoginPage'], 'middleware' => [Middleware\isUnauthenticated::class]]); + $routeCollector->addRoute('POST', '/verify-totp', [[Web\TwoFactorAuthenticationController::class, 'verifyTotp'], 'middleware' => [Middleware\isUnauthenticated::class]]); $routeCollector->addRoute('GET', '/logout', [Web\AuthenticationController::class, 'logout']); - $routeCollector->addRoute('POST', '/create-user', [Web\CreateUserController::class, 'createUser']); - $routeCollector->addRoute('GET', '/create-user', [Web\CreateUserController::class, 'renderPage']); + $routeCollector->addRoute('POST', '/create-user', [[Web\CreateUserController::class, 'createUser'], 'middleware' => [Middleware\isUnauthenticated::class, Middleware\HasUsersCheck::class, Middleware\RegistrationEnabledCheck::class]]); + $routeCollector->addRoute('GET', '/create-user', [[Web\CreateUserController::class, 'renderPage'], 'middleware' => [Middleware\isUnauthenticated::class, Middleware\HasUsersCheck::class, Middleware\RegistrationEnabledCheck::class]]); $routeCollector->addRoute('GET', '/docs/api', [Web\OpenApiController::class, 'renderPage']); ##################### @@ -29,21 +30,21 @@ function addWebRoutes(FastRoute\RouteCollector $routeCollector) : void ############# # Job Queue # ############# - $routeCollector->addRoute('GET', '/jobs', [Web\JobController::class, 'getJobs']); - $routeCollector->addRoute('GET', '/job-queue/purge-processed', [Web\JobController::class, 'purgeProcessedJobs']); - $routeCollector->addRoute('GET', '/job-queue/purge-all', [Web\JobController::class, 'purgeAllJobs']); - $routeCollector->addRoute('GET', '/jobs/schedule/trakt-history-sync', [Web\JobController::class, 'scheduleTraktHistorySync']); - $routeCollector->addRoute('GET', '/jobs/schedule/trakt-ratings-sync', [Web\JobController::class, 'scheduleTraktRatingsSync']); - $routeCollector->addRoute('POST', '/jobs/schedule/letterboxd-diary-sync', [Web\JobController::class, 'scheduleLetterboxdDiaryImport']); - $routeCollector->addRoute('POST', '/jobs/schedule/letterboxd-ratings-sync', [Web\JobController::class, 'scheduleLetterboxdRatingsImport']); - $routeCollector->addRoute('GET', '/jobs/schedule/plex-watchlist-sync', [Web\JobController::class, 'schedulePlexWatchlistImport']); - $routeCollector->addRoute('GET', '/jobs/schedule/jellyfin-import-history', [Web\JobController::class, 'scheduleJellyfinImportHistory']); - $routeCollector->addRoute('GET', '/jobs/schedule/jellyfin-export-history', [Web\JobController::class, 'scheduleJellyfinExportHistory']); + $routeCollector->addRoute('GET', '/jobs', [[Web\JobController::class, 'getJobs'], 'middleware' => [Middleware\isAuthenticated::class]]); + $routeCollector->addRoute('GET', '/job-queue/purge-processed', [[Web\JobController::class, 'purgeProcessedJobs'], 'middleware' => [Middleware\isAuthenticated::class]]); + $routeCollector->addRoute('GET', '/job-queue/purge-all', [[Web\JobController::class, 'purgeAllJobs'], 'middleware' => [Middleware\isAuthenticated::class]]); + $routeCollector->addRoute('GET', '/jobs/schedule/trakt-history-sync', [[Web\JobController::class, 'scheduleTraktHistorySync'], 'middleware' => [Middleware\isAuthenticated::class]]); + $routeCollector->addRoute('GET', '/jobs/schedule/trakt-ratings-sync', [[Web\JobController::class, 'scheduleTraktRatingsSync'], 'middleware' => [Middleware\isAuthenticated::class]]); + $routeCollector->addRoute('POST', '/jobs/schedule/letterboxd-diary-sync', [[Web\JobController::class, 'scheduleLetterboxdDiaryImport'], 'middleware' => [Middleware\isAuthenticated::class]]); + $routeCollector->addRoute('POST', '/jobs/schedule/letterboxd-ratings-sync', [[Web\JobController::class, 'scheduleLetterboxdRatingsImport'], 'middleware' => [Middleware\isAuthenticated::class]]); + $routeCollector->addRoute('GET', '/jobs/schedule/plex-watchlist-sync', [[Web\JobController::class, 'schedulePlexWatchlistImport'], 'middleware' => [Middleware\isAuthenticated::class, Middleware\HasPlexAccessToken::class]]); + $routeCollector->addRoute('GET', '/jobs/schedule/jellyfin-import-history', [[Web\JobController::class, 'scheduleJellyfinImportHistory'], 'middleware' => [Middleware\isAuthenticated::class, Middleware\HasJellyfinToken::class]]); + $routeCollector->addRoute('GET', '/jobs/schedule/jellyfin-export-history', [[Web\JobController::class, 'scheduleJellyfinExportHistory'], 'middleware' => [Middleware\isAuthenticated::class, Middleware\HasJellyfinToken::class]]); ############ # Settings # ############ - $routeCollector->addRoute('GET', '/settings/account/general', [Web\SettingsController::class, 'renderGeneralAccountPage']); + $routeCollector->addRoute('GET', '/settings/account/general', [[Web\SettingsController::class, 'renderGeneralAccountPage'], 'middleware' => [Middleware\isUnauthenticated::class]]); $routeCollector->addRoute('GET', '/settings/account/general/api-token', [Web\SettingsController::class, 'getApiToken'],); $routeCollector->addRoute('DELETE', '/settings/account/general/api-token', [Web\SettingsController::class, 'deleteApiToken'],); $routeCollector->addRoute('PUT', '/settings/account/general/api-token', [Web\SettingsController::class, 'regenerateApiToken'],); diff --git a/src/Factory.php b/src/Factory.php index d390f189..06665b44 100644 --- a/src/Factory.php +++ b/src/Factory.php @@ -25,6 +25,7 @@ use Movary\Domain\User\Service\TwoFactorAuthenticationApi; use Movary\Domain\User\UserApi; use Movary\HttpController\Api\OpenApiController; +use Movary\HttpController\Middleware; use Movary\HttpController\Web\CreateUserController; use Movary\HttpController\Web\JobController; use Movary\HttpController\Web\LandingPageController; @@ -262,6 +263,11 @@ public static function createLogger(ContainerInterface $container, Config $confi return $logger; } + public static function createRegistrationEnabledCheck(Config $config) : Middleware\RegistrationEnabledCheck + { + return new Middleware\RegistrationEnabledCheck($config->getAsBool('ENABLE_REGISTRATION', false)); + } + public static function createSettingsController(ContainerInterface $container, Config $config) : SettingsController { return new SettingsController( diff --git a/src/HttpController/Middleware/DoesNotHaveUsers.php b/src/HttpController/Middleware/DoesNotHaveUsers.php new file mode 100644 index 00000000..abc7fc93 --- /dev/null +++ b/src/HttpController/Middleware/DoesNotHaveUsers.php @@ -0,0 +1,21 @@ +userApi->hasUsers() === false) { + return Response::createSeeOther('/create-user'); + } + return null; + } +} \ No newline at end of file diff --git a/src/HttpController/Middleware/HasJellyfinToken.php b/src/HttpController/Middleware/HasJellyfinToken.php new file mode 100644 index 00000000..c3a837e6 --- /dev/null +++ b/src/HttpController/Middleware/HasJellyfinToken.php @@ -0,0 +1,25 @@ +userApi->findJellyfinAuthentication($this->authenticationService->getCurrentUserId()); + if ($jellyfinAuthentication === null) { + return Response::createBadRequest(JellyfinInvalidAuthentication::create()->getMessage()); + } + return null; + } +} \ No newline at end of file diff --git a/src/HttpController/Middleware/HasPlexAccessToken.php b/src/HttpController/Middleware/HasPlexAccessToken.php new file mode 100644 index 00000000..458e4c29 --- /dev/null +++ b/src/HttpController/Middleware/HasPlexAccessToken.php @@ -0,0 +1,23 @@ +authenticationService->getCurrentUser()->getPlexAccessToken() === null) { + return Response::createBadRequest(PlexAuthenticationMissing::create()->getMessage()); + } + return null; + } +} \ No newline at end of file diff --git a/src/HttpController/Middleware/HasUsersCheck.php b/src/HttpController/Middleware/HasUsersCheck.php new file mode 100644 index 00000000..907291e9 --- /dev/null +++ b/src/HttpController/Middleware/HasUsersCheck.php @@ -0,0 +1,21 @@ +userApi->hasUsers() === true) { + return Response::createSeeOther('/'); + } + return null; + } +} \ No newline at end of file diff --git a/src/HttpController/Middleware/IsAdmin.php b/src/HttpController/Middleware/IsAdmin.php new file mode 100644 index 00000000..93ddaf0f --- /dev/null +++ b/src/HttpController/Middleware/IsAdmin.php @@ -0,0 +1,21 @@ +authenticationService->getCurrentUser()->isAdmin() === false) { + return Response::createSeeOther('/'); + } + return null; + } +} \ No newline at end of file diff --git a/src/HttpController/Middleware/RegistrationEnabledCheck.php b/src/HttpController/Middleware/RegistrationEnabledCheck.php new file mode 100644 index 00000000..17410a2b --- /dev/null +++ b/src/HttpController/Middleware/RegistrationEnabledCheck.php @@ -0,0 +1,20 @@ +registrationEnabled === false) { + return Response::createSeeOther("/"); + } + return null; + } +} \ No newline at end of file diff --git a/src/HttpController/Middleware/isAuthenticated.php b/src/HttpController/Middleware/isAuthenticated.php new file mode 100644 index 00000000..9da2295f --- /dev/null +++ b/src/HttpController/Middleware/isAuthenticated.php @@ -0,0 +1,22 @@ +authenticationService->isUserAuthenticated() === true) { + $userName = $this->authenticationService->getCurrentUser()->getName(); + return Response::createSeeOther("/users/$userName/dashboard"); + } + return null; + } +} \ No newline at end of file diff --git a/src/HttpController/Middleware/isUnauthenticated.php b/src/HttpController/Middleware/isUnauthenticated.php new file mode 100644 index 00000000..3890e44a --- /dev/null +++ b/src/HttpController/Middleware/isUnauthenticated.php @@ -0,0 +1,21 @@ +authenticationService->isUserAuthenticated() === false) { + return Response::createSeeOther("/login"); + } + return null; + } +} \ No newline at end of file diff --git a/src/HttpController/Web/AuthenticationController.php b/src/HttpController/Web/AuthenticationController.php index a933496f..edaf6084 100644 --- a/src/HttpController/Web/AuthenticationController.php +++ b/src/HttpController/Web/AuthenticationController.php @@ -58,14 +58,6 @@ public function logout() : Response public function renderLoginPage() : Response { - if ($this->authenticationService->isUserAuthenticated() === true) { - return Response::create( - StatusCode::createSeeOther(), - null, - [Header::createLocation('/')], - ); - } - $failedLogin = $this->sessionWrapper->has('failedLogin'); $this->sessionWrapper->unset('failedLogin'); diff --git a/src/HttpController/Web/CreateUserController.php b/src/HttpController/Web/CreateUserController.php index dc7a4bd9..d795b294 100644 --- a/src/HttpController/Web/CreateUserController.php +++ b/src/HttpController/Web/CreateUserController.php @@ -30,16 +30,7 @@ public function __construct( // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh public function createUser(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === true) { - return Response::createSeeOther('/'); - } - $hasUsers = $this->userApi->hasUsers(); - - if ($hasUsers === true && $this->registrationEnabled === false) { - return Response::createSeeOther('/'); - } - $postParameters = $request->getPostParameters(); $email = empty($postParameters['email']) === true ? null : (string)$postParameters['email']; @@ -92,16 +83,8 @@ public function createUser(Request $request) : Response public function renderPage() : Response { - if ($this->authenticationService->isUserAuthenticated() === true) { - return Response::createSeeOther('/'); - } - $hasUsers = $this->userApi->hasUsers(); - if ($hasUsers === true && $this->registrationEnabled === false) { - return Response::createSeeOther('/'); - } - $errorPasswordTooShort = $this->sessionWrapper->find('errorPasswordTooShort'); $errorPasswordNotEqual = $this->sessionWrapper->find('errorPasswordNotEqual'); $errorUsernameInvalidFormat = $this->sessionWrapper->find('errorUsernameInvalidFormat'); diff --git a/src/HttpController/Web/JobController.php b/src/HttpController/Web/JobController.php index f6079379..659d4831 100644 --- a/src/HttpController/Web/JobController.php +++ b/src/HttpController/Web/JobController.php @@ -31,10 +31,6 @@ public function __construct( public function getJobs(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $parameters = $request->getGetParameters(); $jobType = JobType::createFromString($parameters['type']); @@ -46,10 +42,6 @@ public function getJobs(Request $request) : Response public function purgeAllJobs() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $this->jobQueueApi->purgeAllJobs(); return Response::createSeeOther('/settings/server/jobs'); @@ -57,10 +49,6 @@ public function purgeAllJobs() : Response public function purgeProcessedJobs() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $this->jobQueueApi->purgeProcessedJobs(); return Response::createSeeOther('/settings/server/jobs'); @@ -68,10 +56,6 @@ public function purgeProcessedJobs() : Response public function scheduleLetterboxdDiaryImport(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $fileParameters = $request->getFileParameters(); if (empty($fileParameters['diaryCsv']['tmp_name']) === true) { @@ -106,10 +90,6 @@ public function scheduleLetterboxdDiaryImport(Request $request) : Response public function scheduleLetterboxdRatingsImport(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $fileParameters = $request->getFileParameters(); if (empty($fileParameters['ratingsCsv']['tmp_name']) === true) { @@ -150,14 +130,7 @@ public function scheduleLetterboxdRatingsImport(Request $request) : Response public function schedulePlexWatchlistImport() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $currentUser = $this->authenticationService->getCurrentUser(); - if ($currentUser->getPlexAccessToken() === null) { - return Response::createBadRequest(PlexAuthenticationMissing::create()->getMessage()); - } $this->jobQueueApi->addPlexImportWatchlistJob($currentUser->getId()); @@ -170,17 +143,8 @@ public function schedulePlexWatchlistImport() : Response public function scheduleJellyfinImportHistory() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $currentUserId = $this->authenticationService->getCurrentUserId(); - $jellyfinAuthentication = $this->userApi->findJellyfinAuthentication($currentUserId); - if ($jellyfinAuthentication === null) { - return Response::createBadRequest(JellyfinInvalidAuthentication::create()->getMessage()); - } - $this->jobQueueApi->addJellyfinImportMoviesJob($currentUserId); return Response::create( @@ -192,17 +156,8 @@ public function scheduleJellyfinImportHistory() : Response public function scheduleJellyfinExportHistory() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $currentUserId = $this->authenticationService->getCurrentUserId(); - $jellyfinAuthentication = $this->userApi->findJellyfinAuthentication($currentUserId); - if ($jellyfinAuthentication === null) { - return Response::createBadRequest(JellyfinInvalidAuthentication::create()->getMessage()); - } - $this->jobQueueApi->addJellyfinExportMoviesJob($currentUserId); return Response::create( @@ -214,10 +169,6 @@ public function scheduleJellyfinExportHistory() : Response public function scheduleTraktHistorySync() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $this->jobQueueApi->addTraktImportHistoryJob($this->authenticationService->getCurrentUserId()); $this->sessionWrapper->set('scheduledTraktHistoryImport', true); @@ -231,10 +182,6 @@ public function scheduleTraktHistorySync() : Response public function scheduleTraktRatingsSync() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $this->jobQueueApi->addTraktImportRatingsJob($this->authenticationService->getCurrentUserId()); $this->sessionWrapper->set('scheduledTraktRatingsImport', true); diff --git a/src/HttpController/Web/LandingPageController.php b/src/HttpController/Web/LandingPageController.php index 9c8a56f8..e7fcff5a 100644 --- a/src/HttpController/Web/LandingPageController.php +++ b/src/HttpController/Web/LandingPageController.php @@ -24,15 +24,15 @@ public function __construct( public function render() : Response { - if ($this->authenticationService->isUserAuthenticated() === true) { - $userName = $this->authenticationService->getCurrentUser()->getName(); + // if ($this->authenticationService->isUserAuthenticated() === true) { + // $userName = $this->authenticationService->getCurrentUser()->getName(); - return Response::createSeeOther("/users/$userName/dashboard"); - } + // return Response::createSeeOther("/users/$userName/dashboard"); + // } - if ($this->userApi->hasUsers() === false) { - return Response::createSeeOther('/create-user'); - } + // if ($this->userApi->hasUsers() === false) { + // return Response::createSeeOther('/create-user'); + // } $failedLogin = $this->sessionWrapper->has('failedLogin'); $deletedAccount = $this->sessionWrapper->has('deletedAccount'); diff --git a/src/HttpController/Web/SettingsController.php b/src/HttpController/Web/SettingsController.php index 20925a96..01addd3c 100644 --- a/src/HttpController/Web/SettingsController.php +++ b/src/HttpController/Web/SettingsController.php @@ -332,7 +332,7 @@ public function renderJellyfinPage() : Response 'isActive' => $applicationUrl !== null, 'jellyfinWebhookUrl' => $webhookUrl ?? '-', 'jellyfinServerUrl' => $jellyfinServerUrl, - 'jellyfinIsAuthenticated' => $jellyfinAuthentication !== null, + 'jellyfinisAuthenticated' => $jellyfinAuthentication !== null, 'jellyfinUsername' => $jellyfinUsername?->getUsername(), 'jellyfinDeviceId' => $jellyfinDeviceId, 'scrobbleWatches' => $user->hasJellyfinScrobbleWatchesEnabled(), @@ -493,10 +493,6 @@ public function renderServerEmailPage() : Response public function renderServerGeneralPage() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - if ($this->authenticationService->getCurrentUser()->isAdmin() === false) { return Response::createSeeOther('/'); } diff --git a/src/HttpController/Web/TwoFactorAuthenticationController.php b/src/HttpController/Web/TwoFactorAuthenticationController.php index ec4d790d..16831692 100644 --- a/src/HttpController/Web/TwoFactorAuthenticationController.php +++ b/src/HttpController/Web/TwoFactorAuthenticationController.php @@ -76,14 +76,6 @@ public function enableTOTP(Request $request) : Response public function verifyTotp(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === true) { - return Response::create( - StatusCode::createSeeOther(), - null, - [Header::createLocation($_SERVER['HTTP_REFERER'])], - ); - } - $userTotpInput = $request->getPostParameters()['totpCode']; $rememberMe = $this->sessionWrapper->find('rememberMe') ?? false; $userId = (int)$this->sessionWrapper->find('totpUserId'); diff --git a/src/Service/MiddlewareService.php b/src/Service/MiddlewareService.php new file mode 100644 index 00000000..7729ac1f --- /dev/null +++ b/src/Service/MiddlewareService.php @@ -0,0 +1,11 @@ +getData(); + } +} \ No newline at end of file diff --git a/src/Service/RouterService.php b/src/Service/RouterService.php new file mode 100644 index 00000000..53042034 --- /dev/null +++ b/src/Service/RouterService.php @@ -0,0 +1,30 @@ +addRoute($httpMethod, $route, [[$handler]]); + } + + public static function create($httpMethod, $route, $handler) + { + return new self($httpMethod, $route, $handler); + } + + public function getMiddleware() + { + + } +} + + +class RouterService +{ + public function createNewRoute($httpMethod, $route, $handler) : RouteDto + { + return RouteDto::create($httpMethod, $route, $handler); + } +} \ No newline at end of file diff --git a/src/ValueObject/Http/Request.php b/src/ValueObject/Http/Request.php index 5112969c..b39ea9a8 100644 --- a/src/ValueObject/Http/Request.php +++ b/src/ValueObject/Http/Request.php @@ -7,7 +7,7 @@ class Request { private array $routeParameters = []; - + private function __construct( private readonly string $path, private readonly array $getParameters, diff --git a/templates/page/settings-integration-jellyfin.html.twig b/templates/page/settings-integration-jellyfin.html.twig index c111327a..c6b28af3 100644 --- a/templates/page/settings-integration-jellyfin.html.twig +++ b/templates/page/settings-integration-jellyfin.html.twig @@ -98,7 +98,7 @@ -
+
-
+

Username: {{ jellyfinUsername }}

@@ -212,7 +212,7 @@
Jellyfin sync
- @@ -246,7 +246,7 @@ data-bs-target="#exportHistoryModal" data-bs-toggle="modal" id="jellyfinHistoryExportButton" - {% if jellyfinIsAuthenticated == false %}disabled{% endif %}> + {% if jellyfinisAuthenticated == false %}disabled{% endif %}> Export history to Jellyfin
@@ -257,7 +257,7 @@ value="1" id="automaticWatchStateSyncCheckbox" name="scrobbleWatches" - {% if jellyfinIsAuthenticated == false %}disabled{% endif %} + {% if jellyfinisAuthenticated == false %}disabled{% endif %} {% if jellyfinSyncEnabled == true %}checked{% endif %} style="margin-right: 0.2rem"> @@ -265,7 +265,7 @@
-
From 2903e067814ce05c2e9c9a953df3be20a4dd0c8b Mon Sep 17 00:00:00 2001 From: JVT038 <47184046+JVT038@users.noreply.github.com> Date: Mon, 4 Sep 2023 16:39:01 +0200 Subject: [PATCH 02/11] Improved the middleware syntax :D --- public/index.php | 20 +- settings/routes.php | 265 +++++++++--------- .../Middleware/HasPlexAccessToken.php | 1 - .../Middleware/isAuthenticated.php | 9 +- .../Middleware/isUnauthenticated.php | 9 +- src/Service/MiddlewareService.php | 11 - src/Service/Router/Dto/Route.php | 48 ++++ src/Service/Router/Dto/RouteList.php | 30 ++ src/Service/Router/RouterService.php | 35 +++ src/Service/RouterService.php | 30 -- 10 files changed, 266 insertions(+), 192 deletions(-) delete mode 100644 src/Service/MiddlewareService.php create mode 100644 src/Service/Router/Dto/Route.php create mode 100644 src/Service/Router/Dto/RouteList.php create mode 100644 src/Service/Router/RouterService.php delete mode 100644 src/Service/RouterService.php diff --git a/public/index.php b/public/index.php index db94e3a3..5fe65be3 100644 --- a/public/index.php +++ b/public/index.php @@ -34,20 +34,14 @@ $response = Response::createMethodNotAllowed(); break; case FastRoute\Dispatcher::FOUND: - $handler = is_array($routeInfo[1][0]) ? $routeInfo[1][0] : $routeInfo[1]; + $handler = $routeInfo[1]['handler']; $httpRequest->addRouteParameters($routeInfo[2]); - - if(array_key_exists('middleware', $routeInfo[1])) { - foreach($routeInfo[1]['middleware'] as $middleware) { - if(class_exists($middleware)) { - $middlewareResponse = $container->call([$middleware, 'main']); - if($middlewareResponse instanceof Response) { - $response = $middlewareResponse; - break 2; - } - } else { - $container->get(LoggerInterface::class)->warning('The class '. $middleware . 'does not exist!'); - } + + foreach($routeInfo[1]['middleware'] as $middleware) { + $middlewareResponse = $container->call([$middleware, 'main']); + if($middlewareResponse instanceof Response) { + $response = $middlewareResponse; + break 2; } } diff --git a/settings/routes.php b/settings/routes.php index a53c50ea..286a6f69 100644 --- a/settings/routes.php +++ b/settings/routes.php @@ -1,147 +1,156 @@ addGroup('', fn(FastRoute\RouteCollector $routeCollector) => addWebRoutes($routeCollector)); - $routeCollector->addGroup('/api', fn(FastRoute\RouteCollector $routeCollector) => addApiRoutes($routeCollector)); +return function (FastRoute\RouteCollector $routeCollector) { + $routeCollector->addGroup('', fn($routeCollector) => addWebRoutes($routeCollector)); + $routeCollector->addGroup('/api', fn($routeCollector) => addApiRoutes($routeCollector)); }; function addWebRoutes(FastRoute\RouteCollector $routeCollector) : void { - $routeCollector->addRoute('GET', '/', [[Web\LandingPageController::class, 'render'], 'middleware' => [Middleware\isUnauthenticated::class, Middleware\DoesNotHaveUsers::class]]); - $routeCollector->addRoute('POST', '/login', [Web\AuthenticationController::class, 'login']); - $routeCollector->addRoute('GET', '/login', [[Web\AuthenticationController::class, 'renderLoginPage'], 'middleware' => [Middleware\isUnauthenticated::class]]); - $routeCollector->addRoute('POST', '/verify-totp', [[Web\TwoFactorAuthenticationController::class, 'verifyTotp'], 'middleware' => [Middleware\isUnauthenticated::class]]); - $routeCollector->addRoute('GET', '/logout', [Web\AuthenticationController::class, 'logout']); - $routeCollector->addRoute('POST', '/create-user', [[Web\CreateUserController::class, 'createUser'], 'middleware' => [Middleware\isUnauthenticated::class, Middleware\HasUsersCheck::class, Middleware\RegistrationEnabledCheck::class]]); - $routeCollector->addRoute('GET', '/create-user', [[Web\CreateUserController::class, 'renderPage'], 'middleware' => [Middleware\isUnauthenticated::class, Middleware\HasUsersCheck::class, Middleware\RegistrationEnabledCheck::class]]); - $routeCollector->addRoute('GET', '/docs/api', [Web\OpenApiController::class, 'renderPage']); - - ##################### - # Webhook listeners # - ##################### - $routeCollector->addRoute('POST', '/plex/{id:.+}', [Web\PlexController::class, 'handlePlexWebhook']); - $routeCollector->addRoute('POST', '/jellyfin/{id:.+}', [Web\JellyfinController::class, 'handleJellyfinWebhook']); - $routeCollector->addRoute('POST', '/emby/{id:.+}', [Web\EmbyController::class, 'handleEmbyWebhook']); + $routerService = new RouterService(); + $routes = $routerService->createRouteList(); + $routes->addRoutes( + $routerService->createNewRoute('GET', '/', [Web\LandingPageController::class, 'render'])->addMiddleware(Middleware\isUnauthenticated::class, Middleware\DoesNotHaveUsers::class), + $routerService->createNewRoute('GET', '/login', [Web\AuthenticationController::class, 'renderLoginPage'])->addMiddleware(Middleware\isUnauthenticated::class), + $routerService->createNewRoute('POST', '/login', [Web\AuthenticationController::class, 'login']), + $routerService->createNewRoute('POST', '/verify-totp', [Web\TwoFactorAuthenticationController::class, 'verifyTotp'])->addMiddleware(Middleware\isUnauthenticated::class), + $routerService->createNewRoute('GET', '/logout', [Web\AuthenticationController::class, 'logout']), + $routerService->createNewRoute('POST', '/create-user', [Web\CreateUserController::class, 'createUser'])->addMiddleware(Middleware\isUnauthenticated::class, Middleware\HasUsersCheck::class, Middleware\RegistrationEnabledCheck::class), + $routerService->createNewRoute('GET', '/create-user', [Web\CreateUserController::class, 'renderPage'])->addMiddleware(Middleware\isUnauthenticated::class, Middleware\HasUsersCheck::class, Middleware\RegistrationEnabledCheck::class), + $routerService->createNewRoute('GET', '/docs/api', [Web\OpenApiController::class, 'renderPage']), - ############# - # Job Queue # - ############# - $routeCollector->addRoute('GET', '/jobs', [[Web\JobController::class, 'getJobs'], 'middleware' => [Middleware\isAuthenticated::class]]); - $routeCollector->addRoute('GET', '/job-queue/purge-processed', [[Web\JobController::class, 'purgeProcessedJobs'], 'middleware' => [Middleware\isAuthenticated::class]]); - $routeCollector->addRoute('GET', '/job-queue/purge-all', [[Web\JobController::class, 'purgeAllJobs'], 'middleware' => [Middleware\isAuthenticated::class]]); - $routeCollector->addRoute('GET', '/jobs/schedule/trakt-history-sync', [[Web\JobController::class, 'scheduleTraktHistorySync'], 'middleware' => [Middleware\isAuthenticated::class]]); - $routeCollector->addRoute('GET', '/jobs/schedule/trakt-ratings-sync', [[Web\JobController::class, 'scheduleTraktRatingsSync'], 'middleware' => [Middleware\isAuthenticated::class]]); - $routeCollector->addRoute('POST', '/jobs/schedule/letterboxd-diary-sync', [[Web\JobController::class, 'scheduleLetterboxdDiaryImport'], 'middleware' => [Middleware\isAuthenticated::class]]); - $routeCollector->addRoute('POST', '/jobs/schedule/letterboxd-ratings-sync', [[Web\JobController::class, 'scheduleLetterboxdRatingsImport'], 'middleware' => [Middleware\isAuthenticated::class]]); - $routeCollector->addRoute('GET', '/jobs/schedule/plex-watchlist-sync', [[Web\JobController::class, 'schedulePlexWatchlistImport'], 'middleware' => [Middleware\isAuthenticated::class, Middleware\HasPlexAccessToken::class]]); - $routeCollector->addRoute('GET', '/jobs/schedule/jellyfin-import-history', [[Web\JobController::class, 'scheduleJellyfinImportHistory'], 'middleware' => [Middleware\isAuthenticated::class, Middleware\HasJellyfinToken::class]]); - $routeCollector->addRoute('GET', '/jobs/schedule/jellyfin-export-history', [[Web\JobController::class, 'scheduleJellyfinExportHistory'], 'middleware' => [Middleware\isAuthenticated::class, Middleware\HasJellyfinToken::class]]); + ##################### + # Webhook listeners # + ##################### + $routerService->createNewRoute('POST', '/plex/{id:.+}', [Web\PlexController::class, 'handlePlexWebhook']), + $routerService->createNewRoute('POST', '/jellyfin/{id:.+}', [Web\JellyfinController::class, 'handleJellyfinWebhook']), + $routerService->createNewRoute('POST', '/emby/{id:.+}', [Web\EmbyController::class, 'handleEmbyWebhook']), - ############ - # Settings # - ############ - $routeCollector->addRoute('GET', '/settings/account/general', [[Web\SettingsController::class, 'renderGeneralAccountPage'], 'middleware' => [Middleware\isUnauthenticated::class]]); - $routeCollector->addRoute('GET', '/settings/account/general/api-token', [Web\SettingsController::class, 'getApiToken'],); - $routeCollector->addRoute('DELETE', '/settings/account/general/api-token', [Web\SettingsController::class, 'deleteApiToken'],); - $routeCollector->addRoute('PUT', '/settings/account/general/api-token', [Web\SettingsController::class, 'regenerateApiToken'],); - $routeCollector->addRoute('GET', '/settings/account/dashboard', [Web\SettingsController::class, 'renderDashboardAccountPage']); - $routeCollector->addRoute('GET', '/settings/account/security', [Web\SettingsController::class, 'renderSecurityAccountPage']); - $routeCollector->addRoute('GET', '/settings/account/data', [Web\SettingsController::class, 'renderDataAccountPage']); - $routeCollector->addRoute('GET', '/settings/server/general', [Web\SettingsController::class, 'renderServerGeneralPage']); - $routeCollector->addRoute('GET', '/settings/server/jobs', [Web\SettingsController::class, 'renderServerJobsPage']); - $routeCollector->addRoute('POST', '/settings/server/general', [Web\SettingsController::class, 'updateServerGeneral']); - $routeCollector->addRoute('GET', '/settings/server/users', [Web\SettingsController::class, 'renderServerUsersPage']); - $routeCollector->addRoute('GET', '/settings/server/email', [Web\SettingsController::class, 'renderServerEmailPage']); - $routeCollector->addRoute('POST', '/settings/server/email', [Web\SettingsController::class, 'updateServerEmail']); - $routeCollector->addRoute('POST', '/settings/server/email-test', [Web\SettingsController::class, 'sendTestEmail']); - $routeCollector->addRoute('POST', '/settings/account', [Web\SettingsController::class, 'updateGeneral']); - $routeCollector->addRoute('POST', '/settings/account/security/update-password', [Web\SettingsController::class, 'updatePassword']); - $routeCollector->addRoute('POST', '/settings/account/security/create-totp-uri', [Web\TwoFactorAuthenticationController::class, 'createTotpUri']); - $routeCollector->addRoute('POST', '/settings/account/security/disable-totp', [Web\TwoFactorAuthenticationController::class, 'disableTotp']); - $routeCollector->addRoute('POST', '/settings/account/security/enable-totp', [Web\TwoFactorAuthenticationController::class, 'enableTotp']); - $routeCollector->addRoute('GET', '/settings/account/export/csv/{exportType:.+}', [Web\ExportController::class, 'getCsvExport']); - $routeCollector->addRoute('POST', '/settings/account/import/csv/{exportType:.+}', [Web\ImportController::class, 'handleCsvImport']); - $routeCollector->addRoute('GET', '/settings/account/delete-ratings', [Web\SettingsController::class, 'deleteRatings']); - $routeCollector->addRoute('GET', '/settings/account/delete-history', [Web\SettingsController::class, 'deleteHistory']); - $routeCollector->addRoute('GET', '/settings/account/delete-account', [Web\SettingsController::class, 'deleteAccount']); - $routeCollector->addRoute('POST', '/settings/account/update-dashboard-rows', [Web\SettingsController::class, 'updateDashboardRows']); - $routeCollector->addRoute('POST', '/settings/account/reset-dashboard-rows', [Web\SettingsController::class, 'resetDashboardRows']); - $routeCollector->addRoute('GET', '/settings/integrations/trakt', [Web\SettingsController::class, 'renderTraktPage']); - $routeCollector->addRoute('POST', '/settings/trakt', [Web\SettingsController::class, 'updateTrakt']); - $routeCollector->addRoute('POST', '/settings/trakt/verify-credentials', [Web\SettingsController::class, 'traktVerifyCredentials']); - $routeCollector->addRoute('GET', '/settings/integrations/letterboxd', [Web\SettingsController::class, 'renderLetterboxdPage']); - $routeCollector->addRoute('GET', '/settings/letterboxd-export', [Web\SettingsController::class, 'generateLetterboxdExportData']); - $routeCollector->addRoute('GET', '/settings/integrations/plex', [Web\SettingsController::class, 'renderPlexPage']); - $routeCollector->addRoute('GET', '/settings/plex/logout', [Web\PlexController::class, 'removePlexAccessTokens']); - $routeCollector->addRoute('POST', '/settings/plex/server-url-save', [Web\PlexController::class, 'savePlexServerUrl']); - $routeCollector->addRoute('POST', '/settings/plex/server-url-verify', [Web\PlexController::class, 'verifyPlexServerUrl']); - $routeCollector->addRoute('GET', '/settings/plex/authentication-url', [Web\PlexController::class, 'generatePlexAuthenticationUrl']); - $routeCollector->addRoute('GET', '/settings/plex/callback', [Web\PlexController::class, 'processPlexCallback']); - $routeCollector->addRoute('POST', '/settings/plex', [Web\SettingsController::class, 'updatePlex']); - $routeCollector->addRoute('PUT', '/settings/plex/webhook', [Web\PlexController::class, 'regeneratePlexWebhookUrl']); - $routeCollector->addRoute('DELETE', '/settings/plex/webhook', [Web\PlexController::class, 'deletePlexWebhookUrl']); - $routeCollector->addRoute('GET', '/settings/integrations/jellyfin', [Web\SettingsController::class, 'renderJellyfinPage']); - $routeCollector->addRoute('POST', '/settings/jellyfin', [Web\SettingsController::class, 'updateJellyfin']); - $routeCollector->addRoute('POST', '/settings/jellyfin/sync', [Web\JellyfinController::class, 'saveJellyfinSyncOptions']); - $routeCollector->addRoute('POST', '/settings/jellyfin/authenticate', [Web\JellyfinController::class, 'authenticateJellyfinAccount']); - $routeCollector->addRoute('POST', '/settings/jellyfin/remove-authentication', [Web\JellyfinController::class, 'removeJellyfinAuthentication']); - $routeCollector->addRoute('POST', '/settings/jellyfin/server-url-save', [Web\JellyfinController::class, 'saveJellyfinServerUrl']); - $routeCollector->addRoute('POST', '/settings/jellyfin/server-url-verify', [Web\JellyfinController::class, 'verifyJellyfinServerUrl']); - $routeCollector->addRoute('GET', '/settings/jellyfin/webhook', [Web\JellyfinController::class, 'getJellyfinWebhookUrl']); - $routeCollector->addRoute('PUT', '/settings/jellyfin/webhook', [Web\JellyfinController::class, 'regenerateJellyfinWebhookUrl']); - $routeCollector->addRoute('DELETE', '/settings/jellyfin/webhook', [Web\JellyfinController::class, 'deleteJellyfinWebhookUrl']); - $routeCollector->addRoute('GET', '/settings/integrations/emby', [Web\SettingsController::class, 'renderEmbyPage']); - $routeCollector->addRoute('POST', '/settings/emby', [Web\SettingsController::class, 'updateEmby']); - $routeCollector->addRoute('GET', '/settings/emby/webhook', [Web\EmbyController::class, 'getEmbyWebhookUrl']); - $routeCollector->addRoute('PUT', '/settings/emby/webhook', [Web\EmbyController::class, 'regenerateEmbyWebhookUrl']); - $routeCollector->addRoute('DELETE', '/settings/emby/webhook', [Web\EmbyController::class, 'deleteEmbyWebhookUrl']); - $routeCollector->addRoute('GET', '/settings/app', [Web\SettingsController::class, 'renderAppPage']); - $routeCollector->addRoute('GET', '/settings/integrations/netflix', [Web\SettingsController::class, 'renderNetflixPage']); - $routeCollector->addRoute('POST', '/settings/netflix', [Web\NetflixController::class, 'matchNetflixActivityCsvWithTmdbMovies']); - $routeCollector->addRoute('POST', '/settings/netflix/import', [Web\NetflixController::class, 'importNetflixData']); - $routeCollector->addRoute('POST', '/settings/netflix/search', [Web\NetflixController::class, 'searchTmbd']); - $routeCollector->addRoute('GET', '/settings/users', [Web\UserController::class, 'fetchUsers']); - $routeCollector->addRoute('POST', '/settings/users', [Web\UserController::class, 'createUser']); - $routeCollector->addRoute('PUT', '/settings/users/{userId:\d+}', [Web\UserController::class, 'updateUser']); - $routeCollector->addRoute('DELETE', '/settings/users/{userId:\d+}', [Web\UserController::class, 'deleteUser']); + ############# + # Job Queue # + ############# + $routerService->createNewRoute('GET', '/jobs', [[Web\JobController::class, 'getJobs'], 'middleware' => [Middleware\isAuthenticated::class]]), + $routerService->createNewRoute('GET', '/job-queue/purge-processed', [[Web\JobController::class, 'purgeProcessedJobs'], 'middleware' => [Middleware\isAuthenticated::class]]), + $routerService->createNewRoute('GET', '/job-queue/purge-all', [[Web\JobController::class, 'purgeAllJobs'], 'middleware' => [Middleware\isAuthenticated::class]]), + $routerService->createNewRoute('GET', '/jobs/schedule/trakt-history-sync', [[Web\JobController::class, 'scheduleTraktHistorySync'], 'middleware' => [Middleware\isAuthenticated::class]]), + $routerService->createNewRoute('GET', '/jobs/schedule/trakt-ratings-sync', [[Web\JobController::class, 'scheduleTraktRatingsSync'], 'middleware' => [Middleware\isAuthenticated::class]]), + $routerService->createNewRoute('POST', '/jobs/schedule/letterboxd-diary-sync', [[Web\JobController::class, 'scheduleLetterboxdDiaryImport'], 'middleware' => [Middleware\isAuthenticated::class]]), + $routerService->createNewRoute('POST', '/jobs/schedule/letterboxd-ratings-sync', [[Web\JobController::class, 'scheduleLetterboxdRatingsImport'], 'middleware' => [Middleware\isAuthenticated::class]]), + $routerService->createNewRoute('GET', '/jobs/schedule/plex-watchlist-sync', [[Web\JobController::class, 'schedulePlexWatchlistImport'], 'middleware' => [Middleware\isAuthenticated::class, Middleware\HasPlexAccessToken::class]]), + $routerService->createNewRoute('GET', '/jobs/schedule/jellyfin-import-history', [[Web\JobController::class, 'scheduleJellyfinImportHistory'], 'middleware' => [Middleware\isAuthenticated::class, Middleware\HasJellyfinToken::class]]), + $routerService->createNewRoute('GET', '/jobs/schedule/jellyfin-export-history', [[Web\JobController::class, 'scheduleJellyfinExportHistory'], 'middleware' => [Middleware\isAuthenticated::class, Middleware\HasJellyfinToken::class]]), - ########## - # Movies # - ########## - $routeCollector->addRoute('GET', '/movies/{id:[0-9]+}/refresh-tmdb', [Web\Movie\MovieController::class, 'refreshTmdbData']); - $routeCollector->addRoute('GET', '/movies/{id:[0-9]+}/refresh-imdb', [Web\Movie\MovieController::class, 'refreshImdbRating']); - $routeCollector->addRoute('GET', '/movies/{id:[0-9]+}/watch-providers', [Web\Movie\MovieWatchProviderController::class, 'getWatchProviders']); - $routeCollector->addRoute('GET', '/movies/{id:[0-9]+}/add-watchlist', [Web\Movie\MovieWatchlistController::class, 'addToWatchlist']); - $routeCollector->addRoute('GET', '/movies/{id:[0-9]+}/remove-watchlist', [Web\Movie\MovieWatchlistController::class, 'removeFromWatchlist']); + ############ + # Settings # + ############ + $routerService->createNewRoute('GET', '/settings/account/general', [Web\SettingsController::class, 'renderGeneralAccountPage'])->addMiddleware(Middleware\isAuthenticated::class), + $routerService->createNewRoute('GET', '/settings/account/general/api-token', [Web\SettingsController::class, 'getApiToken']), + $routerService->createNewRoute('DELETE', '/settings/account/general/api-token', [Web\SettingsController::class, 'deleteApiToken']), + $routerService->createNewRoute('PUT', '/settings/account/general/api-token', [Web\SettingsController::class, 'regenerateApiToken']), + $routerService->createNewRoute('GET', '/settings/account/dashboard', [Web\SettingsController::class, 'renderDashboardAccountPage']), + $routerService->createNewRoute('GET', '/settings/account/security', [Web\SettingsController::class, 'renderSecurityAccountPage']), + $routerService->createNewRoute('GET', '/settings/account/data', [Web\SettingsController::class, 'renderDataAccountPage']), + $routerService->createNewRoute('GET', '/settings/server/general', [Web\SettingsController::class, 'renderServerGeneralPage']), + $routerService->createNewRoute('GET', '/settings/server/jobs', [Web\SettingsController::class, 'renderServerJobsPage']), + $routerService->createNewRoute('POST', '/settings/server/general', [Web\SettingsController::class, 'updateServerGeneral']), + $routerService->createNewRoute('GET', '/settings/server/users', [Web\SettingsController::class, 'renderServerUsersPage']), + $routerService->createNewRoute('GET', '/settings/server/email', [Web\SettingsController::class, 'renderServerEmailPage']), + $routerService->createNewRoute('POST', '/settings/server/email', [Web\SettingsController::class, 'updateServerEmail']), + $routerService->createNewRoute('POST', '/settings/server/email-test', [Web\SettingsController::class, 'sendTestEmail']), + $routerService->createNewRoute('POST', '/settings/account', [Web\SettingsController::class, 'updateGeneral']), + $routerService->createNewRoute('POST', '/settings/account/security/update-password', [Web\SettingsController::class, 'updatePassword']), + $routerService->createNewRoute('POST', '/settings/account/security/create-totp-uri', [Web\TwoFactorAuthenticationController::class, 'createTotpUri']), + $routerService->createNewRoute('POST', '/settings/account/security/disable-totp', [Web\TwoFactorAuthenticationController::class, 'disableTotp']), + $routerService->createNewRoute('POST', '/settings/account/security/enable-totp', [Web\TwoFactorAuthenticationController::class, 'enableTotp']), + $routerService->createNewRoute('GET', '/settings/account/export/csv/{exportType:.+}', [Web\ExportController::class, 'getCsvExport']), + $routerService->createNewRoute('POST', '/settings/account/import/csv/{exportType:.+}', [Web\ImportController::class, 'handleCsvImport']), + $routerService->createNewRoute('GET', '/settings/account/delete-ratings', [Web\SettingsController::class, 'deleteRatings']), + $routerService->createNewRoute('GET', '/settings/account/delete-history', [Web\SettingsController::class, 'deleteHistory']), + $routerService->createNewRoute('GET', '/settings/account/delete-account', [Web\SettingsController::class, 'deleteAccount']), + $routerService->createNewRoute('POST', '/settings/account/update-dashboard-rows', [Web\SettingsController::class, 'updateDashboardRows']), + $routerService->createNewRoute('POST', '/settings/account/reset-dashboard-rows', [Web\SettingsController::class, 'resetDashboardRows']), + $routerService->createNewRoute('GET', '/settings/integrations/trakt', [Web\SettingsController::class, 'renderTraktPage']), + $routerService->createNewRoute('POST', '/settings/trakt', [Web\SettingsController::class, 'updateTrakt']), + $routerService->createNewRoute('POST', '/settings/trakt/verify-credentials', [Web\SettingsController::class, 'traktVerifyCredentials']), + $routerService->createNewRoute('GET', '/settings/integrations/letterboxd', [Web\SettingsController::class, 'renderLetterboxdPage']), + $routerService->createNewRoute('GET', '/settings/letterboxd-export', [Web\SettingsController::class, 'generateLetterboxdExportData']), + $routerService->createNewRoute('GET', '/settings/integrations/plex', [Web\SettingsController::class, 'renderPlexPage']), + $routerService->createNewRoute('GET', '/settings/plex/logout', [Web\PlexController::class, 'removePlexAccessTokens']), + $routerService->createNewRoute('POST', '/settings/plex/server-url-save', [Web\PlexController::class, 'savePlexServerUrl']), + $routerService->createNewRoute('POST', '/settings/plex/server-url-verify', [Web\PlexController::class, 'verifyPlexServerUrl']), + $routerService->createNewRoute('GET', '/settings/plex/authentication-url', [Web\PlexController::class, 'generatePlexAuthenticationUrl']), + $routerService->createNewRoute('GET', '/settings/plex/callback', [Web\PlexController::class, 'processPlexCallback']), + $routerService->createNewRoute('POST', '/settings/plex', [Web\SettingsController::class, 'updatePlex']), + $routerService->createNewRoute('PUT', '/settings/plex/webhook', [Web\PlexController::class, 'regeneratePlexWebhookUrl']), + $routerService->createNewRoute('DELETE', '/settings/plex/webhook', [Web\PlexController::class, 'deletePlexWebhookUrl']), + $routerService->createNewRoute('GET', '/settings/integrations/jellyfin', [Web\SettingsController::class, 'renderJellyfinPage']), + $routerService->createNewRoute('POST', '/settings/jellyfin', [Web\SettingsController::class, 'updateJellyfin']), + $routerService->createNewRoute('POST', '/settings/jellyfin/sync', [Web\JellyfinController::class, 'saveJellyfinSyncOptions']), + $routerService->createNewRoute('POST', '/settings/jellyfin/authenticate', [Web\JellyfinController::class, 'authenticateJellyfinAccount']), + $routerService->createNewRoute('POST', '/settings/jellyfin/remove-authentication', [Web\JellyfinController::class, 'removeJellyfinAuthentication']), + $routerService->createNewRoute('POST', '/settings/jellyfin/server-url-save', [Web\JellyfinController::class, 'saveJellyfinServerUrl']), + $routerService->createNewRoute('POST', '/settings/jellyfin/server-url-verify', [Web\JellyfinController::class, 'verifyJellyfinServerUrl']), + $routerService->createNewRoute('GET', '/settings/jellyfin/webhook', [Web\JellyfinController::class, 'getJellyfinWebhookUrl']), + $routerService->createNewRoute('PUT', '/settings/jellyfin/webhook', [Web\JellyfinController::class, 'regenerateJellyfinWebhookUrl']), + $routerService->createNewRoute('DELETE', '/settings/jellyfin/webhook', [Web\JellyfinController::class, 'deleteJellyfinWebhookUrl']), + $routerService->createNewRoute('GET', '/settings/integrations/emby', [Web\SettingsController::class, 'renderEmbyPage']), + $routerService->createNewRoute('POST', '/settings/emby', [Web\SettingsController::class, 'updateEmby']), + $routerService->createNewRoute('GET', '/settings/emby/webhook', [Web\EmbyController::class, 'getEmbyWebhookUrl']), + $routerService->createNewRoute('PUT', '/settings/emby/webhook', [Web\EmbyController::class, 'regenerateEmbyWebhookUrl']), + $routerService->createNewRoute('DELETE', '/settings/emby/webhook', [Web\EmbyController::class, 'deleteEmbyWebhookUrl']), + $routerService->createNewRoute('GET', '/settings/app', [Web\SettingsController::class, 'renderAppPage']), + $routerService->createNewRoute('GET', '/settings/integrations/netflix', [Web\SettingsController::class, 'renderNetflixPage']), + $routerService->createNewRoute('POST', '/settings/netflix', [Web\NetflixController::class, 'matchNetflixActivityCsvWithTmdbMovies']), + $routerService->createNewRoute('POST', '/settings/netflix/import', [Web\NetflixController::class, 'importNetflixData']), + $routerService->createNewRoute('POST', '/settings/netflix/search', [Web\NetflixController::class, 'searchTmbd']), + $routerService->createNewRoute('GET', '/settings/users', [Web\UserController::class, 'fetchUsers']), + $routerService->createNewRoute('POST', '/settings/users', [Web\UserController::class, 'createUser']), + $routerService->createNewRoute('PUT', '/settings/users/{userId:\d+}', [Web\UserController::class, 'updateUser']), + $routerService->createNewRoute('DELETE', '/settings/users/{userId:\d+}', [Web\UserController::class, 'deleteUser']), - ############## - # User media # - ############## - $routeCollector->addRoute('GET', '/users/{username:[a-zA-Z0-9]+}/dashboard', [Web\DashboardController::class, 'render']); - $routeCollector->addRoute('GET', '/users/{username:[a-zA-Z0-9]+}/history', [Web\HistoryController::class, 'renderHistory']); - $routeCollector->addRoute('GET', '/users/{username:[a-zA-Z0-9]+}/watchlist', [Web\WatchlistController::class, 'renderWatchlist']); - $routeCollector->addRoute('GET', '/users/{username:[a-zA-Z0-9]+}/movies', [Web\MoviesController::class, 'renderPage']); - $routeCollector->addRoute('GET', '/users/{username:[a-zA-Z0-9]+}/actors', [Web\ActorsController::class, 'renderPage']); - $routeCollector->addRoute('GET', '/users/{username:[a-zA-Z0-9]+}/directors', [Web\DirectorsController::class, 'renderPage']); - $routeCollector->addRoute('GET', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}', [Web\Movie\MovieController::class, 'renderPage']); - $routeCollector->addRoute('GET', '/users/{username:[a-zA-Z0-9]+}/persons/{id:\d+}', [Web\PersonController::class, 'renderPage']); - $routeCollector->addRoute('DELETE', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}/history', [Web\HistoryController::class, 'deleteHistoryEntry']); - $routeCollector->addRoute('POST', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}/history', [Web\HistoryController::class, 'createHistoryEntry']); - $routeCollector->addRoute('POST', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}/rating', [Web\Movie\MovieRatingController::class, 'updateRating']); - $routeCollector->addRoute('POST', '/log-movie', [Web\HistoryController::class, 'logMovie']); - $routeCollector->addRoute('POST', '/add-movie-to-watchlist', [Web\WatchlistController::class, 'addMovieToWatchlist']); - $routeCollector->addRoute('GET', '/fetchMovieRatingByTmdbdId', [Web\Movie\MovieRatingController::class, 'fetchMovieRatingByTmdbdId']); + ########## + # Movies # + ########## + $routerService->createNewRoute('GET', '/movies/{id:[0-9]+}/refresh-tmdb', [Web\Movie\MovieController::class, 'refreshTmdbData']), + $routerService->createNewRoute('GET', '/movies/{id:[0-9]+}/refresh-imdb', [Web\Movie\MovieController::class, 'refreshImdbRating']), + $routerService->createNewRoute('GET', '/movies/{id:[0-9]+}/watch-providers', [Web\Movie\MovieWatchProviderController::class, 'getWatchProviders']), + $routerService->createNewRoute('GET', '/movies/{id:[0-9]+}/add-watchlist', [Web\Movie\MovieWatchlistController::class, 'addToWatchlist']), + $routerService->createNewRoute('GET', '/movies/{id:[0-9]+}/remove-watchlist', [Web\Movie\MovieWatchlistController::class, 'removeFromWatchlist']), - // Added last, so that more specific routes can be defined (possible username vs route collisions here!) - $routeCollector->addRoute('GET', '/{username:[a-zA-Z0-9]+}[/]', [Web\DashboardController::class, 'redirectToDashboard']); + ############## + # User media # + ############## + $routerService->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/dashboard', [Web\DashboardController::class, 'render']), + $routerService->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/history', [Web\HistoryController::class, 'renderHistory']), + $routerService->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/watchlist', [Web\WatchlistController::class, 'renderWatchlist']), + $routerService->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/movies', [Web\MoviesController::class, 'renderPage']), + $routerService->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/actors', [Web\ActorsController::class, 'renderPage']), + $routerService->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/directors', [Web\DirectorsController::class, 'renderPage']), + $routerService->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}', [Web\Movie\MovieController::class, 'renderPage']), + $routerService->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/persons/{id:\d+}', [Web\PersonController::class, 'renderPage']), + $routerService->createNewRoute('DELETE', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}/history', [Web\HistoryController::class, 'deleteHistoryEntry']), + $routerService->createNewRoute('POST', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}/history', [Web\HistoryController::class, 'createHistoryEntry']), + $routerService->createNewRoute('POST', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}/rating', [Web\Movie\MovieRatingController::class, 'updateRating']), + $routerService->createNewRoute('POST', '/log-movie', [Web\HistoryController::class, 'logMovie']), + $routerService->createNewRoute('POST', '/add-movie-to-watchlist', [Web\WatchlistController::class, 'addMovieToWatchlist']), + $routerService->createNewRoute('GET', '/fetchMovieRatingByTmdbdId', [Web\Movie\MovieRatingController::class, 'fetchMovieRatingByTmdbdId']), + ); + $routerService->generateRouteCallback($routeCollector, $routes); } function addApiRoutes(FastRoute\RouteCollector $routeCollector) : void { - $routeCollector->addRoute('GET', '/openapi.json', [Api\OpenApiController::class, 'getSchema']); - $routeCollector->addRoute('GET', '/users/{username:[a-zA-Z0-9]+}/history', [Api\HistoryController::class, 'getHistory']); -} + $routerService = new RouterService(); + $routes = $routerService->createRouteList(); + $routes->addRoutes( + $routerService->createNewRoute('GET', '/openapi.jsn', [Api\OpenApiController::class, 'getSchema']), + $routerService->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/history', [Api\HistoryController::class, 'getHistory']), + ); + $routerService->generateRouteCallback($routeCollector, $routes); +} \ No newline at end of file diff --git a/src/HttpController/Middleware/HasPlexAccessToken.php b/src/HttpController/Middleware/HasPlexAccessToken.php index 458e4c29..1ea6c1ae 100644 --- a/src/HttpController/Middleware/HasPlexAccessToken.php +++ b/src/HttpController/Middleware/HasPlexAccessToken.php @@ -4,7 +4,6 @@ use Movary\Api\Plex\Exception\PlexAuthenticationMissing; use Movary\Domain\User\Service\Authentication; -use Movary\Domain\User\UserApi; use Movary\ValueObject\Http\Response; class HasPlexAccessToken diff --git a/src/HttpController/Middleware/isAuthenticated.php b/src/HttpController/Middleware/isAuthenticated.php index 9da2295f..3890e44a 100644 --- a/src/HttpController/Middleware/isAuthenticated.php +++ b/src/HttpController/Middleware/isAuthenticated.php @@ -5,17 +5,16 @@ use Movary\Domain\User\Service\Authentication; use Movary\ValueObject\Http\Response; -class isUnauthenticated +class isAuthenticated { public function __construct( - private readonly Authentication $authenticationService + private readonly Authentication $authenticationService, ) {} public function main() : ?Response { - if ($this->authenticationService->isUserAuthenticated() === true) { - $userName = $this->authenticationService->getCurrentUser()->getName(); - return Response::createSeeOther("/users/$userName/dashboard"); + if ($this->authenticationService->isUserAuthenticated() === false) { + return Response::createSeeOther("/login"); } return null; } diff --git a/src/HttpController/Middleware/isUnauthenticated.php b/src/HttpController/Middleware/isUnauthenticated.php index 3890e44a..9da2295f 100644 --- a/src/HttpController/Middleware/isUnauthenticated.php +++ b/src/HttpController/Middleware/isUnauthenticated.php @@ -5,16 +5,17 @@ use Movary\Domain\User\Service\Authentication; use Movary\ValueObject\Http\Response; -class isAuthenticated +class isUnauthenticated { public function __construct( - private readonly Authentication $authenticationService, + private readonly Authentication $authenticationService ) {} public function main() : ?Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther("/login"); + if ($this->authenticationService->isUserAuthenticated() === true) { + $userName = $this->authenticationService->getCurrentUser()->getName(); + return Response::createSeeOther("/users/$userName/dashboard"); } return null; } diff --git a/src/Service/MiddlewareService.php b/src/Service/MiddlewareService.php deleted file mode 100644 index 7729ac1f..00000000 --- a/src/Service/MiddlewareService.php +++ /dev/null @@ -1,11 +0,0 @@ -getData(); - } -} \ No newline at end of file diff --git a/src/Service/Router/Dto/Route.php b/src/Service/Router/Dto/Route.php new file mode 100644 index 00000000..ad8b9692 --- /dev/null +++ b/src/Service/Router/Dto/Route.php @@ -0,0 +1,48 @@ +handler = $handler; + $this->httpMethod = $httpMethod; + $this->route = $route; + } + + public static function create(string $httpMethod, string $route, array $handler) + { + return new self($httpMethod, $route, $handler); + } + + public function getHandler() : array + { + return $this->handler; + } + + public function getMethod() : string + { + return $this->httpMethod; + } + + public function getRoute() : string + { + return $this->route; + } + + public function getMiddleware() :?array + { + return $this->middleware; + } + + public function addMiddleware(...$middlewares) : self + { + $this->middleware = $middlewares; + return $this; + } +} \ No newline at end of file diff --git a/src/Service/Router/Dto/RouteList.php b/src/Service/Router/Dto/RouteList.php new file mode 100644 index 00000000..3a5c9a6e --- /dev/null +++ b/src/Service/Router/Dto/RouteList.php @@ -0,0 +1,30 @@ +data[] = $route; + return end($this->data); + } + + public function addRoutes(...$routes) : void + { + $this->data = array_merge($this->data, $routes); + } + + public function getRoutes() : array + { + return $this->data; + } +} \ No newline at end of file diff --git a/src/Service/Router/RouterService.php b/src/Service/Router/RouterService.php new file mode 100644 index 00000000..564bf38f --- /dev/null +++ b/src/Service/Router/RouterService.php @@ -0,0 +1,35 @@ +getRoutes() as $route) { + $routeCollector->addRoute( + $route->getMethod(), + $route->getRoute(), + [ + 'handler' => $route->getHandler(), + 'middleware' => $route->getMiddleware() + ] + ); + } + } +} \ No newline at end of file diff --git a/src/Service/RouterService.php b/src/Service/RouterService.php deleted file mode 100644 index 53042034..00000000 --- a/src/Service/RouterService.php +++ /dev/null @@ -1,30 +0,0 @@ -addRoute($httpMethod, $route, [[$handler]]); - } - - public static function create($httpMethod, $route, $handler) - { - return new self($httpMethod, $route, $handler); - } - - public function getMiddleware() - { - - } -} - - -class RouterService -{ - public function createNewRoute($httpMethod, $route, $handler) : RouteDto - { - return RouteDto::create($httpMethod, $route, $handler); - } -} \ No newline at end of file From 928fd1a77a86f91dc42808eb0e9919c155756a73 Mon Sep 17 00:00:00 2001 From: JVT038 <47184046+JVT038@users.noreply.github.com> Date: Mon, 4 Sep 2023 16:47:58 +0200 Subject: [PATCH 03/11] Improve syntax even more --- settings/routes.php | 246 +++++++++++++-------------- src/Service/Router/Dto/Route.php | 3 +- src/Service/Router/Dto/RouteList.php | 7 + src/Service/Router/RouterService.php | 6 - 4 files changed, 129 insertions(+), 133 deletions(-) diff --git a/settings/routes.php b/settings/routes.php index 286a6f69..c05ef603 100644 --- a/settings/routes.php +++ b/settings/routes.php @@ -15,132 +15,130 @@ function addWebRoutes(FastRoute\RouteCollector $routeCollector) : void { $routerService = new RouterService(); $routes = $routerService->createRouteList(); - $routes->addRoutes( - $routerService->createNewRoute('GET', '/', [Web\LandingPageController::class, 'render'])->addMiddleware(Middleware\isUnauthenticated::class, Middleware\DoesNotHaveUsers::class), - $routerService->createNewRoute('GET', '/login', [Web\AuthenticationController::class, 'renderLoginPage'])->addMiddleware(Middleware\isUnauthenticated::class), - $routerService->createNewRoute('POST', '/login', [Web\AuthenticationController::class, 'login']), - $routerService->createNewRoute('POST', '/verify-totp', [Web\TwoFactorAuthenticationController::class, 'verifyTotp'])->addMiddleware(Middleware\isUnauthenticated::class), - $routerService->createNewRoute('GET', '/logout', [Web\AuthenticationController::class, 'logout']), - $routerService->createNewRoute('POST', '/create-user', [Web\CreateUserController::class, 'createUser'])->addMiddleware(Middleware\isUnauthenticated::class, Middleware\HasUsersCheck::class, Middleware\RegistrationEnabledCheck::class), - $routerService->createNewRoute('GET', '/create-user', [Web\CreateUserController::class, 'renderPage'])->addMiddleware(Middleware\isUnauthenticated::class, Middleware\HasUsersCheck::class, Middleware\RegistrationEnabledCheck::class), - $routerService->createNewRoute('GET', '/docs/api', [Web\OpenApiController::class, 'renderPage']), + $routes->createNewRoute('GET', '/', [Web\LandingPageController::class, 'render'])->addMiddleware(Middleware\isUnauthenticated::class, Middleware\DoesNotHaveUsers::class); + $routes->createNewRoute('GET', '/login', [Web\AuthenticationController::class, 'renderLoginPage'])->addMiddleware(Middleware\isUnauthenticated::class); + $routes->createNewRoute('POST', '/login', [Web\AuthenticationController::class, 'login']); + $routes->createNewRoute('POST', '/verify-totp', [Web\TwoFactorAuthenticationController::class, 'verifyTotp'])->addMiddleware(Middleware\isUnauthenticated::class); + $routes->createNewRoute('GET', '/logout', [Web\AuthenticationController::class, 'logout']); + $routes->createNewRoute('POST', '/create-user', [Web\CreateUserController::class, 'createUser'])->addMiddleware(Middleware\isUnauthenticated::class, Middleware\HasUsersCheck::class, Middleware\RegistrationEnabledCheck::class); + $routes->createNewRoute('GET', '/create-user', [Web\CreateUserController::class, 'renderPage'])->addMiddleware(Middleware\isUnauthenticated::class, Middleware\HasUsersCheck::class, Middleware\RegistrationEnabledCheck::class); + $routes->createNewRoute('GET', '/docs/api', [Web\OpenApiController::class, 'renderPage']); - ##################### - # Webhook listeners # - ##################### - $routerService->createNewRoute('POST', '/plex/{id:.+}', [Web\PlexController::class, 'handlePlexWebhook']), - $routerService->createNewRoute('POST', '/jellyfin/{id:.+}', [Web\JellyfinController::class, 'handleJellyfinWebhook']), - $routerService->createNewRoute('POST', '/emby/{id:.+}', [Web\EmbyController::class, 'handleEmbyWebhook']), + ##################### + # Webhook listeners # + ##################### + $routes->createNewRoute('POST', '/plex/{id:.+}', [Web\PlexController::class, 'handlePlexWebhook']); + $routes->createNewRoute('POST', '/jellyfin/{id:.+}', [Web\JellyfinController::class, 'handleJellyfinWebhook']); + $routes->createNewRoute('POST', '/emby/{id:.+}', [Web\EmbyController::class, 'handleEmbyWebhook']); - ############# - # Job Queue # - ############# - $routerService->createNewRoute('GET', '/jobs', [[Web\JobController::class, 'getJobs'], 'middleware' => [Middleware\isAuthenticated::class]]), - $routerService->createNewRoute('GET', '/job-queue/purge-processed', [[Web\JobController::class, 'purgeProcessedJobs'], 'middleware' => [Middleware\isAuthenticated::class]]), - $routerService->createNewRoute('GET', '/job-queue/purge-all', [[Web\JobController::class, 'purgeAllJobs'], 'middleware' => [Middleware\isAuthenticated::class]]), - $routerService->createNewRoute('GET', '/jobs/schedule/trakt-history-sync', [[Web\JobController::class, 'scheduleTraktHistorySync'], 'middleware' => [Middleware\isAuthenticated::class]]), - $routerService->createNewRoute('GET', '/jobs/schedule/trakt-ratings-sync', [[Web\JobController::class, 'scheduleTraktRatingsSync'], 'middleware' => [Middleware\isAuthenticated::class]]), - $routerService->createNewRoute('POST', '/jobs/schedule/letterboxd-diary-sync', [[Web\JobController::class, 'scheduleLetterboxdDiaryImport'], 'middleware' => [Middleware\isAuthenticated::class]]), - $routerService->createNewRoute('POST', '/jobs/schedule/letterboxd-ratings-sync', [[Web\JobController::class, 'scheduleLetterboxdRatingsImport'], 'middleware' => [Middleware\isAuthenticated::class]]), - $routerService->createNewRoute('GET', '/jobs/schedule/plex-watchlist-sync', [[Web\JobController::class, 'schedulePlexWatchlistImport'], 'middleware' => [Middleware\isAuthenticated::class, Middleware\HasPlexAccessToken::class]]), - $routerService->createNewRoute('GET', '/jobs/schedule/jellyfin-import-history', [[Web\JobController::class, 'scheduleJellyfinImportHistory'], 'middleware' => [Middleware\isAuthenticated::class, Middleware\HasJellyfinToken::class]]), - $routerService->createNewRoute('GET', '/jobs/schedule/jellyfin-export-history', [[Web\JobController::class, 'scheduleJellyfinExportHistory'], 'middleware' => [Middleware\isAuthenticated::class, Middleware\HasJellyfinToken::class]]), + ############# + # Job Queue # + ############# + $routes->createNewRoute('GET', '/jobs', [Web\JobController::class, 'getJobs'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/job-queue/purge-processed', [Web\JobController::class, 'purgeProcessedJobs'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/job-queue/purge-all', [Web\JobController::class, 'purgeAllJobs'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/jobs/schedule/trakt-history-sync', [Web\JobController::class, 'scheduleTraktHistorySync'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/jobs/schedule/trakt-ratings-sync', [Web\JobController::class, 'scheduleTraktRatingsSync'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/jobs/schedule/letterboxd-diary-sync', [Web\JobController::class, 'scheduleLetterboxdDiaryImport'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/jobs/schedule/letterboxd-ratings-sync', [Web\JobController::class, 'scheduleLetterboxdRatingsImport'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/jobs/schedule/plex-watchlist-sync', [Web\JobController::class, 'schedulePlexWatchlistImport'])->addMiddleware(Middleware\isAuthenticated::class, Middleware\HasPlexAccessToken::class); + $routes->createNewRoute('GET', '/jobs/schedule/jellyfin-import-history', [Web\JobController::class, 'scheduleJellyfinImportHistory'])->addMiddleware(Middleware\isAuthenticated::class, Middleware\HasJellyfinToken::class); + $routes->createNewRoute('GET', '/jobs/schedule/jellyfin-export-history', [Web\JobController::class, 'scheduleJellyfinExportHistory'])->addMiddleware(Middleware\isAuthenticated::class, Middleware\HasJellyfinToken::class); - ############ - # Settings # - ############ - $routerService->createNewRoute('GET', '/settings/account/general', [Web\SettingsController::class, 'renderGeneralAccountPage'])->addMiddleware(Middleware\isAuthenticated::class), - $routerService->createNewRoute('GET', '/settings/account/general/api-token', [Web\SettingsController::class, 'getApiToken']), - $routerService->createNewRoute('DELETE', '/settings/account/general/api-token', [Web\SettingsController::class, 'deleteApiToken']), - $routerService->createNewRoute('PUT', '/settings/account/general/api-token', [Web\SettingsController::class, 'regenerateApiToken']), - $routerService->createNewRoute('GET', '/settings/account/dashboard', [Web\SettingsController::class, 'renderDashboardAccountPage']), - $routerService->createNewRoute('GET', '/settings/account/security', [Web\SettingsController::class, 'renderSecurityAccountPage']), - $routerService->createNewRoute('GET', '/settings/account/data', [Web\SettingsController::class, 'renderDataAccountPage']), - $routerService->createNewRoute('GET', '/settings/server/general', [Web\SettingsController::class, 'renderServerGeneralPage']), - $routerService->createNewRoute('GET', '/settings/server/jobs', [Web\SettingsController::class, 'renderServerJobsPage']), - $routerService->createNewRoute('POST', '/settings/server/general', [Web\SettingsController::class, 'updateServerGeneral']), - $routerService->createNewRoute('GET', '/settings/server/users', [Web\SettingsController::class, 'renderServerUsersPage']), - $routerService->createNewRoute('GET', '/settings/server/email', [Web\SettingsController::class, 'renderServerEmailPage']), - $routerService->createNewRoute('POST', '/settings/server/email', [Web\SettingsController::class, 'updateServerEmail']), - $routerService->createNewRoute('POST', '/settings/server/email-test', [Web\SettingsController::class, 'sendTestEmail']), - $routerService->createNewRoute('POST', '/settings/account', [Web\SettingsController::class, 'updateGeneral']), - $routerService->createNewRoute('POST', '/settings/account/security/update-password', [Web\SettingsController::class, 'updatePassword']), - $routerService->createNewRoute('POST', '/settings/account/security/create-totp-uri', [Web\TwoFactorAuthenticationController::class, 'createTotpUri']), - $routerService->createNewRoute('POST', '/settings/account/security/disable-totp', [Web\TwoFactorAuthenticationController::class, 'disableTotp']), - $routerService->createNewRoute('POST', '/settings/account/security/enable-totp', [Web\TwoFactorAuthenticationController::class, 'enableTotp']), - $routerService->createNewRoute('GET', '/settings/account/export/csv/{exportType:.+}', [Web\ExportController::class, 'getCsvExport']), - $routerService->createNewRoute('POST', '/settings/account/import/csv/{exportType:.+}', [Web\ImportController::class, 'handleCsvImport']), - $routerService->createNewRoute('GET', '/settings/account/delete-ratings', [Web\SettingsController::class, 'deleteRatings']), - $routerService->createNewRoute('GET', '/settings/account/delete-history', [Web\SettingsController::class, 'deleteHistory']), - $routerService->createNewRoute('GET', '/settings/account/delete-account', [Web\SettingsController::class, 'deleteAccount']), - $routerService->createNewRoute('POST', '/settings/account/update-dashboard-rows', [Web\SettingsController::class, 'updateDashboardRows']), - $routerService->createNewRoute('POST', '/settings/account/reset-dashboard-rows', [Web\SettingsController::class, 'resetDashboardRows']), - $routerService->createNewRoute('GET', '/settings/integrations/trakt', [Web\SettingsController::class, 'renderTraktPage']), - $routerService->createNewRoute('POST', '/settings/trakt', [Web\SettingsController::class, 'updateTrakt']), - $routerService->createNewRoute('POST', '/settings/trakt/verify-credentials', [Web\SettingsController::class, 'traktVerifyCredentials']), - $routerService->createNewRoute('GET', '/settings/integrations/letterboxd', [Web\SettingsController::class, 'renderLetterboxdPage']), - $routerService->createNewRoute('GET', '/settings/letterboxd-export', [Web\SettingsController::class, 'generateLetterboxdExportData']), - $routerService->createNewRoute('GET', '/settings/integrations/plex', [Web\SettingsController::class, 'renderPlexPage']), - $routerService->createNewRoute('GET', '/settings/plex/logout', [Web\PlexController::class, 'removePlexAccessTokens']), - $routerService->createNewRoute('POST', '/settings/plex/server-url-save', [Web\PlexController::class, 'savePlexServerUrl']), - $routerService->createNewRoute('POST', '/settings/plex/server-url-verify', [Web\PlexController::class, 'verifyPlexServerUrl']), - $routerService->createNewRoute('GET', '/settings/plex/authentication-url', [Web\PlexController::class, 'generatePlexAuthenticationUrl']), - $routerService->createNewRoute('GET', '/settings/plex/callback', [Web\PlexController::class, 'processPlexCallback']), - $routerService->createNewRoute('POST', '/settings/plex', [Web\SettingsController::class, 'updatePlex']), - $routerService->createNewRoute('PUT', '/settings/plex/webhook', [Web\PlexController::class, 'regeneratePlexWebhookUrl']), - $routerService->createNewRoute('DELETE', '/settings/plex/webhook', [Web\PlexController::class, 'deletePlexWebhookUrl']), - $routerService->createNewRoute('GET', '/settings/integrations/jellyfin', [Web\SettingsController::class, 'renderJellyfinPage']), - $routerService->createNewRoute('POST', '/settings/jellyfin', [Web\SettingsController::class, 'updateJellyfin']), - $routerService->createNewRoute('POST', '/settings/jellyfin/sync', [Web\JellyfinController::class, 'saveJellyfinSyncOptions']), - $routerService->createNewRoute('POST', '/settings/jellyfin/authenticate', [Web\JellyfinController::class, 'authenticateJellyfinAccount']), - $routerService->createNewRoute('POST', '/settings/jellyfin/remove-authentication', [Web\JellyfinController::class, 'removeJellyfinAuthentication']), - $routerService->createNewRoute('POST', '/settings/jellyfin/server-url-save', [Web\JellyfinController::class, 'saveJellyfinServerUrl']), - $routerService->createNewRoute('POST', '/settings/jellyfin/server-url-verify', [Web\JellyfinController::class, 'verifyJellyfinServerUrl']), - $routerService->createNewRoute('GET', '/settings/jellyfin/webhook', [Web\JellyfinController::class, 'getJellyfinWebhookUrl']), - $routerService->createNewRoute('PUT', '/settings/jellyfin/webhook', [Web\JellyfinController::class, 'regenerateJellyfinWebhookUrl']), - $routerService->createNewRoute('DELETE', '/settings/jellyfin/webhook', [Web\JellyfinController::class, 'deleteJellyfinWebhookUrl']), - $routerService->createNewRoute('GET', '/settings/integrations/emby', [Web\SettingsController::class, 'renderEmbyPage']), - $routerService->createNewRoute('POST', '/settings/emby', [Web\SettingsController::class, 'updateEmby']), - $routerService->createNewRoute('GET', '/settings/emby/webhook', [Web\EmbyController::class, 'getEmbyWebhookUrl']), - $routerService->createNewRoute('PUT', '/settings/emby/webhook', [Web\EmbyController::class, 'regenerateEmbyWebhookUrl']), - $routerService->createNewRoute('DELETE', '/settings/emby/webhook', [Web\EmbyController::class, 'deleteEmbyWebhookUrl']), - $routerService->createNewRoute('GET', '/settings/app', [Web\SettingsController::class, 'renderAppPage']), - $routerService->createNewRoute('GET', '/settings/integrations/netflix', [Web\SettingsController::class, 'renderNetflixPage']), - $routerService->createNewRoute('POST', '/settings/netflix', [Web\NetflixController::class, 'matchNetflixActivityCsvWithTmdbMovies']), - $routerService->createNewRoute('POST', '/settings/netflix/import', [Web\NetflixController::class, 'importNetflixData']), - $routerService->createNewRoute('POST', '/settings/netflix/search', [Web\NetflixController::class, 'searchTmbd']), - $routerService->createNewRoute('GET', '/settings/users', [Web\UserController::class, 'fetchUsers']), - $routerService->createNewRoute('POST', '/settings/users', [Web\UserController::class, 'createUser']), - $routerService->createNewRoute('PUT', '/settings/users/{userId:\d+}', [Web\UserController::class, 'updateUser']), - $routerService->createNewRoute('DELETE', '/settings/users/{userId:\d+}', [Web\UserController::class, 'deleteUser']), + ############ + # Settings # + ############ + $routes->createNewRoute('GET', '/settings/account/general', [Web\SettingsController::class, 'renderGeneralAccountPage'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/settings/account/general/api-token', [Web\SettingsController::class, 'getApiToken']); + $routes->createNewRoute('DELETE', '/settings/account/general/api-token', [Web\SettingsController::class, 'deleteApiToken']); + $routes->createNewRoute('PUT', '/settings/account/general/api-token', [Web\SettingsController::class, 'regenerateApiToken']); + $routes->createNewRoute('GET', '/settings/account/dashboard', [Web\SettingsController::class, 'renderDashboardAccountPage']); + $routes->createNewRoute('GET', '/settings/account/security', [Web\SettingsController::class, 'renderSecurityAccountPage']); + $routes->createNewRoute('GET', '/settings/account/data', [Web\SettingsController::class, 'renderDataAccountPage']); + $routes->createNewRoute('GET', '/settings/server/general', [Web\SettingsController::class, 'renderServerGeneralPage']); + $routes->createNewRoute('GET', '/settings/server/jobs', [Web\SettingsController::class, 'renderServerJobsPage']); + $routes->createNewRoute('POST', '/settings/server/general', [Web\SettingsController::class, 'updateServerGeneral']); + $routes->createNewRoute('GET', '/settings/server/users', [Web\SettingsController::class, 'renderServerUsersPage']); + $routes->createNewRoute('GET', '/settings/server/email', [Web\SettingsController::class, 'renderServerEmailPage']); + $routes->createNewRoute('POST', '/settings/server/email', [Web\SettingsController::class, 'updateServerEmail']); + $routes->createNewRoute('POST', '/settings/server/email-test', [Web\SettingsController::class, 'sendTestEmail']); + $routes->createNewRoute('POST', '/settings/account', [Web\SettingsController::class, 'updateGeneral']); + $routes->createNewRoute('POST', '/settings/account/security/update-password', [Web\SettingsController::class, 'updatePassword']); + $routes->createNewRoute('POST', '/settings/account/security/create-totp-uri', [Web\TwoFactorAuthenticationController::class, 'createTotpUri']); + $routes->createNewRoute('POST', '/settings/account/security/disable-totp', [Web\TwoFactorAuthenticationController::class, 'disableTotp']); + $routes->createNewRoute('POST', '/settings/account/security/enable-totp', [Web\TwoFactorAuthenticationController::class, 'enableTotp']); + $routes->createNewRoute('GET', '/settings/account/export/csv/{exportType:.+}', [Web\ExportController::class, 'getCsvExport']); + $routes->createNewRoute('POST', '/settings/account/import/csv/{exportType:.+}', [Web\ImportController::class, 'handleCsvImport']); + $routes->createNewRoute('GET', '/settings/account/delete-ratings', [Web\SettingsController::class, 'deleteRatings']); + $routes->createNewRoute('GET', '/settings/account/delete-history', [Web\SettingsController::class, 'deleteHistory']); + $routes->createNewRoute('GET', '/settings/account/delete-account', [Web\SettingsController::class, 'deleteAccount']); + $routes->createNewRoute('POST', '/settings/account/update-dashboard-rows', [Web\SettingsController::class, 'updateDashboardRows']); + $routes->createNewRoute('POST', '/settings/account/reset-dashboard-rows', [Web\SettingsController::class, 'resetDashboardRows']); + $routes->createNewRoute('GET', '/settings/integrations/trakt', [Web\SettingsController::class, 'renderTraktPage']); + $routes->createNewRoute('POST', '/settings/trakt', [Web\SettingsController::class, 'updateTrakt']); + $routes->createNewRoute('POST', '/settings/trakt/verify-credentials', [Web\SettingsController::class, 'traktVerifyCredentials']); + $routes->createNewRoute('GET', '/settings/integrations/letterboxd', [Web\SettingsController::class, 'renderLetterboxdPage']); + $routes->createNewRoute('GET', '/settings/letterboxd-export', [Web\SettingsController::class, 'generateLetterboxdExportData']); + $routes->createNewRoute('GET', '/settings/integrations/plex', [Web\SettingsController::class, 'renderPlexPage']); + $routes->createNewRoute('GET', '/settings/plex/logout', [Web\PlexController::class, 'removePlexAccessTokens']); + $routes->createNewRoute('POST', '/settings/plex/server-url-save', [Web\PlexController::class, 'savePlexServerUrl']); + $routes->createNewRoute('POST', '/settings/plex/server-url-verify', [Web\PlexController::class, 'verifyPlexServerUrl']); + $routes->createNewRoute('GET', '/settings/plex/authentication-url', [Web\PlexController::class, 'generatePlexAuthenticationUrl']); + $routes->createNewRoute('GET', '/settings/plex/callback', [Web\PlexController::class, 'processPlexCallback']); + $routes->createNewRoute('POST', '/settings/plex', [Web\SettingsController::class, 'updatePlex']); + $routes->createNewRoute('PUT', '/settings/plex/webhook', [Web\PlexController::class, 'regeneratePlexWebhookUrl']); + $routes->createNewRoute('DELETE', '/settings/plex/webhook', [Web\PlexController::class, 'deletePlexWebhookUrl']); + $routes->createNewRoute('GET', '/settings/integrations/jellyfin', [Web\SettingsController::class, 'renderJellyfinPage']); + $routes->createNewRoute('POST', '/settings/jellyfin', [Web\SettingsController::class, 'updateJellyfin']); + $routes->createNewRoute('POST', '/settings/jellyfin/sync', [Web\JellyfinController::class, 'saveJellyfinSyncOptions']); + $routes->createNewRoute('POST', '/settings/jellyfin/authenticate', [Web\JellyfinController::class, 'authenticateJellyfinAccount']); + $routes->createNewRoute('POST', '/settings/jellyfin/remove-authentication', [Web\JellyfinController::class, 'removeJellyfinAuthentication']); + $routes->createNewRoute('POST', '/settings/jellyfin/server-url-save', [Web\JellyfinController::class, 'saveJellyfinServerUrl']); + $routes->createNewRoute('POST', '/settings/jellyfin/server-url-verify', [Web\JellyfinController::class, 'verifyJellyfinServerUrl']); + $routes->createNewRoute('GET', '/settings/jellyfin/webhook', [Web\JellyfinController::class, 'getJellyfinWebhookUrl']); + $routes->createNewRoute('PUT', '/settings/jellyfin/webhook', [Web\JellyfinController::class, 'regenerateJellyfinWebhookUrl']); + $routes->createNewRoute('DELETE', '/settings/jellyfin/webhook', [Web\JellyfinController::class, 'deleteJellyfinWebhookUrl']); + $routes->createNewRoute('GET', '/settings/integrations/emby', [Web\SettingsController::class, 'renderEmbyPage']); + $routes->createNewRoute('POST', '/settings/emby', [Web\SettingsController::class, 'updateEmby']); + $routes->createNewRoute('GET', '/settings/emby/webhook', [Web\EmbyController::class, 'getEmbyWebhookUrl']); + $routes->createNewRoute('PUT', '/settings/emby/webhook', [Web\EmbyController::class, 'regenerateEmbyWebhookUrl']); + $routes->createNewRoute('DELETE', '/settings/emby/webhook', [Web\EmbyController::class, 'deleteEmbyWebhookUrl']); + $routes->createNewRoute('GET', '/settings/app', [Web\SettingsController::class, 'renderAppPage']); + $routes->createNewRoute('GET', '/settings/integrations/netflix', [Web\SettingsController::class, 'renderNetflixPage']); + $routes->createNewRoute('POST', '/settings/netflix', [Web\NetflixController::class, 'matchNetflixActivityCsvWithTmdbMovies']); + $routes->createNewRoute('POST', '/settings/netflix/import', [Web\NetflixController::class, 'importNetflixData']); + $routes->createNewRoute('POST', '/settings/netflix/search', [Web\NetflixController::class, 'searchTmbd']); + $routes->createNewRoute('GET', '/settings/users', [Web\UserController::class, 'fetchUsers']); + $routes->createNewRoute('POST', '/settings/users', [Web\UserController::class, 'createUser']); + $routes->createNewRoute('PUT', '/settings/users/{userId:\d+}', [Web\UserController::class, 'updateUser']); + $routes->createNewRoute('DELETE', '/settings/users/{userId:\d+}', [Web\UserController::class, 'deleteUser']); - ########## - # Movies # - ########## - $routerService->createNewRoute('GET', '/movies/{id:[0-9]+}/refresh-tmdb', [Web\Movie\MovieController::class, 'refreshTmdbData']), - $routerService->createNewRoute('GET', '/movies/{id:[0-9]+}/refresh-imdb', [Web\Movie\MovieController::class, 'refreshImdbRating']), - $routerService->createNewRoute('GET', '/movies/{id:[0-9]+}/watch-providers', [Web\Movie\MovieWatchProviderController::class, 'getWatchProviders']), - $routerService->createNewRoute('GET', '/movies/{id:[0-9]+}/add-watchlist', [Web\Movie\MovieWatchlistController::class, 'addToWatchlist']), - $routerService->createNewRoute('GET', '/movies/{id:[0-9]+}/remove-watchlist', [Web\Movie\MovieWatchlistController::class, 'removeFromWatchlist']), + ########## + # Movies # + ########## + $routes->createNewRoute('GET', '/movies/{id:[0-9]+}/refresh-tmdb', [Web\Movie\MovieController::class, 'refreshTmdbData']); + $routes->createNewRoute('GET', '/movies/{id:[0-9]+}/refresh-imdb', [Web\Movie\MovieController::class, 'refreshImdbRating']); + $routes->createNewRoute('GET', '/movies/{id:[0-9]+}/watch-providers', [Web\Movie\MovieWatchProviderController::class, 'getWatchProviders']); + $routes->createNewRoute('GET', '/movies/{id:[0-9]+}/add-watchlist', [Web\Movie\MovieWatchlistController::class, 'addToWatchlist']); + $routes->createNewRoute('GET', '/movies/{id:[0-9]+}/remove-watchlist', [Web\Movie\MovieWatchlistController::class, 'removeFromWatchlist']); - ############## - # User media # - ############## - $routerService->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/dashboard', [Web\DashboardController::class, 'render']), - $routerService->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/history', [Web\HistoryController::class, 'renderHistory']), - $routerService->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/watchlist', [Web\WatchlistController::class, 'renderWatchlist']), - $routerService->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/movies', [Web\MoviesController::class, 'renderPage']), - $routerService->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/actors', [Web\ActorsController::class, 'renderPage']), - $routerService->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/directors', [Web\DirectorsController::class, 'renderPage']), - $routerService->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}', [Web\Movie\MovieController::class, 'renderPage']), - $routerService->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/persons/{id:\d+}', [Web\PersonController::class, 'renderPage']), - $routerService->createNewRoute('DELETE', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}/history', [Web\HistoryController::class, 'deleteHistoryEntry']), - $routerService->createNewRoute('POST', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}/history', [Web\HistoryController::class, 'createHistoryEntry']), - $routerService->createNewRoute('POST', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}/rating', [Web\Movie\MovieRatingController::class, 'updateRating']), - $routerService->createNewRoute('POST', '/log-movie', [Web\HistoryController::class, 'logMovie']), - $routerService->createNewRoute('POST', '/add-movie-to-watchlist', [Web\WatchlistController::class, 'addMovieToWatchlist']), - $routerService->createNewRoute('GET', '/fetchMovieRatingByTmdbdId', [Web\Movie\MovieRatingController::class, 'fetchMovieRatingByTmdbdId']), - ); + ############## + # User media # + ############## + $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/dashboard', [Web\DashboardController::class, 'render']); + $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/history', [Web\HistoryController::class, 'renderHistory']); + $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/watchlist', [Web\WatchlistController::class, 'renderWatchlist']); + $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/movies', [Web\MoviesController::class, 'renderPage']); + $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/actors', [Web\ActorsController::class, 'renderPage']); + $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/directors', [Web\DirectorsController::class, 'renderPage']); + $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}', [Web\Movie\MovieController::class, 'renderPage']); + $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/persons/{id:\d+}', [Web\PersonController::class, 'renderPage']); + $routes->createNewRoute('DELETE', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}/history', [Web\HistoryController::class, 'deleteHistoryEntry']); + $routes->createNewRoute('POST', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}/history', [Web\HistoryController::class, 'createHistoryEntry']); + $routes->createNewRoute('POST', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}/rating', [Web\Movie\MovieRatingController::class, 'updateRating']); + $routes->createNewRoute('POST', '/log-movie', [Web\HistoryController::class, 'logMovie']); + $routes->createNewRoute('POST', '/add-movie-to-watchlist', [Web\WatchlistController::class, 'addMovieToWatchlist']); + $routes->createNewRoute('GET', '/fetchMovieRatingByTmdbdId', [Web\Movie\MovieRatingController::class, 'fetchMovieRatingByTmdbdId']); $routerService->generateRouteCallback($routeCollector, $routes); } @@ -148,9 +146,7 @@ function addApiRoutes(FastRoute\RouteCollector $routeCollector) : void { $routerService = new RouterService(); $routes = $routerService->createRouteList(); - $routes->addRoutes( - $routerService->createNewRoute('GET', '/openapi.jsn', [Api\OpenApiController::class, 'getSchema']), - $routerService->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/history', [Api\HistoryController::class, 'getHistory']), - ); + $routes->createNewRoute('GET', '/openapi.jsn', [Api\OpenApiController::class, 'getSchema']); + $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/history', [Api\HistoryController::class, 'getHistory']); $routerService->generateRouteCallback($routeCollector, $routes); } \ No newline at end of file diff --git a/src/Service/Router/Dto/Route.php b/src/Service/Router/Dto/Route.php index ad8b9692..78d4ed98 100644 --- a/src/Service/Router/Dto/Route.php +++ b/src/Service/Router/Dto/Route.php @@ -40,9 +40,8 @@ public function getMiddleware() :?array return $this->middleware; } - public function addMiddleware(...$middlewares) : self + public function addMiddleware(...$middlewares) : void { $this->middleware = $middlewares; - return $this; } } \ No newline at end of file diff --git a/src/Service/Router/Dto/RouteList.php b/src/Service/Router/Dto/RouteList.php index 3a5c9a6e..4c24195f 100644 --- a/src/Service/Router/Dto/RouteList.php +++ b/src/Service/Router/Dto/RouteList.php @@ -23,6 +23,13 @@ public function addRoutes(...$routes) : void $this->data = array_merge($this->data, $routes); } + public function createNewRoute(string $httpMethod, string $route, array $handler) : Route + { + $route = Route::create($httpMethod, $route, $handler); + $this->data[] = $route; + return $route; + } + public function getRoutes() : array { return $this->data; diff --git a/src/Service/Router/RouterService.php b/src/Service/Router/RouterService.php index 564bf38f..bec1a013 100644 --- a/src/Service/Router/RouterService.php +++ b/src/Service/Router/RouterService.php @@ -8,12 +8,6 @@ class RouterService { - public function createNewRoute(string $httpMethod, string $route, array $handler) : Route - { - return Route::create($httpMethod, $route, $handler); - } - - public function createRouteList() : RouteList { return RouteList::create(); From 60c22b99837de6c26e9b77721e9c33e72a0cac98 Mon Sep 17 00:00:00 2001 From: JVT038 <47184046+JVT038@users.noreply.github.com> Date: Mon, 4 Sep 2023 17:31:51 +0200 Subject: [PATCH 04/11] Added middleware to most controllers --- public/index.php | 4 +- settings/routes.php | 144 ++++++++-------- .../Middleware/CanUserBeViewed.php | 24 +++ src/HttpController/Middleware/IsAdmin.php | 2 +- .../Web/DashboardController.php | 4 - src/HttpController/Web/EmbyController.php | 8 - src/HttpController/Web/ExportController.php | 4 - src/HttpController/Web/HistoryController.php | 16 +- src/HttpController/Web/ImportController.php | 4 - src/HttpController/Web/JellyfinController.php | 28 --- .../Web/Movie/MovieController.php | 8 - .../Web/Movie/MovieRatingController.php | 8 - .../Web/Movie/MovieWatchlistController.php | 8 - src/HttpController/Web/NetflixController.php | 12 -- src/HttpController/Web/PlexController.php | 28 --- src/HttpController/Web/SettingsController.php | 160 ------------------ .../Web/TwoFactorAuthenticationController.php | 12 -- src/HttpController/Web/UserController.php | 8 - .../Web/WatchlistController.php | 4 - 19 files changed, 101 insertions(+), 385 deletions(-) create mode 100644 src/HttpController/Middleware/CanUserBeViewed.php diff --git a/public/index.php b/public/index.php index 5fe65be3..743c5f52 100644 --- a/public/index.php +++ b/public/index.php @@ -12,6 +12,8 @@ $container = require(__DIR__ . '/../bootstrap.php'); $httpRequest = $container->get(Request::class); +$middlewareMethodName = 'main'; + try { $dispatcher = FastRoute\simpleDispatcher( require(__DIR__ . '/../settings/routes.php') @@ -38,7 +40,7 @@ $httpRequest->addRouteParameters($routeInfo[2]); foreach($routeInfo[1]['middleware'] as $middleware) { - $middlewareResponse = $container->call([$middleware, 'main']); + $middlewareResponse = $container->call([$middleware, $middlewareMethodName]); if($middlewareResponse instanceof Response) { $response = $middlewareResponse; break 2; diff --git a/settings/routes.php b/settings/routes.php index c05ef603..cb834c5d 100644 --- a/settings/routes.php +++ b/settings/routes.php @@ -49,83 +49,83 @@ function addWebRoutes(FastRoute\RouteCollector $routeCollector) : void # Settings # ############ $routes->createNewRoute('GET', '/settings/account/general', [Web\SettingsController::class, 'renderGeneralAccountPage'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/settings/account/general/api-token', [Web\SettingsController::class, 'getApiToken']); - $routes->createNewRoute('DELETE', '/settings/account/general/api-token', [Web\SettingsController::class, 'deleteApiToken']); - $routes->createNewRoute('PUT', '/settings/account/general/api-token', [Web\SettingsController::class, 'regenerateApiToken']); - $routes->createNewRoute('GET', '/settings/account/dashboard', [Web\SettingsController::class, 'renderDashboardAccountPage']); - $routes->createNewRoute('GET', '/settings/account/security', [Web\SettingsController::class, 'renderSecurityAccountPage']); - $routes->createNewRoute('GET', '/settings/account/data', [Web\SettingsController::class, 'renderDataAccountPage']); - $routes->createNewRoute('GET', '/settings/server/general', [Web\SettingsController::class, 'renderServerGeneralPage']); - $routes->createNewRoute('GET', '/settings/server/jobs', [Web\SettingsController::class, 'renderServerJobsPage']); - $routes->createNewRoute('POST', '/settings/server/general', [Web\SettingsController::class, 'updateServerGeneral']); - $routes->createNewRoute('GET', '/settings/server/users', [Web\SettingsController::class, 'renderServerUsersPage']); - $routes->createNewRoute('GET', '/settings/server/email', [Web\SettingsController::class, 'renderServerEmailPage']); - $routes->createNewRoute('POST', '/settings/server/email', [Web\SettingsController::class, 'updateServerEmail']); - $routes->createNewRoute('POST', '/settings/server/email-test', [Web\SettingsController::class, 'sendTestEmail']); - $routes->createNewRoute('POST', '/settings/account', [Web\SettingsController::class, 'updateGeneral']); - $routes->createNewRoute('POST', '/settings/account/security/update-password', [Web\SettingsController::class, 'updatePassword']); - $routes->createNewRoute('POST', '/settings/account/security/create-totp-uri', [Web\TwoFactorAuthenticationController::class, 'createTotpUri']); - $routes->createNewRoute('POST', '/settings/account/security/disable-totp', [Web\TwoFactorAuthenticationController::class, 'disableTotp']); - $routes->createNewRoute('POST', '/settings/account/security/enable-totp', [Web\TwoFactorAuthenticationController::class, 'enableTotp']); - $routes->createNewRoute('GET', '/settings/account/export/csv/{exportType:.+}', [Web\ExportController::class, 'getCsvExport']); - $routes->createNewRoute('POST', '/settings/account/import/csv/{exportType:.+}', [Web\ImportController::class, 'handleCsvImport']); - $routes->createNewRoute('GET', '/settings/account/delete-ratings', [Web\SettingsController::class, 'deleteRatings']); - $routes->createNewRoute('GET', '/settings/account/delete-history', [Web\SettingsController::class, 'deleteHistory']); - $routes->createNewRoute('GET', '/settings/account/delete-account', [Web\SettingsController::class, 'deleteAccount']); - $routes->createNewRoute('POST', '/settings/account/update-dashboard-rows', [Web\SettingsController::class, 'updateDashboardRows']); - $routes->createNewRoute('POST', '/settings/account/reset-dashboard-rows', [Web\SettingsController::class, 'resetDashboardRows']); - $routes->createNewRoute('GET', '/settings/integrations/trakt', [Web\SettingsController::class, 'renderTraktPage']); - $routes->createNewRoute('POST', '/settings/trakt', [Web\SettingsController::class, 'updateTrakt']); - $routes->createNewRoute('POST', '/settings/trakt/verify-credentials', [Web\SettingsController::class, 'traktVerifyCredentials']); - $routes->createNewRoute('GET', '/settings/integrations/letterboxd', [Web\SettingsController::class, 'renderLetterboxdPage']); - $routes->createNewRoute('GET', '/settings/letterboxd-export', [Web\SettingsController::class, 'generateLetterboxdExportData']); - $routes->createNewRoute('GET', '/settings/integrations/plex', [Web\SettingsController::class, 'renderPlexPage']); - $routes->createNewRoute('GET', '/settings/plex/logout', [Web\PlexController::class, 'removePlexAccessTokens']); - $routes->createNewRoute('POST', '/settings/plex/server-url-save', [Web\PlexController::class, 'savePlexServerUrl']); - $routes->createNewRoute('POST', '/settings/plex/server-url-verify', [Web\PlexController::class, 'verifyPlexServerUrl']); - $routes->createNewRoute('GET', '/settings/plex/authentication-url', [Web\PlexController::class, 'generatePlexAuthenticationUrl']); - $routes->createNewRoute('GET', '/settings/plex/callback', [Web\PlexController::class, 'processPlexCallback']); - $routes->createNewRoute('POST', '/settings/plex', [Web\SettingsController::class, 'updatePlex']); - $routes->createNewRoute('PUT', '/settings/plex/webhook', [Web\PlexController::class, 'regeneratePlexWebhookUrl']); - $routes->createNewRoute('DELETE', '/settings/plex/webhook', [Web\PlexController::class, 'deletePlexWebhookUrl']); - $routes->createNewRoute('GET', '/settings/integrations/jellyfin', [Web\SettingsController::class, 'renderJellyfinPage']); - $routes->createNewRoute('POST', '/settings/jellyfin', [Web\SettingsController::class, 'updateJellyfin']); - $routes->createNewRoute('POST', '/settings/jellyfin/sync', [Web\JellyfinController::class, 'saveJellyfinSyncOptions']); - $routes->createNewRoute('POST', '/settings/jellyfin/authenticate', [Web\JellyfinController::class, 'authenticateJellyfinAccount']); - $routes->createNewRoute('POST', '/settings/jellyfin/remove-authentication', [Web\JellyfinController::class, 'removeJellyfinAuthentication']); - $routes->createNewRoute('POST', '/settings/jellyfin/server-url-save', [Web\JellyfinController::class, 'saveJellyfinServerUrl']); - $routes->createNewRoute('POST', '/settings/jellyfin/server-url-verify', [Web\JellyfinController::class, 'verifyJellyfinServerUrl']); - $routes->createNewRoute('GET', '/settings/jellyfin/webhook', [Web\JellyfinController::class, 'getJellyfinWebhookUrl']); - $routes->createNewRoute('PUT', '/settings/jellyfin/webhook', [Web\JellyfinController::class, 'regenerateJellyfinWebhookUrl']); - $routes->createNewRoute('DELETE', '/settings/jellyfin/webhook', [Web\JellyfinController::class, 'deleteJellyfinWebhookUrl']); - $routes->createNewRoute('GET', '/settings/integrations/emby', [Web\SettingsController::class, 'renderEmbyPage']); - $routes->createNewRoute('POST', '/settings/emby', [Web\SettingsController::class, 'updateEmby']); + $routes->createNewRoute('GET', '/settings/account/general/api-token', [Web\SettingsController::class, 'getApiToken'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('DELETE', '/settings/account/general/api-token', [Web\SettingsController::class, 'deleteApiToken'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('PUT', '/settings/account/general/api-token', [Web\SettingsController::class, 'regenerateApiToken'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/settings/account/dashboard', [Web\SettingsController::class, 'renderDashboardAccountPage'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/settings/account/security', [Web\SettingsController::class, 'renderSecurityAccountPage'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/settings/account/data', [Web\SettingsController::class, 'renderDataAccountPage'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/settings/server/general', [Web\SettingsController::class, 'renderServerGeneralPage'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/settings/server/jobs', [Web\SettingsController::class, 'renderServerJobsPage'])->addMiddleware(Middleware\isAuthenticated::class, Middleware\IsAdmin::class); + $routes->createNewRoute('POST', '/settings/server/general', [Web\SettingsController::class, 'updateServerGeneral'])->addMiddleware(Middleware\isAuthenticated::class, Middleware\IsAdmin::class); + $routes->createNewRoute('GET', '/settings/server/users', [Web\SettingsController::class, 'renderServerUsersPage'])->addMiddleware(Middleware\isAuthenticated::class, Middleware\IsAdmin::class); + $routes->createNewRoute('GET', '/settings/server/email', [Web\SettingsController::class, 'renderServerEmailPage'])->addMiddleware(Middleware\isAuthenticated::class, Middleware\IsAdmin::class); + $routes->createNewRoute('POST', '/settings/server/email', [Web\SettingsController::class, 'updateServerEmail'])->addMiddleware(Middleware\isAuthenticated::class, Middleware\IsAdmin::class); + $routes->createNewRoute('POST', '/settings/server/email-test', [Web\SettingsController::class, 'sendTestEmail'])->addMiddleware(Middleware\isAuthenticated::class, Middleware\IsAdmin::class); + $routes->createNewRoute('POST', '/settings/account', [Web\SettingsController::class, 'updateGeneral'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/settings/account/security/update-password', [Web\SettingsController::class, 'updatePassword'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/settings/account/security/create-totp-uri', [Web\TwoFactorAuthenticationController::class, 'createTotpUri'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/settings/account/security/disable-totp', [Web\TwoFactorAuthenticationController::class, 'disableTotp'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/settings/account/security/enable-totp', [Web\TwoFactorAuthenticationController::class, 'enableTotp'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/settings/account/export/csv/{exportType:.+}', [Web\ExportController::class, 'getCsvExport'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/settings/account/import/csv/{exportType:.+}', [Web\ImportController::class, 'handleCsvImport'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/settings/account/delete-ratings', [Web\SettingsController::class, 'deleteRatings'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/settings/account/delete-history', [Web\SettingsController::class, 'deleteHistory'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/settings/account/delete-account', [Web\SettingsController::class, 'deleteAccount'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/settings/account/update-dashboard-rows', [Web\SettingsController::class, 'updateDashboardRows'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/settings/account/reset-dashboard-rows', [Web\SettingsController::class, 'resetDashboardRows'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/settings/integrations/trakt', [Web\SettingsController::class, 'renderTraktPage'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/settings/trakt', [Web\SettingsController::class, 'updateTrakt'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/settings/trakt/verify-credentials', [Web\SettingsController::class, 'traktVerifyCredentials'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/settings/integrations/letterboxd', [Web\SettingsController::class, 'renderLetterboxdPage'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/settings/letterboxd-export', [Web\SettingsController::class, 'generateLetterboxdExportData'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/settings/integrations/plex', [Web\SettingsController::class, 'renderPlexPage'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/settings/plex/logout', [Web\PlexController::class, 'removePlexAccessTokens'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/settings/plex/server-url-save', [Web\PlexController::class, 'savePlexServerUrl'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/settings/plex/server-url-verify', [Web\PlexController::class, 'verifyPlexServerUrl'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/settings/plex/authentication-url', [Web\PlexController::class, 'generatePlexAuthenticationUrl'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/settings/plex/callback', [Web\PlexController::class, 'processPlexCallback'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/settings/plex', [Web\SettingsController::class, 'updatePlex'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('PUT', '/settings/plex/webhook', [Web\PlexController::class, 'regeneratePlexWebhookUrl'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('DELETE', '/settings/plex/webhook', [Web\PlexController::class, 'deletePlexWebhookUrl'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/settings/integrations/jellyfin', [Web\SettingsController::class, 'renderJellyfinPage'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/settings/jellyfin', [Web\SettingsController::class, 'updateJellyfin'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/settings/jellyfin/sync', [Web\JellyfinController::class, 'saveJellyfinSyncOptions'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/settings/jellyfin/authenticate', [Web\JellyfinController::class, 'authenticateJellyfinAccount'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/settings/jellyfin/remove-authentication', [Web\JellyfinController::class, 'removeJellyfinAuthentication'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/settings/jellyfin/server-url-save', [Web\JellyfinController::class, 'saveJellyfinServerUrl'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/settings/jellyfin/server-url-verify', [Web\JellyfinController::class, 'verifyJellyfinServerUrl'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/settings/jellyfin/webhook', [Web\JellyfinController::class, 'getJellyfinWebhookUrl'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('PUT', '/settings/jellyfin/webhook', [Web\JellyfinController::class, 'regenerateJellyfinWebhookUrl'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('DELETE', '/settings/jellyfin/webhook', [Web\JellyfinController::class, 'deleteJellyfinWebhookUrl'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/settings/integrations/emby', [Web\SettingsController::class, 'renderEmbyPage'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/settings/emby', [Web\SettingsController::class, 'updateEmby'])->addMiddleware(Middleware\isAuthenticated::class); $routes->createNewRoute('GET', '/settings/emby/webhook', [Web\EmbyController::class, 'getEmbyWebhookUrl']); - $routes->createNewRoute('PUT', '/settings/emby/webhook', [Web\EmbyController::class, 'regenerateEmbyWebhookUrl']); - $routes->createNewRoute('DELETE', '/settings/emby/webhook', [Web\EmbyController::class, 'deleteEmbyWebhookUrl']); - $routes->createNewRoute('GET', '/settings/app', [Web\SettingsController::class, 'renderAppPage']); - $routes->createNewRoute('GET', '/settings/integrations/netflix', [Web\SettingsController::class, 'renderNetflixPage']); - $routes->createNewRoute('POST', '/settings/netflix', [Web\NetflixController::class, 'matchNetflixActivityCsvWithTmdbMovies']); - $routes->createNewRoute('POST', '/settings/netflix/import', [Web\NetflixController::class, 'importNetflixData']); - $routes->createNewRoute('POST', '/settings/netflix/search', [Web\NetflixController::class, 'searchTmbd']); + $routes->createNewRoute('PUT', '/settings/emby/webhook', [Web\EmbyController::class, 'regenerateEmbyWebhookUrl'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('DELETE', '/settings/emby/webhook', [Web\EmbyController::class, 'deleteEmbyWebhookUrl'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/settings/app', [Web\SettingsController::class, 'renderAppPage'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/settings/integrations/netflix', [Web\SettingsController::class, 'renderNetflixPage'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/settings/netflix', [Web\NetflixController::class, 'matchNetflixActivityCsvWithTmdbMovies'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/settings/netflix/import', [Web\NetflixController::class, 'importNetflixData'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/settings/netflix/search', [Web\NetflixController::class, 'searchTmbd'])->addMiddleware(Middleware\isAuthenticated::class); $routes->createNewRoute('GET', '/settings/users', [Web\UserController::class, 'fetchUsers']); $routes->createNewRoute('POST', '/settings/users', [Web\UserController::class, 'createUser']); - $routes->createNewRoute('PUT', '/settings/users/{userId:\d+}', [Web\UserController::class, 'updateUser']); - $routes->createNewRoute('DELETE', '/settings/users/{userId:\d+}', [Web\UserController::class, 'deleteUser']); + $routes->createNewRoute('PUT', '/settings/users/{userId:\d+}', [Web\UserController::class, 'updateUser'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('DELETE', '/settings/users/{userId:\d+}', [Web\UserController::class, 'deleteUser'])->addMiddleware(Middleware\isAuthenticated::class); ########## # Movies # ########## - $routes->createNewRoute('GET', '/movies/{id:[0-9]+}/refresh-tmdb', [Web\Movie\MovieController::class, 'refreshTmdbData']); - $routes->createNewRoute('GET', '/movies/{id:[0-9]+}/refresh-imdb', [Web\Movie\MovieController::class, 'refreshImdbRating']); + $routes->createNewRoute('GET', '/movies/{id:[0-9]+}/refresh-tmdb', [Web\Movie\MovieController::class, 'refreshTmdbData'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/movies/{id:[0-9]+}/refresh-imdb', [Web\Movie\MovieController::class, 'refreshImdbRating'])->addMiddleware(Middleware\isAuthenticated::class); $routes->createNewRoute('GET', '/movies/{id:[0-9]+}/watch-providers', [Web\Movie\MovieWatchProviderController::class, 'getWatchProviders']); - $routes->createNewRoute('GET', '/movies/{id:[0-9]+}/add-watchlist', [Web\Movie\MovieWatchlistController::class, 'addToWatchlist']); - $routes->createNewRoute('GET', '/movies/{id:[0-9]+}/remove-watchlist', [Web\Movie\MovieWatchlistController::class, 'removeFromWatchlist']); + $routes->createNewRoute('GET', '/movies/{id:[0-9]+}/add-watchlist', [Web\Movie\MovieWatchlistController::class, 'addToWatchlist'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/movies/{id:[0-9]+}/remove-watchlist', [Web\Movie\MovieWatchlistController::class, 'removeFromWatchlist'])->addMiddleware(Middleware\isAuthenticated::class); ############## # User media # ############## - $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/dashboard', [Web\DashboardController::class, 'render']); + $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/dashboard', [Web\DashboardController::class, 'render'])->addMiddleware(Middleware\CanUserBeViewed::class); $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/history', [Web\HistoryController::class, 'renderHistory']); $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/watchlist', [Web\WatchlistController::class, 'renderWatchlist']); $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/movies', [Web\MoviesController::class, 'renderPage']); @@ -133,12 +133,12 @@ function addWebRoutes(FastRoute\RouteCollector $routeCollector) : void $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/directors', [Web\DirectorsController::class, 'renderPage']); $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}', [Web\Movie\MovieController::class, 'renderPage']); $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/persons/{id:\d+}', [Web\PersonController::class, 'renderPage']); - $routes->createNewRoute('DELETE', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}/history', [Web\HistoryController::class, 'deleteHistoryEntry']); - $routes->createNewRoute('POST', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}/history', [Web\HistoryController::class, 'createHistoryEntry']); - $routes->createNewRoute('POST', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}/rating', [Web\Movie\MovieRatingController::class, 'updateRating']); - $routes->createNewRoute('POST', '/log-movie', [Web\HistoryController::class, 'logMovie']); - $routes->createNewRoute('POST', '/add-movie-to-watchlist', [Web\WatchlistController::class, 'addMovieToWatchlist']); - $routes->createNewRoute('GET', '/fetchMovieRatingByTmdbdId', [Web\Movie\MovieRatingController::class, 'fetchMovieRatingByTmdbdId']); + $routes->createNewRoute('DELETE', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}/history', [Web\HistoryController::class, 'deleteHistoryEntry'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}/history', [Web\HistoryController::class, 'createHistoryEntry'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}/rating', [Web\Movie\MovieRatingController::class, 'updateRating'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/log-movie', [Web\HistoryController::class, 'logMovie'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('POST', '/add-movie-to-watchlist', [Web\WatchlistController::class, 'addMovieToWatchlist'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->createNewRoute('GET', '/fetchMovieRatingByTmdbdId', [Web\Movie\MovieRatingController::class, 'fetchMovieRatingByTmdbdId'])->addMiddleware(Middleware\isAuthenticated::class); $routerService->generateRouteCallback($routeCollector, $routes); } @@ -146,7 +146,7 @@ function addApiRoutes(FastRoute\RouteCollector $routeCollector) : void { $routerService = new RouterService(); $routes = $routerService->createRouteList(); - $routes->createNewRoute('GET', '/openapi.jsn', [Api\OpenApiController::class, 'getSchema']); + $routes->createNewRoute('GET', '/openapi.json', [Api\OpenApiController::class, 'getSchema']); $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/history', [Api\HistoryController::class, 'getHistory']); $routerService->generateRouteCallback($routeCollector, $routes); } \ No newline at end of file diff --git a/src/HttpController/Middleware/CanUserBeViewed.php b/src/HttpController/Middleware/CanUserBeViewed.php new file mode 100644 index 00000000..7f77fc25 --- /dev/null +++ b/src/HttpController/Middleware/CanUserBeViewed.php @@ -0,0 +1,24 @@ +userPageAuthorizationChecker->findUserIdIfCurrentVisitorIsAllowedToSeeUser((string)$request->getRouteParameters()['username']); + if ($userId === null) { + return Response::createSeeOther('/'); + } + return null; + } +} \ No newline at end of file diff --git a/src/HttpController/Middleware/IsAdmin.php b/src/HttpController/Middleware/IsAdmin.php index 93ddaf0f..e5153c37 100644 --- a/src/HttpController/Middleware/IsAdmin.php +++ b/src/HttpController/Middleware/IsAdmin.php @@ -5,7 +5,7 @@ use Movary\Domain\User\Service\Authentication; use Movary\ValueObject\Http\Response; -class HasUsersCheck +class IsAdmin { public function __construct( private readonly Authentication $authenticationService diff --git a/src/HttpController/Web/DashboardController.php b/src/HttpController/Web/DashboardController.php index 746d0358..c6b6437b 100644 --- a/src/HttpController/Web/DashboardController.php +++ b/src/HttpController/Web/DashboardController.php @@ -40,10 +40,6 @@ public function redirectToDashboard(Request $request) : Response public function render(Request $request) : Response { $userId = $this->userPageAuthorizationChecker->findUserIdIfCurrentVisitorIsAllowedToSeeUser((string)$request->getRouteParameters()['username']); - if ($userId === null) { - return Response::createSeeOther('/'); - } - $dashboardRows = $this->dashboardFactory->createDashboardRowsForUser($this->userApi->fetchUser($userId)); return Response::create( diff --git a/src/HttpController/Web/EmbyController.php b/src/HttpController/Web/EmbyController.php index 96d41ed5..7abd4547 100644 --- a/src/HttpController/Web/EmbyController.php +++ b/src/HttpController/Web/EmbyController.php @@ -24,10 +24,6 @@ public function __construct( public function deleteEmbyWebhookUrl() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $this->userApi->deleteEmbyWebhookId($this->authenticationService->getCurrentUserId()); return Response::createOk(); @@ -53,10 +49,6 @@ public function handleEmbyWebhook(Request $request) : Response public function regenerateEmbyWebhookUrl() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $webhookId = $this->userApi->regenerateEmbyWebhookId($this->authenticationService->getCurrentUserId()); return Response::createJson(Json::encode(['url' => $this->webhookUrlBuilder->buildEmbyWebhookUrl($webhookId)])); diff --git a/src/HttpController/Web/ExportController.php b/src/HttpController/Web/ExportController.php index ee0eadba..7b5581e4 100644 --- a/src/HttpController/Web/ExportController.php +++ b/src/HttpController/Web/ExportController.php @@ -19,10 +19,6 @@ public function __construct( public function getCsvExport(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/login'); - } - $userId = $this->authenticationService->getCurrentUserId(); $exportType = $request->getRouteParameters()['exportType'] ?? null; diff --git a/src/HttpController/Web/HistoryController.php b/src/HttpController/Web/HistoryController.php index 1aa68092..f167d232 100644 --- a/src/HttpController/Web/HistoryController.php +++ b/src/HttpController/Web/HistoryController.php @@ -36,10 +36,6 @@ public function __construct( public function createHistoryEntry(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createForbidden(); - } - $userId = $this->authenticationService->getCurrentUserId(); if ($this->userApi->fetchUser($userId)->getName() !== $request->getRouteParameters()['username']) { @@ -61,10 +57,6 @@ public function createHistoryEntry(Request $request) : Response public function deleteHistoryEntry(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createForbidden(); - } - $userId = $this->authenticationService->getCurrentUserId(); if ($this->userApi->fetchUser($userId)->getName() !== $request->getRouteParameters()['username']) { @@ -83,10 +75,6 @@ public function deleteHistoryEntry(Request $request) : Response public function logMovie(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $userId = $this->authenticationService->getCurrentUserId(); $requestData = Json::decode($request->getBody()); @@ -116,9 +104,7 @@ public function logMovie(Request $request) : Response public function renderHistory(Request $request) : Response { $userId = $this->userPageAuthorizationChecker->findUserIdIfCurrentVisitorIsAllowedToSeeUser((string)$request->getRouteParameters()['username']); - if ($userId === null) { - return Response::createNotFound(); - } + $searchTerm = $request->getGetParameters()['s'] ?? null; $page = $request->getGetParameters()['p'] ?? 1; diff --git a/src/HttpController/Web/ImportController.php b/src/HttpController/Web/ImportController.php index 79c07b0a..ed59cb2d 100644 --- a/src/HttpController/Web/ImportController.php +++ b/src/HttpController/Web/ImportController.php @@ -25,10 +25,6 @@ public function __construct( public function handleCsvImport(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/login'); - } - $userId = $this->authenticationService->getCurrentUserId(); $exportType = $request->getRouteParameters()['exportType']; $fileParameters = $request->getFileParameters(); diff --git a/src/HttpController/Web/JellyfinController.php b/src/HttpController/Web/JellyfinController.php index 93508de0..dde92211 100644 --- a/src/HttpController/Web/JellyfinController.php +++ b/src/HttpController/Web/JellyfinController.php @@ -33,10 +33,6 @@ public function __construct( public function authenticateJellyfinAccount(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $userId = $this->authenticationService->getCurrentUserId(); $username = Json::decode($request->getBody())['username']; @@ -65,10 +61,6 @@ public function authenticateJellyfinAccount(Request $request) : Response public function deleteJellyfinWebhookUrl() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $this->userApi->deleteJellyfinWebhookId($this->authenticationService->getCurrentUserId()); return Response::createOk(); @@ -94,10 +86,6 @@ public function handleJellyfinWebhook(Request $request) : Response public function regenerateJellyfinWebhookUrl() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $webhookId = $this->userApi->regenerateJellyfinWebhookId($this->authenticationService->getCurrentUserId()); return Response::createJson(Json::encode(['url' => $this->webhookUrlBuilder->buildJellyfinWebhookUrl($webhookId)])); @@ -105,10 +93,6 @@ public function regenerateJellyfinWebhookUrl() : Response public function removeJellyfinAuthentication() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $userId = $this->authenticationService->getCurrentUserId(); $jellyfinAuthentication = $this->userApi->findJellyfinAuthentication($userId); @@ -131,10 +115,6 @@ public function removeJellyfinAuthentication() : Response public function saveJellyfinServerUrl(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $jellyfinServerUrl = Json::decode($request->getBody())['JellyfinServerUrl']; $userId = $this->authenticationService->getCurrentUserId(); @@ -157,10 +137,6 @@ public function saveJellyfinServerUrl(Request $request) : Response public function saveJellyfinSyncOptions(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $syncWatches = Json::decode($request->getBody())['syncWatches']; $userId = $this->authenticationService->getCurrentUserId(); @@ -171,10 +147,6 @@ public function saveJellyfinSyncOptions(Request $request) : Response public function verifyJellyfinServerUrl(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $jellyfinServerUrl = Url::createFromString(Json::decode($request->getBody())['jellyfinServerUrl']); $jellyfinAuthentication = $this->userApi->findJellyfinAuthentication($this->authenticationService->getCurrentUserId()); diff --git a/src/HttpController/Web/Movie/MovieController.php b/src/HttpController/Web/Movie/MovieController.php index 349e47f6..2c6d153c 100644 --- a/src/HttpController/Web/Movie/MovieController.php +++ b/src/HttpController/Web/Movie/MovieController.php @@ -30,10 +30,6 @@ public function __construct( public function refreshImdbRating(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createForbidden(); - } - $movieId = (int)$request->getRouteParameters()['id']; $movie = $this->movieApi->findByIdFormatted($movieId); @@ -48,10 +44,6 @@ public function refreshImdbRating(Request $request) : Response public function refreshTmdbData(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createForbidden(); - } - $movieId = (int)$request->getRouteParameters()['id']; $movie = $this->movieApi->findByIdFormatted($movieId); diff --git a/src/HttpController/Web/Movie/MovieRatingController.php b/src/HttpController/Web/Movie/MovieRatingController.php index c9870e0e..8bd1a1ac 100644 --- a/src/HttpController/Web/Movie/MovieRatingController.php +++ b/src/HttpController/Web/Movie/MovieRatingController.php @@ -22,10 +22,6 @@ public function __construct( public function fetchMovieRatingByTmdbdId(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $userId = $this->authenticationService->getCurrentUserId(); $tmdbId = $request->getGetParameters()['tmdbId'] ?? null; @@ -43,10 +39,6 @@ public function fetchMovieRatingByTmdbdId(Request $request) : Response public function updateRating(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createForbidden(); - } - $userId = $this->authenticationService->getCurrentUserId(); if ($this->userApi->fetchUser($userId)->getName() !== $request->getRouteParameters()['username']) { diff --git a/src/HttpController/Web/Movie/MovieWatchlistController.php b/src/HttpController/Web/Movie/MovieWatchlistController.php index 0e9e2dbd..f2522e04 100644 --- a/src/HttpController/Web/Movie/MovieWatchlistController.php +++ b/src/HttpController/Web/Movie/MovieWatchlistController.php @@ -17,10 +17,6 @@ public function __construct( public function addToWatchlist(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createForbidden(); - } - $movieId = (int)$request->getRouteParameters()['id']; $userId = $this->authenticationService->getCurrentUser()->getId(); @@ -31,10 +27,6 @@ public function addToWatchlist(Request $request) : Response public function removeFromWatchlist(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createForbidden(); - } - $movieId = (int)$request->getRouteParameters()['id']; $userId = $this->authenticationService->getCurrentUser()->getId(); diff --git a/src/HttpController/Web/NetflixController.php b/src/HttpController/Web/NetflixController.php index 81074f56..808159a6 100644 --- a/src/HttpController/Web/NetflixController.php +++ b/src/HttpController/Web/NetflixController.php @@ -25,10 +25,6 @@ public function __construct( public function importNetflixData(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $userId = $this->authenticationService->getCurrentUserId(); $items = Json::decode($request->getBody()); @@ -43,10 +39,6 @@ public function importNetflixData(Request $request) : Response */ public function matchNetflixActivityCsvWithTmdbMovies(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $files = $request->getFileParameters(); $postParameters = $request->getPostParameters(); if (empty($files['netflixActivityCsv']) === true || empty($postParameters['netflixActivityCsvDateFormat']) === true) { @@ -74,10 +66,6 @@ public function matchNetflixActivityCsvWithTmdbMovies(Request $request) : Respon public function searchTmbd(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $input = Json::decode($request->getBody()); $tmdbSearchResult = $this->tmdbApi->searchMovie($input['query']); diff --git a/src/HttpController/Web/PlexController.php b/src/HttpController/Web/PlexController.php index e5591a4b..001db998 100644 --- a/src/HttpController/Web/PlexController.php +++ b/src/HttpController/Web/PlexController.php @@ -32,10 +32,6 @@ public function __construct( public function deletePlexWebhookUrl() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $this->userApi->deletePlexWebhookId($this->authenticationService->getCurrentUserId()); return Response::createOk(); @@ -43,10 +39,6 @@ public function deletePlexWebhookUrl() : Response public function generatePlexAuthenticationUrl() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createForbidden(); - } - $plexAccessToken = $this->userApi->findPlexAccessToken($this->authenticationService->getCurrentUserId()); if ($plexAccessToken !== null) { return Response::createBadRequest('User is already authenticated'); @@ -84,10 +76,6 @@ public function handlePlexWebhook(Request $request) : Response public function processPlexCallback() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createForbidden(); - } - $plexClientId = $this->userApi->findPlexClientId($this->authenticationService->getCurrentUserId()); $plexClientCode = $this->userApi->findTemporaryPlexCode($this->authenticationService->getCurrentUserId()); if ($plexClientId === null || $plexClientCode === null) { @@ -112,10 +100,6 @@ public function processPlexCallback() : Response public function regeneratePlexWebhookUrl() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $webhookId = $this->userApi->regeneratePlexWebhookId($this->authenticationService->getCurrentUserId()); return Response::createJson(Json::encode(['url' => $this->webhookUrlBuilder->buildPlexWebhookUrl($webhookId)])); @@ -123,10 +107,6 @@ public function regeneratePlexWebhookUrl() : Response public function removePlexAccessTokens() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $userId = $this->authenticationService->getCurrentUserId(); $this->userApi->updatePlexAccessToken($userId, null); @@ -139,10 +119,6 @@ public function removePlexAccessTokens() : Response public function savePlexServerUrl(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $userId = $this->authenticationService->getCurrentUserId(); $plexServerUrl = Json::decode($request->getBody())['plexServerUrl']; @@ -165,10 +141,6 @@ public function savePlexServerUrl(Request $request) : Response public function verifyPlexServerUrl(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $plexAccessToken = $this->authenticationService->getCurrentUser()->getPlexAccessToken(); if ($plexAccessToken === null) { return Response::createBadRequest('Plex authentication is missing'); diff --git a/src/HttpController/Web/SettingsController.php b/src/HttpController/Web/SettingsController.php index 01addd3c..01db7f3e 100644 --- a/src/HttpController/Web/SettingsController.php +++ b/src/HttpController/Web/SettingsController.php @@ -57,10 +57,6 @@ public function __construct( public function deleteAccount() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $userId = $this->authenticationService->getCurrentUserId(); $user = $this->userApi->fetchUser($userId); @@ -83,10 +79,6 @@ public function deleteAccount() : Response public function deleteApiToken() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $this->userApi->deleteApiToken($this->authenticationService->getCurrentUserId()); return Response::createOk(); @@ -94,10 +86,6 @@ public function deleteApiToken() : Response public function deleteHistory() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $this->movieApi->deleteHistoryByUserId($this->authenticationService->getCurrentUserId()); $this->sessionWrapper->set('deletedUserHistory', true); @@ -111,10 +99,6 @@ public function deleteHistory() : Response public function deleteRatings() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $this->movieApi->deleteRatingsByUserId($this->authenticationService->getCurrentUserId()); $this->sessionWrapper->set('deletedUserRatings', true); @@ -128,10 +112,6 @@ public function deleteRatings() : Response public function generateLetterboxdExportData() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $userId = $this->authenticationService->getCurrentUserId(); $options = new ZipStream\Option\Archive(); @@ -152,10 +132,6 @@ public function generateLetterboxdExportData() : Response public function getApiToken() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $userId = $this->authenticationService->getCurrentUserId(); return Response::createJson(Json::encode(['token' => $this->userApi->findApiTokenByUserId($userId)])); @@ -163,10 +139,6 @@ public function getApiToken() : Response public function regenerateApiToken() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $userId = $this->authenticationService->getCurrentUserId(); $this->userApi->deleteApiToken($userId); @@ -177,10 +149,6 @@ public function regenerateApiToken() : Response public function renderAppPage() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - return Response::create( StatusCode::createOk(), $this->twig->render('page/settings-app.html.twig', [ @@ -193,10 +161,6 @@ public function renderAppPage() : Response public function renderDashboardAccountPage() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $user = $this->authenticationService->getCurrentUser(); $dashboardRows = $this->dashboardFactory->createDashboardRowsForUser($user); @@ -215,10 +179,6 @@ public function renderDashboardAccountPage() : Response public function renderDataAccountPage() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $userId = $this->authenticationService->getCurrentUserId(); $importHistorySuccessful = $this->sessionWrapper->find('importHistorySuccessful'); @@ -255,10 +215,6 @@ public function renderDataAccountPage() : Response public function renderEmbyPage() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $user = $this->userApi->fetchUser($this->authenticationService->getCurrentUserId()); $applicationUrl = $this->serverSettings->getApplicationUrl(); @@ -280,10 +236,6 @@ public function renderEmbyPage() : Response public function renderGeneralAccountPage() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $user = $this->authenticationService->getCurrentUser(); return Response::create( @@ -304,10 +256,6 @@ public function renderGeneralAccountPage() : Response public function renderJellyfinPage() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $user = $this->userApi->fetchUser($this->authenticationService->getCurrentUserId()); $applicationUrl = $this->serverSettings->getApplicationUrl(); @@ -343,10 +291,6 @@ public function renderJellyfinPage() : Response public function renderLetterboxdPage() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $user = $this->userApi->fetchUser($this->authenticationService->getCurrentUserId()); $letterboxdDiarySyncSuccessful = $this->sessionWrapper->find('letterboxdDiarySyncSuccessful'); @@ -375,10 +319,6 @@ public function renderLetterboxdPage() : Response public function renderNetflixPage() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - return Response::create( StatusCode::createOk(), $this->twig->render('page/settings-integration-netflix.html.twig'), @@ -387,10 +327,6 @@ public function renderNetflixPage() : Response public function renderPlexPage() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $plexAccessToken = null; $plexIdentifier = $this->serverSettings->getPlexIdentifier(); @@ -433,10 +369,6 @@ public function renderPlexPage() : Response public function renderSecurityAccountPage() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $user = $this->authenticationService->getCurrentUser(); $totpEnabled = $this->twoFactorAuthenticationService->findTotpUri($user->getId()) === null ? false : true; @@ -462,14 +394,6 @@ public function renderSecurityAccountPage() : Response public function renderServerEmailPage() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - - if ($this->authenticationService->getCurrentUser()->isAdmin() === false) { - return Response::createSeeOther('/'); - } - return Response::create( StatusCode::createOk(), $this->twig->render('page/settings-server-email.html.twig', [ @@ -493,10 +417,6 @@ public function renderServerEmailPage() : Response public function renderServerGeneralPage() : Response { - if ($this->authenticationService->getCurrentUser()->isAdmin() === false) { - return Response::createSeeOther('/'); - } - return Response::create( StatusCode::createOk(), $this->twig->render('page/settings-server-general.html.twig', [ @@ -510,14 +430,6 @@ public function renderServerGeneralPage() : Response public function renderServerJobsPage(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - - if ($this->authenticationService->getCurrentUser()->isAdmin() === false) { - return Response::createSeeOther('/'); - } - $jobsPerPage = $request->getGetParameters()['jpp'] ?? 30; $jobs = $this->jobQueueApi->fetchJobsForStatusPage((int)$jobsPerPage); @@ -533,14 +445,6 @@ public function renderServerJobsPage(Request $request) : Response public function renderServerUsersPage() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - - if ($this->authenticationService->getCurrentUser()->isAdmin() === false) { - return Response::createSeeOther('/'); - } - return Response::create( StatusCode::createOk(), $this->twig->render('page/settings-server-users.html.twig'), @@ -549,10 +453,6 @@ public function renderServerUsersPage() : Response public function renderTraktPage() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $traktCredentialsUpdated = $this->sessionWrapper->find('traktCredentialsUpdated'); $scheduledTraktHistoryImport = $this->sessionWrapper->find('scheduledTraktHistoryImport'); $scheduledTraktRatingsImport = $this->sessionWrapper->find('scheduledTraktRatingsImport'); @@ -576,10 +476,6 @@ public function renderTraktPage() : Response public function resetDashboardRows() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $userId = $this->authenticationService->getCurrentUserId(); $this->userApi->updateVisibleDashboardRows($userId, null); @@ -593,14 +489,6 @@ public function resetDashboardRows() : Response public function sendTestEmail(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - - if ($this->authenticationService->getCurrentUser()->isAdmin() === false) { - return Response::createSeeOther('/'); - } - $requestData = Json::decode($request->getBody()); $smtpConfig = SmtpConfig::create( @@ -629,10 +517,6 @@ public function sendTestEmail(Request $request) : Response public function traktVerifyCredentials(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $requestData = Json::decode($request->getBody()); $clientId = $requestData['clientId'] ?? ''; @@ -647,10 +531,6 @@ public function traktVerifyCredentials(Request $request) : Response public function updateDashboardRows(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $userId = $this->authenticationService->getCurrentUserId(); $bodyData = Json::decode($request->getBody()); @@ -671,10 +551,6 @@ public function updateDashboardRows(Request $request) : Response public function updateEmby(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $userId = $this->authenticationService->getCurrentUserId(); $postParameters = Json::decode($request->getBody()); @@ -688,10 +564,6 @@ public function updateEmby(Request $request) : Response public function updateGeneral(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $requestData = Json::decode($request->getBody()); $privacyLevel = isset($requestData['privacyLevel']) === false ? 1 : (int)$requestData['privacyLevel']; @@ -717,10 +589,6 @@ public function updateGeneral(Request $request) : Response public function updateJellyfin(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $userId = $this->authenticationService->getCurrentUserId(); $postParameters = Json::decode($request->getBody()); @@ -734,10 +602,6 @@ public function updateJellyfin(Request $request) : Response public function updatePassword(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $userId = $this->authenticationService->getCurrentUserId(); $user = $this->userApi->fetchUser($userId); @@ -765,10 +629,6 @@ public function updatePassword(Request $request) : Response public function updatePlex(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $userId = $this->authenticationService->getCurrentUserId(); $postParameters = Json::decode($request->getBody()); @@ -783,14 +643,6 @@ public function updatePlex(Request $request) : Response // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh public function updateServerEmail(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - - if ($this->authenticationService->getCurrentUser()->isAdmin() === false) { - return Response::createForbidden(); - } - $requestData = Json::decode($request->getBody()); $smtpHost = isset($requestData['smtpHost']) === false ? null : $requestData['smtpHost']; @@ -828,14 +680,6 @@ public function updateServerEmail(Request $request) : Response public function updateServerGeneral(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - - if ($this->authenticationService->getCurrentUser()->isAdmin() === false) { - return Response::createForbidden(); - } - $requestData = Json::decode($request->getBody()); $tmdbApiKey = isset($requestData['tmdbApiKey']) === false ? null : $requestData['tmdbApiKey']; @@ -853,10 +697,6 @@ public function updateServerGeneral(Request $request) : Response public function updateTrakt(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $userId = $this->authenticationService->getCurrentUserId(); $postParameters = $request->getPostParameters(); diff --git a/src/HttpController/Web/TwoFactorAuthenticationController.php b/src/HttpController/Web/TwoFactorAuthenticationController.php index 16831692..0fa6a0ad 100644 --- a/src/HttpController/Web/TwoFactorAuthenticationController.php +++ b/src/HttpController/Web/TwoFactorAuthenticationController.php @@ -24,10 +24,6 @@ public function __construct( public function createTotpUri() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $currentUserName = $this->authenticationService->getCurrentUser()->getName(); $totp = $this->twoFactorAuthenticationFactory->createTotp($currentUserName); @@ -41,10 +37,6 @@ public function createTotpUri() : Response public function disableTOTP() : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $this->twoFactorAuthenticationApi->deleteTotp($this->authenticationService->getCurrentUserId()); $this->sessionWrapper->set('twoFactorAuthenticationDisabled', true); @@ -53,10 +45,6 @@ public function disableTOTP() : Response public function enableTOTP(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $userId = $this->authenticationService->getCurrentUserId(); $requestData = Json::decode($request->getBody()); diff --git a/src/HttpController/Web/UserController.php b/src/HttpController/Web/UserController.php index 9c677cc0..79c15f5c 100644 --- a/src/HttpController/Web/UserController.php +++ b/src/HttpController/Web/UserController.php @@ -51,10 +51,6 @@ public function createUser(Request $request) : Response public function deleteUser(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $userId = (int)$request->getRouteParameters()['userId']; $currentUser = $this->authenticationService->getCurrentUser(); @@ -79,10 +75,6 @@ public function fetchUsers() : Response public function updateUser(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createForbidden(); - } - $userId = (int)$request->getRouteParameters()['userId']; $currentUser = $this->authenticationService->getCurrentUser(); diff --git a/src/HttpController/Web/WatchlistController.php b/src/HttpController/Web/WatchlistController.php index 10346681..df62d92d 100644 --- a/src/HttpController/Web/WatchlistController.php +++ b/src/HttpController/Web/WatchlistController.php @@ -32,10 +32,6 @@ public function __construct( public function addMovieToWatchlist(Request $request) : Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther('/'); - } - $userId = $this->authenticationService->getCurrentUserId(); $requestData = Json::decode($request->getBody()); From d8552e24e9f0389060e4c5fa6d1e4476ca70c35e Mon Sep 17 00:00:00 2001 From: JVT038 <47184046+JVT038@users.noreply.github.com> Date: Mon, 4 Sep 2023 17:35:25 +0200 Subject: [PATCH 05/11] Remove unnecessary methods --- src/Service/Router/Dto/RouteList.php | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/Service/Router/Dto/RouteList.php b/src/Service/Router/Dto/RouteList.php index 4c24195f..c428537c 100644 --- a/src/Service/Router/Dto/RouteList.php +++ b/src/Service/Router/Dto/RouteList.php @@ -12,17 +12,6 @@ public static function create() : self return new self(); } - public function addRoute(Route $route) : Route - { - $this->data[] = $route; - return end($this->data); - } - - public function addRoutes(...$routes) : void - { - $this->data = array_merge($this->data, $routes); - } - public function createNewRoute(string $httpMethod, string $route, array $handler) : Route { $route = Route::create($httpMethod, $route, $handler); From d4a9d5325e53cfed1c67c431b90ab6eeaac91601 Mon Sep 17 00:00:00 2001 From: Lee Peuker Date: Wed, 6 Sep 2023 21:18:51 +0200 Subject: [PATCH 06/11] Some refactoring and reformating --- bootstrap.php | 2 +- settings/routes.php | 259 ++++++++++-------- src/Factory.php | 10 +- .../Middleware/RegistrationEnabledCheck.php | 20 -- .../Web/CreateUserController.php | 1 - src/HttpController/Web/HistoryController.php | 1 - src/HttpController/Web/JobController.php | 1 - .../Web/LandingPageController.php | 12 - .../Middleware/ServerHasNoUsers.php} | 12 +- .../ServerHasRegistrationEnabled.php | 22 ++ .../Middleware/ServerHasUsers.php} | 12 +- .../Middleware/UserCanViewUser.php} | 13 +- .../Middleware/UserHasJellyfinToken.php} | 12 +- .../Middleware/UserHasPlexAccessToken.php} | 12 +- .../Middleware/UserIsAdmin.php} | 12 +- .../Middleware/UserIsAuthenticated.php} | 10 +- .../Middleware/UserIsUnauthenticated.php} | 13 +- .../Web/Movie/MovieController.php | 1 - src/Service/Router/Dto/Route.php | 30 +- src/Service/Router/Dto/RouteList.php | 19 +- src/Service/Router/RouterService.php | 16 +- 21 files changed, 247 insertions(+), 243 deletions(-) delete mode 100644 src/HttpController/Middleware/RegistrationEnabledCheck.php rename src/HttpController/{Middleware/DoesNotHaveUsers.php => Web/Middleware/ServerHasNoUsers.php} (71%) create mode 100644 src/HttpController/Web/Middleware/ServerHasRegistrationEnabled.php rename src/HttpController/{Middleware/HasUsersCheck.php => Web/Middleware/ServerHasUsers.php} (71%) rename src/HttpController/{Middleware/CanUserBeViewed.php => Web/Middleware/UserCanViewUser.php} (82%) rename src/HttpController/{Middleware/HasJellyfinToken.php => Web/Middleware/UserHasJellyfinToken.php} (83%) rename src/HttpController/{Middleware/HasPlexAccessToken.php => Web/Middleware/UserHasPlexAccessToken.php} (75%) rename src/HttpController/{Middleware/IsAdmin.php => Web/Middleware/UserIsAdmin.php} (71%) rename src/HttpController/{Middleware/isAuthenticated.php => Web/Middleware/UserIsAuthenticated.php} (82%) rename src/HttpController/{Middleware/isUnauthenticated.php => Web/Middleware/UserIsUnauthenticated.php} (74%) diff --git a/bootstrap.php b/bootstrap.php index 1585c1c6..7d566b97 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -19,7 +19,7 @@ \Movary\HttpController\Web\JobController::class => DI\factory([Factory::class, 'createJobController']), \Movary\HttpController\Web\LandingPageController::class => DI\factory([Factory::class, 'createLandingPageController']), \Movary\HttpController\Web\SettingsController::class => DI\factory([Factory::class, 'createSettingsController']), - \Movary\HttpController\Middleware\RegistrationEnabledCheck::class => DI\factory([Factory::class, 'createRegistrationEnabledCheck']), + \Movary\HttpController\Web\Middleware\ServerHasRegistrationEnabled::class => DI\factory([Factory::class, 'createRegistrationEnabledCheck']), \Movary\ValueObject\Http\Request::class => DI\factory([Factory::class, 'createCurrentHttpRequest']), \Movary\Command\CreatePublicStorageLink::class => DI\factory([Factory::class, 'createCreatePublicStorageLink']), \Movary\Command\DatabaseMigrationStatus::class => DI\factory([Factory::class, 'createDatabaseMigrationStatusCommand']), diff --git a/settings/routes.php b/settings/routes.php index d3523a45..efb78e52 100644 --- a/settings/routes.php +++ b/settings/routes.php @@ -1,153 +1,174 @@ addGroup('', fn($routeCollector) => addWebRoutes($routeCollector)); - $routeCollector->addGroup('/api', fn($routeCollector) => addApiRoutes($routeCollector)); + $routerService = new RouterService(); + + $routeCollector->addGroup('', fn($routeCollector) => addWebRoutes($routerService, $routeCollector)); + $routeCollector->addGroup('/api', fn($routeCollector) => addApiRoutes($routerService, $routeCollector)); }; -function addWebRoutes(FastRoute\RouteCollector $routeCollector) : void +function addWebRoutes(RouterService $routerService, FastRoute\RouteCollector $routeCollector) : void { - $routerService = new RouterService(); - $routes = $routerService->createRouteList(); - $routes->createNewRoute('GET', '/', [Web\LandingPageController::class, 'render'])->addMiddleware(Middleware\isUnauthenticated::class, Middleware\DoesNotHaveUsers::class); - $routes->createNewRoute('GET', '/login', [Web\AuthenticationController::class, 'renderLoginPage'])->addMiddleware(Middleware\isUnauthenticated::class); - $routes->createNewRoute('POST', '/login', [Web\AuthenticationController::class, 'login']); - $routes->createNewRoute('POST', '/verify-totp', [Web\TwoFactorAuthenticationController::class, 'verifyTotp'])->addMiddleware(Middleware\isUnauthenticated::class); - $routes->createNewRoute('GET', '/logout', [Web\AuthenticationController::class, 'logout']); - $routes->createNewRoute('POST', '/create-user', [Web\CreateUserController::class, 'createUser'])->addMiddleware(Middleware\isUnauthenticated::class, Middleware\HasUsersCheck::class, Middleware\RegistrationEnabledCheck::class); - $routes->createNewRoute('GET', '/create-user', [Web\CreateUserController::class, 'renderPage'])->addMiddleware(Middleware\isUnauthenticated::class, Middleware\HasUsersCheck::class, Middleware\RegistrationEnabledCheck::class); - $routes->createNewRoute('GET', '/docs/api', [Web\OpenApiController::class, 'renderPage']); + $routes = RouteList::create(); + + $routes->add('GET', '/', [Web\LandingPageController::class, 'render'], [Web\Middleware\UserIsUnauthenticated::class, Web\Middleware\ServerHasNoUsers::class]); + $routes->add('GET', '/login', [Web\AuthenticationController::class, 'renderLoginPage'], [Web\Middleware\UserIsUnauthenticated::class]); + $routes->add('POST', '/login', [Web\AuthenticationController::class, 'login']); + $routes->add('POST', '/verify-totp', [Web\TwoFactorAuthenticationController::class, 'verifyTotp'], [Web\Middleware\UserIsUnauthenticated::class]); + $routes->add('GET', '/logout', [Web\AuthenticationController::class, 'logout']); + $routes->add('POST', '/create-user', [Web\CreateUserController::class, 'createUser'], [ + Web\Middleware\UserIsUnauthenticated::class, + Web\Middleware\ServerHasUsers::class, + Web\Middleware\ServerHasRegistrationEnabled::class + ]); + $routes->add('GET', '/create-user', [Web\CreateUserController::class, 'renderPage'], [ + Web\Middleware\UserIsUnauthenticated::class, + Web\Middleware\ServerHasUsers::class, + Web\Middleware\ServerHasRegistrationEnabled::class + ]); + $routes->add('GET', '/docs/api', [Web\OpenApiController::class, 'renderPage']); ##################### # Webhook listeners # ##################### - $routes->createNewRoute('POST', '/plex/{id:.+}', [Web\PlexController::class, 'handlePlexWebhook']); - $routes->createNewRoute('POST', '/jellyfin/{id:.+}', [Web\JellyfinController::class, 'handleJellyfinWebhook']); - $routes->createNewRoute('POST', '/emby/{id:.+}', [Web\EmbyController::class, 'handleEmbyWebhook']); + $routes->add('POST', '/plex/{id:.+}', [Web\PlexController::class, 'handlePlexWebhook']); + $routes->add('POST', '/jellyfin/{id:.+}', [Web\JellyfinController::class, 'handleJellyfinWebhook']); + $routes->add('POST', '/emby/{id:.+}', [Web\EmbyController::class, 'handleEmbyWebhook']); ############# # Job Queue # ############# - $routes->createNewRoute('GET', '/jobs', [Web\JobController::class, 'getJobs'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/job-queue/purge-processed', [Web\JobController::class, 'purgeProcessedJobs'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/job-queue/purge-all', [Web\JobController::class, 'purgeAllJobs'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/jobs/schedule/trakt-history-sync', [Web\JobController::class, 'scheduleTraktHistorySync'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/jobs/schedule/trakt-ratings-sync', [Web\JobController::class, 'scheduleTraktRatingsSync'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/jobs/schedule/letterboxd-diary-sync', [Web\JobController::class, 'scheduleLetterboxdDiaryImport'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/jobs/schedule/letterboxd-ratings-sync', [Web\JobController::class, 'scheduleLetterboxdRatingsImport'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/jobs/schedule/plex-watchlist-sync', [Web\JobController::class, 'schedulePlexWatchlistImport'])->addMiddleware(Middleware\isAuthenticated::class, Middleware\HasPlexAccessToken::class); - $routes->createNewRoute('GET', '/jobs/schedule/jellyfin-import-history', [Web\JobController::class, 'scheduleJellyfinImportHistory'])->addMiddleware(Middleware\isAuthenticated::class, Middleware\HasJellyfinToken::class); - $routes->createNewRoute('GET', '/jobs/schedule/jellyfin-export-history', [Web\JobController::class, 'scheduleJellyfinExportHistory'])->addMiddleware(Middleware\isAuthenticated::class, Middleware\HasJellyfinToken::class); + $routes->add('GET', '/jobs', [Web\JobController::class, 'getJobs'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/job-queue/purge-processed', [Web\JobController::class, 'purgeProcessedJobs'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/job-queue/purge-all', [Web\JobController::class, 'purgeAllJobs'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/jobs/schedule/trakt-history-sync', [Web\JobController::class, 'scheduleTraktHistorySync'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/jobs/schedule/trakt-ratings-sync', [Web\JobController::class, 'scheduleTraktRatingsSync'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/jobs/schedule/letterboxd-diary-sync', [Web\JobController::class, 'scheduleLetterboxdDiaryImport'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/jobs/schedule/letterboxd-ratings-sync', [Web\JobController::class, 'scheduleLetterboxdRatingsImport'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/jobs/schedule/plex-watchlist-sync', [Web\JobController::class, 'schedulePlexWatchlistImport'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/jobs/schedule/jellyfin-import-history', [Web\JobController::class, 'scheduleJellyfinImportHistory'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/jobs/schedule/jellyfin-export-history', [Web\JobController::class, 'scheduleJellyfinExportHistory'], [ + Web\Middleware\UserIsAuthenticated::class, + Web\Middleware\UserHasJellyfinToken::class + ]); ############ # Settings # ############ - $routes->createNewRoute('GET', '/settings/account/general', [Web\SettingsController::class, 'renderGeneralAccountPage'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/settings/account/general/api-token', [Web\SettingsController::class, 'getApiToken'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('DELETE', '/settings/account/general/api-token', [Web\SettingsController::class, 'deleteApiToken'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('PUT', '/settings/account/general/api-token', [Web\SettingsController::class, 'regenerateApiToken'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/settings/account/dashboard', [Web\SettingsController::class, 'renderDashboardAccountPage'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/settings/account/security', [Web\SettingsController::class, 'renderSecurityAccountPage'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/settings/account/data', [Web\SettingsController::class, 'renderDataAccountPage'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/settings/server/general', [Web\SettingsController::class, 'renderServerGeneralPage'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/settings/server/jobs', [Web\SettingsController::class, 'renderServerJobsPage'])->addMiddleware(Middleware\isAuthenticated::class, Middleware\IsAdmin::class); - $routes->createNewRoute('POST', '/settings/server/general', [Web\SettingsController::class, 'updateServerGeneral'])->addMiddleware(Middleware\isAuthenticated::class, Middleware\IsAdmin::class); - $routes->createNewRoute('GET', '/settings/server/users', [Web\SettingsController::class, 'renderServerUsersPage'])->addMiddleware(Middleware\isAuthenticated::class, Middleware\IsAdmin::class); - $routes->createNewRoute('GET', '/settings/server/email', [Web\SettingsController::class, 'renderServerEmailPage'])->addMiddleware(Middleware\isAuthenticated::class, Middleware\IsAdmin::class); - $routes->createNewRoute('POST', '/settings/server/email', [Web\SettingsController::class, 'updateServerEmail'])->addMiddleware(Middleware\isAuthenticated::class, Middleware\IsAdmin::class); - $routes->createNewRoute('POST', '/settings/server/email-test', [Web\SettingsController::class, 'sendTestEmail'])->addMiddleware(Middleware\isAuthenticated::class, Middleware\IsAdmin::class); - $routes->createNewRoute('POST', '/settings/account', [Web\SettingsController::class, 'updateGeneral'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/settings/account/security/update-password', [Web\SettingsController::class, 'updatePassword'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/settings/account/security/create-totp-uri', [Web\TwoFactorAuthenticationController::class, 'createTotpUri'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/settings/account/security/disable-totp', [Web\TwoFactorAuthenticationController::class, 'disableTotp'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/settings/account/security/enable-totp', [Web\TwoFactorAuthenticationController::class, 'enableTotp'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/settings/account/export/csv/{exportType:.+}', [Web\ExportController::class, 'getCsvExport'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/settings/account/import/csv/{exportType:.+}', [Web\ImportController::class, 'handleCsvImport'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/settings/account/delete-ratings', [Web\SettingsController::class, 'deleteRatings'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/settings/account/delete-history', [Web\SettingsController::class, 'deleteHistory'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/settings/account/delete-account', [Web\SettingsController::class, 'deleteAccount'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/settings/account/update-dashboard-rows', [Web\SettingsController::class, 'updateDashboardRows'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/settings/account/reset-dashboard-rows', [Web\SettingsController::class, 'resetDashboardRows'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/settings/integrations/trakt', [Web\SettingsController::class, 'renderTraktPage'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/settings/trakt', [Web\SettingsController::class, 'updateTrakt'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/settings/trakt/verify-credentials', [Web\SettingsController::class, 'traktVerifyCredentials'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/settings/integrations/letterboxd', [Web\SettingsController::class, 'renderLetterboxdPage'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/settings/letterboxd-export', [Web\SettingsController::class, 'generateLetterboxdExportData'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/settings/integrations/plex', [Web\SettingsController::class, 'renderPlexPage'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/settings/plex/logout', [Web\PlexController::class, 'removePlexAccessTokens'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/settings/plex/server-url-save', [Web\PlexController::class, 'savePlexServerUrl'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/settings/plex/server-url-verify', [Web\PlexController::class, 'verifyPlexServerUrl'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/settings/plex/authentication-url', [Web\PlexController::class, 'generatePlexAuthenticationUrl'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/settings/plex/callback', [Web\PlexController::class, 'processPlexCallback'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/settings/plex', [Web\SettingsController::class, 'updatePlex'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('PUT', '/settings/plex/webhook', [Web\PlexController::class, 'regeneratePlexWebhookUrl'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('DELETE', '/settings/plex/webhook', [Web\PlexController::class, 'deletePlexWebhookUrl'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/settings/integrations/jellyfin', [Web\SettingsController::class, 'renderJellyfinPage'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/settings/jellyfin', [Web\SettingsController::class, 'updateJellyfin'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/settings/jellyfin/sync', [Web\JellyfinController::class, 'saveJellyfinSyncOptions'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/settings/jellyfin/authenticate', [Web\JellyfinController::class, 'authenticateJellyfinAccount'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/settings/jellyfin/remove-authentication', [Web\JellyfinController::class, 'removeJellyfinAuthentication'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/settings/jellyfin/server-url-save', [Web\JellyfinController::class, 'saveJellyfinServerUrl'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/settings/jellyfin/server-url-verify', [Web\JellyfinController::class, 'verifyJellyfinServerUrl'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/settings/jellyfin/webhook', [Web\JellyfinController::class, 'getJellyfinWebhookUrl'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('PUT', '/settings/jellyfin/webhook', [Web\JellyfinController::class, 'regenerateJellyfinWebhookUrl'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('DELETE', '/settings/jellyfin/webhook', [Web\JellyfinController::class, 'deleteJellyfinWebhookUrl'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/settings/integrations/emby', [Web\SettingsController::class, 'renderEmbyPage'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/settings/emby', [Web\SettingsController::class, 'updateEmby'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/settings/emby/webhook', [Web\EmbyController::class, 'getEmbyWebhookUrl']); - $routes->createNewRoute('PUT', '/settings/emby/webhook', [Web\EmbyController::class, 'regenerateEmbyWebhookUrl'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('DELETE', '/settings/emby/webhook', [Web\EmbyController::class, 'deleteEmbyWebhookUrl'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/settings/app', [Web\SettingsController::class, 'renderAppPage'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/settings/integrations/netflix', [Web\SettingsController::class, 'renderNetflixPage'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/settings/netflix', [Web\NetflixController::class, 'matchNetflixActivityCsvWithTmdbMovies'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/settings/netflix/import', [Web\NetflixController::class, 'importNetflixData'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/settings/netflix/search', [Web\NetflixController::class, 'searchTmbd'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/settings/users', [Web\UserController::class, 'fetchUsers']); - $routes->createNewRoute('POST', '/settings/users', [Web\UserController::class, 'createUser']); - $routes->createNewRoute('PUT', '/settings/users/{userId:\d+}', [Web\UserController::class, 'updateUser'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('DELETE', '/settings/users/{userId:\d+}', [Web\UserController::class, 'deleteUser'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->add('GET', '/settings/account/general', [Web\SettingsController::class, 'renderGeneralAccountPage'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/settings/account/general/api-token', [Web\SettingsController::class, 'getApiToken'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('DELETE', '/settings/account/general/api-token', [Web\SettingsController::class, 'deleteApiToken'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('PUT', '/settings/account/general/api-token', [Web\SettingsController::class, 'regenerateApiToken'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/settings/account/dashboard', [Web\SettingsController::class, 'renderDashboardAccountPage'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/settings/account/security', [Web\SettingsController::class, 'renderSecurityAccountPage'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/settings/account/data', [Web\SettingsController::class, 'renderDataAccountPage'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/settings/server/general', [Web\SettingsController::class, 'renderServerGeneralPage'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/settings/server/jobs', [Web\SettingsController::class, 'renderServerJobsPage'], [Web\Middleware\UserIsAuthenticated::class, Web\Middleware\UserIsAdmin::class]); + $routes->add('POST', '/settings/server/general', [Web\SettingsController::class, 'updateServerGeneral'], [ + Web\Middleware\UserIsAuthenticated::class, + Web\Middleware\UserIsAdmin::class + ]); + $routes->add('GET', '/settings/server/users', [Web\SettingsController::class, 'renderServerUsersPage'], [Web\Middleware\UserIsAuthenticated::class, Web\Middleware\UserIsAdmin::class]); + $routes->add('GET', '/settings/server/email', [Web\SettingsController::class, 'renderServerEmailPage'], [Web\Middleware\UserIsAuthenticated::class, Web\Middleware\UserIsAdmin::class]); + $routes->add('POST', '/settings/server/email', [Web\SettingsController::class, 'updateServerEmail'], [Web\Middleware\UserIsAuthenticated::class, Web\Middleware\UserIsAdmin::class]); + $routes->add('POST', '/settings/server/email-test', [Web\SettingsController::class, 'sendTestEmail'], [Web\Middleware\UserIsAuthenticated::class, Web\Middleware\UserIsAdmin::class]); + $routes->add('POST', '/settings/account', [Web\SettingsController::class, 'updateGeneral'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/settings/account/security/update-password', [Web\SettingsController::class, 'updatePassword'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/settings/account/security/create-totp-uri', [Web\TwoFactorAuthenticationController::class, 'createTotpUri'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/settings/account/security/disable-totp', [Web\TwoFactorAuthenticationController::class, 'disableTotp'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/settings/account/security/enable-totp', [Web\TwoFactorAuthenticationController::class, 'enableTotp'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/settings/account/export/csv/{exportType:.+}', [Web\ExportController::class, 'getCsvExport'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/settings/account/import/csv/{exportType:.+}', [Web\ImportController::class, 'handleCsvImport'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/settings/account/delete-ratings', [Web\SettingsController::class, 'deleteRatings'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/settings/account/delete-history', [Web\SettingsController::class, 'deleteHistory'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/settings/account/delete-account', [Web\SettingsController::class, 'deleteAccount'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/settings/account/update-dashboard-rows', [Web\SettingsController::class, 'updateDashboardRows'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/settings/account/reset-dashboard-rows', [Web\SettingsController::class, 'resetDashboardRows'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/settings/integrations/trakt', [Web\SettingsController::class, 'renderTraktPage'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/settings/trakt', [Web\SettingsController::class, 'updateTrakt'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/settings/trakt/verify-credentials', [Web\SettingsController::class, 'traktVerifyCredentials'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/settings/integrations/letterboxd', [Web\SettingsController::class, 'renderLetterboxdPage'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/settings/letterboxd-export', [Web\SettingsController::class, 'generateLetterboxdExportData'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/settings/integrations/plex', [Web\SettingsController::class, 'renderPlexPage'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/settings/plex/logout', [Web\PlexController::class, 'removePlexAccessTokens'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/settings/plex/server-url-save', [Web\PlexController::class, 'savePlexServerUrl'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/settings/plex/server-url-verify', [Web\PlexController::class, 'verifyPlexServerUrl'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/settings/plex/authentication-url', [Web\PlexController::class, 'generatePlexAuthenticationUrl'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/settings/plex/callback', [Web\PlexController::class, 'processPlexCallback'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/settings/plex', [Web\SettingsController::class, 'updatePlex'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('PUT', '/settings/plex/webhook', [Web\PlexController::class, 'regeneratePlexWebhookUrl'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('DELETE', '/settings/plex/webhook', [Web\PlexController::class, 'deletePlexWebhookUrl'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/settings/integrations/jellyfin', [Web\SettingsController::class, 'renderJellyfinPage'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/settings/jellyfin', [Web\SettingsController::class, 'updateJellyfin'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/settings/jellyfin/sync', [Web\JellyfinController::class, 'saveJellyfinSyncOptions'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/settings/jellyfin/authenticate', [Web\JellyfinController::class, 'authenticateJellyfinAccount'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/settings/jellyfin/remove-authentication', [Web\JellyfinController::class, 'removeJellyfinAuthentication'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/settings/jellyfin/server-url-save', [Web\JellyfinController::class, 'saveJellyfinServerUrl'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/settings/jellyfin/server-url-verify', [Web\JellyfinController::class, 'verifyJellyfinServerUrl'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/settings/jellyfin/webhook', [Web\JellyfinController::class, 'getJellyfinWebhookUrl'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('PUT', '/settings/jellyfin/webhook', [Web\JellyfinController::class, 'regenerateJellyfinWebhookUrl'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('DELETE', '/settings/jellyfin/webhook', [Web\JellyfinController::class, 'deleteJellyfinWebhookUrl'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/settings/integrations/emby', [Web\SettingsController::class, 'renderEmbyPage'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/settings/emby', [Web\SettingsController::class, 'updateEmby'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/settings/emby/webhook', [Web\EmbyController::class, 'getEmbyWebhookUrl']); + $routes->add('PUT', '/settings/emby/webhook', [Web\EmbyController::class, 'regenerateEmbyWebhookUrl'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('DELETE', '/settings/emby/webhook', [Web\EmbyController::class, 'deleteEmbyWebhookUrl'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/settings/app', [Web\SettingsController::class, 'renderAppPage'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/settings/integrations/netflix', [Web\SettingsController::class, 'renderNetflixPage'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/settings/netflix', [Web\NetflixController::class, 'matchNetflixActivityCsvWithTmdbMovies'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/settings/netflix/import', [Web\NetflixController::class, 'importNetflixData'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/settings/netflix/search', [Web\NetflixController::class, 'searchTmbd'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/settings/users', [Web\UserController::class, 'fetchUsers']); + $routes->add('POST', '/settings/users', [Web\UserController::class, 'createUser']); + $routes->add('PUT', '/settings/users/{userId:\d+}', [Web\UserController::class, 'updateUser'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('DELETE', '/settings/users/{userId:\d+}', [Web\UserController::class, 'deleteUser'], [Web\Middleware\UserIsAuthenticated::class]); ########## # Movies # ########## - $routes->createNewRoute('GET', '/movies/{id:[0-9]+}/refresh-tmdb', [Web\Movie\MovieController::class, 'refreshTmdbData'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/movies/{id:[0-9]+}/refresh-imdb', [Web\Movie\MovieController::class, 'refreshImdbRating'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/movies/{id:[0-9]+}/watch-providers', [Web\Movie\MovieWatchProviderController::class, 'getWatchProviders']); - $routes->createNewRoute('GET', '/movies/{id:[0-9]+}/add-watchlist', [Web\Movie\MovieWatchlistController::class, 'addToWatchlist'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/movies/{id:[0-9]+}/remove-watchlist', [Web\Movie\MovieWatchlistController::class, 'removeFromWatchlist'])->addMiddleware(Middleware\isAuthenticated::class); + $routes->add('GET', '/movies/{id:[0-9]+}/refresh-tmdb', [Web\Movie\MovieController::class, 'refreshTmdbData'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/movies/{id:[0-9]+}/refresh-imdb', [Web\Movie\MovieController::class, 'refreshImdbRating'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/movies/{id:[0-9]+}/watch-providers', [Web\Movie\MovieWatchProviderController::class, 'getWatchProviders']); + $routes->add('GET', '/movies/{id:[0-9]+}/add-watchlist', [Web\Movie\MovieWatchlistController::class, 'addToWatchlist'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/movies/{id:[0-9]+}/remove-watchlist', [Web\Movie\MovieWatchlistController::class, 'removeFromWatchlist'], [Web\Middleware\UserIsAuthenticated::class]); ############## # User media # ############## - $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/dashboard', [Web\DashboardController::class, 'render'])->addMiddleware(Middleware\CanUserBeViewed::class); - $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/history', [Web\HistoryController::class, 'renderHistory']); - $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/watchlist', [Web\WatchlistController::class, 'renderWatchlist']); - $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/movies', [Web\MoviesController::class, 'renderPage']); - $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/actors', [Web\ActorsController::class, 'renderPage']); - $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/directors', [Web\DirectorsController::class, 'renderPage']); - $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}', [Web\Movie\MovieController::class, 'renderPage']); - $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/persons/{id:\d+}', [Web\PersonController::class, 'renderPage']); - $routes->createNewRoute('DELETE', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}/history', [Web\HistoryController::class, 'deleteHistoryEntry'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}/history', [Web\HistoryController::class, 'createHistoryEntry'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}/rating', [Web\Movie\MovieRatingController::class, 'updateRating'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/log-movie', [Web\HistoryController::class, 'logMovie'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('POST', '/add-movie-to-watchlist', [Web\WatchlistController::class, 'addMovieToWatchlist'])->addMiddleware(Middleware\isAuthenticated::class); - $routes->createNewRoute('GET', '/fetchMovieRatingByTmdbdId', [Web\Movie\MovieRatingController::class, 'fetchMovieRatingByTmdbdId'])->addMiddleware(Middleware\isAuthenticated::class); - $routerService->generateRouteCallback($routeCollector, $routes); + $routes->add('GET', '/users/{username:[a-zA-Z0-9]+}/dashboard', [Web\DashboardController::class, 'render'], [Web\Middleware\UserCanViewUser::class]); + $routes->add('GET', '/users/{username:[a-zA-Z0-9]+}/history', [Web\HistoryController::class, 'renderHistory']); + $routes->add('GET', '/users/{username:[a-zA-Z0-9]+}/watchlist', [Web\WatchlistController::class, 'renderWatchlist']); + $routes->add('GET', '/users/{username:[a-zA-Z0-9]+}/movies', [Web\MoviesController::class, 'renderPage']); + $routes->add('GET', '/users/{username:[a-zA-Z0-9]+}/actors', [Web\ActorsController::class, 'renderPage']); + $routes->add('GET', '/users/{username:[a-zA-Z0-9]+}/directors', [Web\DirectorsController::class, 'renderPage']); + $routes->add('GET', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}', [Web\Movie\MovieController::class, 'renderPage']); + $routes->add('GET', '/users/{username:[a-zA-Z0-9]+}/persons/{id:\d+}', [Web\PersonController::class, 'renderPage']); + $routes->add('DELETE', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}/history', [Web\HistoryController::class, 'deleteHistoryEntry'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}/history', [Web\HistoryController::class, 'createHistoryEntry'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/users/{username:[a-zA-Z0-9]+}/movies/{id:\d+}/rating', [ + Web\Movie\MovieRatingController::class, + 'updateRating' + ], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/log-movie', [Web\HistoryController::class, 'logMovie'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('POST', '/add-movie-to-watchlist', [Web\WatchlistController::class, 'addMovieToWatchlist'], [Web\Middleware\UserIsAuthenticated::class]); + $routes->add('GET', '/fetchMovieRatingByTmdbdId', [Web\Movie\MovieRatingController::class, 'fetchMovieRatingByTmdbdId'], [Web\Middleware\UserIsAuthenticated::class]); + + $routerService->addRoutesToRouteCollector($routeCollector, $routes); } -function addApiRoutes(FastRoute\RouteCollector $routeCollector) : void +function addApiRoutes(RouterService $routerService, FastRoute\RouteCollector $routeCollector) : void { - $routerService = new RouterService(); - $routes = $routerService->createRouteList(); - $routes->createNewRoute('GET', '/openapi.json', [Api\OpenApiController::class, 'getSchema']); - $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/history', [Api\HistoryController::class, 'getHistory']); - $routes->createNewRoute('GET', '/users/{username:[a-zA-Z0-9]+}/watchlist', [Api\WatchlistController::class, 'getWatchlist']); - $routerService->generateRouteCallback($routeCollector, $routes); + $routes = RouteList::create(); + + $routes->add('GET', '/openapi.json', [Api\OpenApiController::class, 'getSchema']); + $routes->add('GET', '/users/{username:[a-zA-Z0-9]+}/history', [Api\HistoryController::class, 'getHistory']); + $routes->add('GET', '/users/{username:[a-zA-Z0-9]+}/watchlist', [Api\WatchlistController::class, 'getWatchlist']); + + $routerService->addRoutesToRouteCollector($routeCollector, $routes); } diff --git a/src/Factory.php b/src/Factory.php index 06665b44..98a5726f 100644 --- a/src/Factory.php +++ b/src/Factory.php @@ -98,14 +98,13 @@ public static function createCreatePublicStorageLink(ContainerInterface $contain ); } - public static function createCreateUserController(ContainerInterface $container, Config $config) : CreateUserController + public static function createCreateUserController(ContainerInterface $container) : CreateUserController { return new CreateUserController( $container->get(Twig\Environment::class), $container->get(Authentication::class), $container->get(UserApi::class), $container->get(SessionWrapper::class), - $config->getAsBool('ENABLE_REGISTRATION', false), ); } @@ -209,7 +208,6 @@ public static function createJobController(ContainerInterface $container) : JobC return new JobController( $container->get(Authentication::class), $container->get(JobQueueApi::class), - $container->get(UserApi::class), $container->get(LetterboxdCsvValidator::class), $container->get(SessionWrapper::class), self::createDirectoryStorageApp() @@ -228,8 +226,6 @@ public static function createLandingPageController(ContainerInterface $container { return new LandingPageController( $container->get(Twig\Environment::class), - $container->get(Authentication::class), - $container->get(UserApi::class), $container->get(SessionWrapper::class), $config->getAsBool('ENABLE_REGISTRATION', false), $config->getAsStringNullable('DEFAULT_LOGIN_EMAIL'), @@ -263,9 +259,9 @@ public static function createLogger(ContainerInterface $container, Config $confi return $logger; } - public static function createRegistrationEnabledCheck(Config $config) : Middleware\RegistrationEnabledCheck + public static function createRegistrationEnabledCheck(Config $config) : HttpController\Web\Middleware\ServerHasRegistrationEnabled { - return new Middleware\RegistrationEnabledCheck($config->getAsBool('ENABLE_REGISTRATION', false)); + return new HttpController\Web\Middleware\ServerHasRegistrationEnabled($config->getAsBool('ENABLE_REGISTRATION', false)); } public static function createSettingsController(ContainerInterface $container, Config $config) : SettingsController diff --git a/src/HttpController/Middleware/RegistrationEnabledCheck.php b/src/HttpController/Middleware/RegistrationEnabledCheck.php deleted file mode 100644 index 17410a2b..00000000 --- a/src/HttpController/Middleware/RegistrationEnabledCheck.php +++ /dev/null @@ -1,20 +0,0 @@ -registrationEnabled === false) { - return Response::createSeeOther("/"); - } - return null; - } -} \ No newline at end of file diff --git a/src/HttpController/Web/CreateUserController.php b/src/HttpController/Web/CreateUserController.php index d795b294..307afe59 100644 --- a/src/HttpController/Web/CreateUserController.php +++ b/src/HttpController/Web/CreateUserController.php @@ -23,7 +23,6 @@ public function __construct( private readonly Authentication $authenticationService, private readonly UserApi $userApi, private readonly SessionWrapper $sessionWrapper, - private readonly bool $registrationEnabled, ) { } diff --git a/src/HttpController/Web/HistoryController.php b/src/HttpController/Web/HistoryController.php index f167d232..f1818066 100644 --- a/src/HttpController/Web/HistoryController.php +++ b/src/HttpController/Web/HistoryController.php @@ -105,7 +105,6 @@ public function renderHistory(Request $request) : Response { $userId = $this->userPageAuthorizationChecker->findUserIdIfCurrentVisitorIsAllowedToSeeUser((string)$request->getRouteParameters()['username']); - $searchTerm = $request->getGetParameters()['s'] ?? null; $page = $request->getGetParameters()['p'] ?? 1; $limit = self::DEFAULT_LIMIT; diff --git a/src/HttpController/Web/JobController.php b/src/HttpController/Web/JobController.php index 659d4831..9b53d699 100644 --- a/src/HttpController/Web/JobController.php +++ b/src/HttpController/Web/JobController.php @@ -22,7 +22,6 @@ class JobController public function __construct( private readonly Authentication $authenticationService, private readonly JobQueueApi $jobQueueApi, - private readonly UserApi $userApi, private readonly LetterboxdCsvValidator $letterboxdImportHistoryFileValidator, private readonly SessionWrapper $sessionWrapper, private readonly string $appStorageDirectory, diff --git a/src/HttpController/Web/LandingPageController.php b/src/HttpController/Web/LandingPageController.php index e7fcff5a..63fb1842 100644 --- a/src/HttpController/Web/LandingPageController.php +++ b/src/HttpController/Web/LandingPageController.php @@ -13,8 +13,6 @@ class LandingPageController { public function __construct( private readonly Environment $twig, - private readonly Authentication $authenticationService, - private readonly UserApi $userApi, private readonly SessionWrapper $sessionWrapper, private readonly bool $registrationEnabled, private readonly ?string $defaultEmail, @@ -24,16 +22,6 @@ public function __construct( public function render() : Response { - // if ($this->authenticationService->isUserAuthenticated() === true) { - // $userName = $this->authenticationService->getCurrentUser()->getName(); - - // return Response::createSeeOther("/users/$userName/dashboard"); - // } - - // if ($this->userApi->hasUsers() === false) { - // return Response::createSeeOther('/create-user'); - // } - $failedLogin = $this->sessionWrapper->has('failedLogin'); $deletedAccount = $this->sessionWrapper->has('deletedAccount'); $invalidTotpCode = $this->sessionWrapper->has('invalidTotpCode'); diff --git a/src/HttpController/Middleware/DoesNotHaveUsers.php b/src/HttpController/Web/Middleware/ServerHasNoUsers.php similarity index 71% rename from src/HttpController/Middleware/DoesNotHaveUsers.php rename to src/HttpController/Web/Middleware/ServerHasNoUsers.php index abc7fc93..25098fb5 100644 --- a/src/HttpController/Middleware/DoesNotHaveUsers.php +++ b/src/HttpController/Web/Middleware/ServerHasNoUsers.php @@ -1,21 +1,23 @@ userApi->hasUsers() === false) { return Response::createSeeOther('/create-user'); } + return null; } -} \ No newline at end of file +} diff --git a/src/HttpController/Web/Middleware/ServerHasRegistrationEnabled.php b/src/HttpController/Web/Middleware/ServerHasRegistrationEnabled.php new file mode 100644 index 00000000..75bfb8bb --- /dev/null +++ b/src/HttpController/Web/Middleware/ServerHasRegistrationEnabled.php @@ -0,0 +1,22 @@ +registrationEnabled === true) { + return Response::createSeeOther("/"); + } + + return null; + } +} diff --git a/src/HttpController/Middleware/HasUsersCheck.php b/src/HttpController/Web/Middleware/ServerHasUsers.php similarity index 71% rename from src/HttpController/Middleware/HasUsersCheck.php rename to src/HttpController/Web/Middleware/ServerHasUsers.php index 907291e9..821d4901 100644 --- a/src/HttpController/Middleware/HasUsersCheck.php +++ b/src/HttpController/Web/Middleware/ServerHasUsers.php @@ -1,21 +1,23 @@ userApi->hasUsers() === true) { return Response::createSeeOther('/'); } + return null; } -} \ No newline at end of file +} diff --git a/src/HttpController/Middleware/CanUserBeViewed.php b/src/HttpController/Web/Middleware/UserCanViewUser.php similarity index 82% rename from src/HttpController/Middleware/CanUserBeViewed.php rename to src/HttpController/Web/Middleware/UserCanViewUser.php index 7f77fc25..ce90b054 100644 --- a/src/HttpController/Middleware/CanUserBeViewed.php +++ b/src/HttpController/Web/Middleware/UserCanViewUser.php @@ -1,17 +1,17 @@ getMessage()); } + return null; } -} \ No newline at end of file +} diff --git a/src/HttpController/Middleware/HasPlexAccessToken.php b/src/HttpController/Web/Middleware/UserHasPlexAccessToken.php similarity index 75% rename from src/HttpController/Middleware/HasPlexAccessToken.php rename to src/HttpController/Web/Middleware/UserHasPlexAccessToken.php index 1ea6c1ae..0a3df0be 100644 --- a/src/HttpController/Middleware/HasPlexAccessToken.php +++ b/src/HttpController/Web/Middleware/UserHasPlexAccessToken.php @@ -1,22 +1,24 @@ authenticationService->getCurrentUser()->getPlexAccessToken() === null) { return Response::createBadRequest(PlexAuthenticationMissing::create()->getMessage()); } + return null; } -} \ No newline at end of file +} diff --git a/src/HttpController/Middleware/IsAdmin.php b/src/HttpController/Web/Middleware/UserIsAdmin.php similarity index 71% rename from src/HttpController/Middleware/IsAdmin.php rename to src/HttpController/Web/Middleware/UserIsAdmin.php index e5153c37..a061d7c3 100644 --- a/src/HttpController/Middleware/IsAdmin.php +++ b/src/HttpController/Web/Middleware/UserIsAdmin.php @@ -1,21 +1,23 @@ authenticationService->getCurrentUser()->isAdmin() === false) { return Response::createSeeOther('/'); } + return null; } -} \ No newline at end of file +} diff --git a/src/HttpController/Middleware/isAuthenticated.php b/src/HttpController/Web/Middleware/UserIsAuthenticated.php similarity index 82% rename from src/HttpController/Middleware/isAuthenticated.php rename to src/HttpController/Web/Middleware/UserIsAuthenticated.php index 3890e44a..88d0b63f 100644 --- a/src/HttpController/Middleware/isAuthenticated.php +++ b/src/HttpController/Web/Middleware/UserIsAuthenticated.php @@ -1,21 +1,23 @@ authenticationService->isUserAuthenticated() === false) { return Response::createSeeOther("/login"); } + return null; } -} \ No newline at end of file +} diff --git a/src/HttpController/Middleware/isUnauthenticated.php b/src/HttpController/Web/Middleware/UserIsUnauthenticated.php similarity index 74% rename from src/HttpController/Middleware/isUnauthenticated.php rename to src/HttpController/Web/Middleware/UserIsUnauthenticated.php index 9da2295f..a63597bf 100644 --- a/src/HttpController/Middleware/isUnauthenticated.php +++ b/src/HttpController/Web/Middleware/UserIsUnauthenticated.php @@ -1,22 +1,25 @@ authenticationService->isUserAuthenticated() === true) { $userName = $this->authenticationService->getCurrentUser()->getName(); + return Response::createSeeOther("/users/$userName/dashboard"); } + return null; } -} \ No newline at end of file +} diff --git a/src/HttpController/Web/Movie/MovieController.php b/src/HttpController/Web/Movie/MovieController.php index 2c6d153c..9d528916 100644 --- a/src/HttpController/Web/Movie/MovieController.php +++ b/src/HttpController/Web/Movie/MovieController.php @@ -20,7 +20,6 @@ public function __construct( private readonly Environment $twig, private readonly MovieApi $movieApi, private readonly MovieWatchlistApi $movieWatchlistApi, - private readonly Authentication $authenticationService, private readonly UserPageAuthorizationChecker $userPageAuthorizationChecker, private readonly SyncMovie $tmdbMovieSync, private readonly ImdbMovieRatingSync $imdbMovieRatingSync, diff --git a/src/Service/Router/Dto/Route.php b/src/Service/Router/Dto/Route.php index 78d4ed98..fc49af91 100644 --- a/src/Service/Router/Dto/Route.php +++ b/src/Service/Router/Dto/Route.php @@ -1,23 +1,20 @@ -handler = $handler; - $this->httpMethod = $httpMethod; - $this->route = $route; + public function __construct( + private readonly string $httpMethod, + private readonly string $route, + private readonly array $handler, + private readonly array $middleware, + ) { } - public static function create(string $httpMethod, string $route, array $handler) + public static function create(string $httpMethod, string $route, array $handler, array $middleware = []) : self { - return new self($httpMethod, $route, $handler); + return new self($httpMethod, $route, $handler, $middleware); } public function getHandler() : array @@ -35,13 +32,8 @@ public function getRoute() : string return $this->route; } - public function getMiddleware() :?array + public function getMiddleware() : ?array { return $this->middleware; } - - public function addMiddleware(...$middlewares) : void - { - $this->middleware = $middlewares; - } -} \ No newline at end of file +} diff --git a/src/Service/Router/Dto/RouteList.php b/src/Service/Router/Dto/RouteList.php index c428537c..7d853d91 100644 --- a/src/Service/Router/Dto/RouteList.php +++ b/src/Service/Router/Dto/RouteList.php @@ -1,10 +1,13 @@ -data[] = $route; - return $route; - } - public function getRoutes() : array - { - return $this->data; + return $route; } -} \ No newline at end of file +} diff --git a/src/Service/Router/RouterService.php b/src/Service/Router/RouterService.php index bec1a013..95a1e8ea 100644 --- a/src/Service/Router/RouterService.php +++ b/src/Service/Router/RouterService.php @@ -1,29 +1,23 @@ -getRoutes() as $route) { + foreach ($routeList as $route) { $routeCollector->addRoute( $route->getMethod(), $route->getRoute(), [ 'handler' => $route->getHandler(), 'middleware' => $route->getMiddleware() - ] + ], ); } } -} \ No newline at end of file +} From 224574df49eb222e49b3eb5fca489d72c6557464 Mon Sep 17 00:00:00 2001 From: Lee Peuker Date: Thu, 7 Sep 2023 15:39:02 +0200 Subject: [PATCH 07/11] Make middlewares invokable and add interface --- public/index.php | 11 +++++---- settings/routes.php | 2 +- .../Web/DashboardController.php | 12 +++------- .../Web/Middleware/MiddlewareInterface.php | 11 +++++++++ .../Web/Middleware/ServerHasNoUsers.php | 10 ++++---- .../ServerHasRegistrationEnabled.php | 10 ++++---- .../Web/Middleware/ServerHasUsers.php | 10 ++++---- .../Web/Middleware/UserCanViewUser.php | 11 ++------- .../Web/Middleware/UserHasJellyfinToken.php | 5 ++-- .../Web/Middleware/UserHasPlexAccessToken.php | 24 ------------------- .../Web/Middleware/UserIsAdmin.php | 4 ++-- .../Web/Middleware/UserIsAuthenticated.php | 4 ++-- .../Web/Middleware/UserIsUnauthenticated.php | 4 ++-- 13 files changed, 47 insertions(+), 71 deletions(-) create mode 100644 src/HttpController/Web/Middleware/MiddlewareInterface.php delete mode 100644 src/HttpController/Web/Middleware/UserHasPlexAccessToken.php diff --git a/public/index.php b/public/index.php index 743c5f52..525536ac 100644 --- a/public/index.php +++ b/public/index.php @@ -16,7 +16,7 @@ try { $dispatcher = FastRoute\simpleDispatcher( - require(__DIR__ . '/../settings/routes.php') + require(__DIR__ . '/../settings/routes.php'), ); $uri = $_SERVER['REQUEST_URI']; @@ -39,14 +39,15 @@ $handler = $routeInfo[1]['handler']; $httpRequest->addRouteParameters($routeInfo[2]); - foreach($routeInfo[1]['middleware'] as $middleware) { - $middlewareResponse = $container->call([$middleware, $middlewareMethodName]); - if($middlewareResponse instanceof Response) { + foreach ($routeInfo[1]['middleware'] as $middleware) { + $middlewareResponse = $container->call($middleware, [$httpRequest]); + + if ($middlewareResponse instanceof Response) { $response = $middlewareResponse; break 2; } } - + $response = $container->call($handler, [$httpRequest]); break; default: diff --git a/settings/routes.php b/settings/routes.php index efb78e52..10e16ab9 100644 --- a/settings/routes.php +++ b/settings/routes.php @@ -141,7 +141,7 @@ function addWebRoutes(RouterService $routerService, FastRoute\RouteCollector $ro ############## # User media # ############## - $routes->add('GET', '/users/{username:[a-zA-Z0-9]+}/dashboard', [Web\DashboardController::class, 'render'], [Web\Middleware\UserCanViewUser::class]); + $routes->add('GET', '/users/{username:[a-zA-Z0-9]+}/dashboard', [Web\DashboardController::class, 'render']); $routes->add('GET', '/users/{username:[a-zA-Z0-9]+}/history', [Web\HistoryController::class, 'renderHistory']); $routes->add('GET', '/users/{username:[a-zA-Z0-9]+}/watchlist', [Web\WatchlistController::class, 'renderWatchlist']); $routes->add('GET', '/users/{username:[a-zA-Z0-9]+}/movies', [Web\MoviesController::class, 'renderPage']); diff --git a/src/HttpController/Web/DashboardController.php b/src/HttpController/Web/DashboardController.php index c6b6437b..b984c05d 100644 --- a/src/HttpController/Web/DashboardController.php +++ b/src/HttpController/Web/DashboardController.php @@ -27,19 +27,13 @@ public function __construct( ) { } - public function redirectToDashboard(Request $request) : Response + public function render(Request $request) : Response { - $user = $this->userPageAuthorizationChecker->findUserIfCurrentVisitorIsAllowedToSeeUser((string)$request->getRouteParameters()['username']); - if ($user === null) { + $userId = $this->userPageAuthorizationChecker->findUserIdIfCurrentVisitorIsAllowedToSeeUser((string)$request->getRouteParameters()['username']); + if ($userId === null) { return Response::createSeeOther('/'); } - return Response::createSeeOther('/users/' . $user->getName() . '/dashboard'); - } - - public function render(Request $request) : Response - { - $userId = $this->userPageAuthorizationChecker->findUserIdIfCurrentVisitorIsAllowedToSeeUser((string)$request->getRouteParameters()['username']); $dashboardRows = $this->dashboardFactory->createDashboardRowsForUser($this->userApi->fetchUser($userId)); return Response::create( diff --git a/src/HttpController/Web/Middleware/MiddlewareInterface.php b/src/HttpController/Web/Middleware/MiddlewareInterface.php new file mode 100644 index 00000000..e9416d56 --- /dev/null +++ b/src/HttpController/Web/Middleware/MiddlewareInterface.php @@ -0,0 +1,11 @@ +userApi->hasUsers() === false) { - return Response::createSeeOther('/create-user'); + if ($this->userApi->hasUsers() === true) { + return null; } - return null; + return Response::createSeeOther('/create-user'); } } diff --git a/src/HttpController/Web/Middleware/ServerHasRegistrationEnabled.php b/src/HttpController/Web/Middleware/ServerHasRegistrationEnabled.php index 75bfb8bb..f2a6e19f 100644 --- a/src/HttpController/Web/Middleware/ServerHasRegistrationEnabled.php +++ b/src/HttpController/Web/Middleware/ServerHasRegistrationEnabled.php @@ -4,19 +4,19 @@ use Movary\ValueObject\Http\Response; -class ServerHasRegistrationEnabled +class ServerHasRegistrationEnabled implements MiddlewareInterface { public function __construct( - private bool $registrationEnabled, + private readonly bool $registrationEnabled, ) { } public function __invoke() : ?Response { - if ($this->registrationEnabled === true) { - return Response::createSeeOther("/"); + if ($this->registrationEnabled === false) { + return null; } - return null; + return Response::createSeeOther("/"); } } diff --git a/src/HttpController/Web/Middleware/ServerHasUsers.php b/src/HttpController/Web/Middleware/ServerHasUsers.php index 821d4901..8a977267 100644 --- a/src/HttpController/Web/Middleware/ServerHasUsers.php +++ b/src/HttpController/Web/Middleware/ServerHasUsers.php @@ -5,19 +5,19 @@ use Movary\Domain\User\UserApi; use Movary\ValueObject\Http\Response; -class ServerHasUsers +class ServerHasUsers implements MiddlewareInterface { public function __construct( private readonly UserApi $userApi, ) { } - public function main() : ?Response + public function __invoke() : ?Response { - if ($this->userApi->hasUsers() === true) { - return Response::createSeeOther('/'); + if ($this->userApi->hasUsers() === false) { + return null; } - return null; + return Response::createSeeOther('/'); } } diff --git a/src/HttpController/Web/Middleware/UserCanViewUser.php b/src/HttpController/Web/Middleware/UserCanViewUser.php index ce90b054..b411dd0d 100644 --- a/src/HttpController/Web/Middleware/UserCanViewUser.php +++ b/src/HttpController/Web/Middleware/UserCanViewUser.php @@ -3,23 +3,16 @@ namespace Movary\HttpController\Web\Middleware; use Movary\Domain\User\Service\UserPageAuthorizationChecker; -use Movary\ValueObject\Http\Request; use Movary\ValueObject\Http\Response; -class UserCanViewUser +class UserCanViewUser implements MiddlewareInterface { public function __construct( private readonly UserPageAuthorizationChecker $userPageAuthorizationChecker, ) { } - public function main(Request $request) : ?Response + public function __invoke() : ?Response { - $userId = $this->userPageAuthorizationChecker->findUserIdIfCurrentVisitorIsAllowedToSeeUser((string)$request->getRouteParameters()['username']); - if ($userId === null) { - return Response::createSeeOther('/'); - } - - return null; } } diff --git a/src/HttpController/Web/Middleware/UserHasJellyfinToken.php b/src/HttpController/Web/Middleware/UserHasJellyfinToken.php index 0ac9a00c..269ac3dd 100644 --- a/src/HttpController/Web/Middleware/UserHasJellyfinToken.php +++ b/src/HttpController/Web/Middleware/UserHasJellyfinToken.php @@ -7,7 +7,7 @@ use Movary\Domain\User\UserApi; use Movary\ValueObject\Http\Response; -class UserHasJellyfinToken +class UserHasJellyfinToken implements MiddlewareInterface { public function __construct( private readonly Authentication $authenticationService, @@ -15,7 +15,8 @@ public function __construct( ) { } - public function main() : ?Response + // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter + public function __invoke() : ?Response { $jellyfinAuthentication = $this->userApi->findJellyfinAuthentication($this->authenticationService->getCurrentUserId()); if ($jellyfinAuthentication === null) { diff --git a/src/HttpController/Web/Middleware/UserHasPlexAccessToken.php b/src/HttpController/Web/Middleware/UserHasPlexAccessToken.php deleted file mode 100644 index 0a3df0be..00000000 --- a/src/HttpController/Web/Middleware/UserHasPlexAccessToken.php +++ /dev/null @@ -1,24 +0,0 @@ -authenticationService->getCurrentUser()->getPlexAccessToken() === null) { - return Response::createBadRequest(PlexAuthenticationMissing::create()->getMessage()); - } - - return null; - } -} diff --git a/src/HttpController/Web/Middleware/UserIsAdmin.php b/src/HttpController/Web/Middleware/UserIsAdmin.php index a061d7c3..580f81be 100644 --- a/src/HttpController/Web/Middleware/UserIsAdmin.php +++ b/src/HttpController/Web/Middleware/UserIsAdmin.php @@ -5,14 +5,14 @@ use Movary\Domain\User\Service\Authentication; use Movary\ValueObject\Http\Response; -class UserIsAdmin +class UserIsAdmin implements MiddlewareInterface { public function __construct( private readonly Authentication $authenticationService, ) { } - public function main() : ?Response + public function __invoke() : ?Response { if ($this->authenticationService->getCurrentUser()->isAdmin() === false) { return Response::createSeeOther('/'); diff --git a/src/HttpController/Web/Middleware/UserIsAuthenticated.php b/src/HttpController/Web/Middleware/UserIsAuthenticated.php index 88d0b63f..1a15cc44 100644 --- a/src/HttpController/Web/Middleware/UserIsAuthenticated.php +++ b/src/HttpController/Web/Middleware/UserIsAuthenticated.php @@ -5,14 +5,14 @@ use Movary\Domain\User\Service\Authentication; use Movary\ValueObject\Http\Response; -class UserIsAuthenticated +class UserIsAuthenticated implements MiddlewareInterface { public function __construct( private readonly Authentication $authenticationService, ) { } - public function main() : ?Response + public function __invoke() : ?Response { if ($this->authenticationService->isUserAuthenticated() === false) { return Response::createSeeOther("/login"); diff --git a/src/HttpController/Web/Middleware/UserIsUnauthenticated.php b/src/HttpController/Web/Middleware/UserIsUnauthenticated.php index a63597bf..110588f3 100644 --- a/src/HttpController/Web/Middleware/UserIsUnauthenticated.php +++ b/src/HttpController/Web/Middleware/UserIsUnauthenticated.php @@ -5,14 +5,14 @@ use Movary\Domain\User\Service\Authentication; use Movary\ValueObject\Http\Response; -class UserIsUnauthenticated +class UserIsUnauthenticated implements MiddlewareInterface { public function __construct( private readonly Authentication $authenticationService, ) { } - public function main() : ?Response + public function __invoke() : ?Response { if ($this->authenticationService->isUserAuthenticated() === true) { $userName = $this->authenticationService->getCurrentUser()->getName(); From 5b9237987eb8920c4dc40aceef4afc79c80e9ed0 Mon Sep 17 00:00:00 2001 From: Lee Peuker Date: Thu, 7 Sep 2023 15:40:18 +0200 Subject: [PATCH 08/11] Cleanup --- src/HttpController/Web/HistoryController.php | 3 +++ .../Web/Middleware/UserCanViewUser.php | 18 ------------------ 2 files changed, 3 insertions(+), 18 deletions(-) delete mode 100644 src/HttpController/Web/Middleware/UserCanViewUser.php diff --git a/src/HttpController/Web/HistoryController.php b/src/HttpController/Web/HistoryController.php index f1818066..ec27ff11 100644 --- a/src/HttpController/Web/HistoryController.php +++ b/src/HttpController/Web/HistoryController.php @@ -104,6 +104,9 @@ public function logMovie(Request $request) : Response public function renderHistory(Request $request) : Response { $userId = $this->userPageAuthorizationChecker->findUserIdIfCurrentVisitorIsAllowedToSeeUser((string)$request->getRouteParameters()['username']); + if ($userId === null) { + return Response::createNotFound(); + } $searchTerm = $request->getGetParameters()['s'] ?? null; $page = $request->getGetParameters()['p'] ?? 1; diff --git a/src/HttpController/Web/Middleware/UserCanViewUser.php b/src/HttpController/Web/Middleware/UserCanViewUser.php deleted file mode 100644 index b411dd0d..00000000 --- a/src/HttpController/Web/Middleware/UserCanViewUser.php +++ /dev/null @@ -1,18 +0,0 @@ - Date: Thu, 7 Sep 2023 15:40:44 +0200 Subject: [PATCH 09/11] Cleanup --- public/index.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/public/index.php b/public/index.php index 525536ac..5d4d94a8 100644 --- a/public/index.php +++ b/public/index.php @@ -12,8 +12,6 @@ $container = require(__DIR__ . '/../bootstrap.php'); $httpRequest = $container->get(Request::class); -$middlewareMethodName = 'main'; - try { $dispatcher = FastRoute\simpleDispatcher( require(__DIR__ . '/../settings/routes.php'), From 0a05e8e4b32fe70d4b07102b563e8bd14e5b959d Mon Sep 17 00:00:00 2001 From: Lee Peuker Date: Thu, 7 Sep 2023 15:47:51 +0200 Subject: [PATCH 10/11] Cleanup --- bootstrap.php | 2 +- src/Factory.php | 32 ++++++++++--------- .../ServerHasRegistrationEnabled.php | 2 +- .../Web/Middleware/UserHasJellyfinToken.php | 8 ++--- .../Web/Middleware/UserIsAdmin.php | 6 ++-- .../Web/Middleware/UserIsAuthenticated.php | 6 ++-- .../Web/Middleware/UserIsUnauthenticated.php | 10 +++--- 7 files changed, 34 insertions(+), 32 deletions(-) diff --git a/bootstrap.php b/bootstrap.php index 7d566b97..4cefe0f9 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -19,7 +19,7 @@ \Movary\HttpController\Web\JobController::class => DI\factory([Factory::class, 'createJobController']), \Movary\HttpController\Web\LandingPageController::class => DI\factory([Factory::class, 'createLandingPageController']), \Movary\HttpController\Web\SettingsController::class => DI\factory([Factory::class, 'createSettingsController']), - \Movary\HttpController\Web\Middleware\ServerHasRegistrationEnabled::class => DI\factory([Factory::class, 'createRegistrationEnabledCheck']), + \Movary\HttpController\Web\Middleware\ServerHasRegistrationEnabled::class => DI\factory([Factory::class, 'createMiddlewareServerHasRegistrationEnabled']), \Movary\ValueObject\Http\Request::class => DI\factory([Factory::class, 'createCurrentHttpRequest']), \Movary\Command\CreatePublicStorageLink::class => DI\factory([Factory::class, 'createCreatePublicStorageLink']), \Movary\Command\DatabaseMigrationStatus::class => DI\factory([Factory::class, 'createDatabaseMigrationStatusCommand']), diff --git a/src/Factory.php b/src/Factory.php index 98a5726f..c3d3c48c 100644 --- a/src/Factory.php +++ b/src/Factory.php @@ -177,15 +177,6 @@ public static function createExportService(ContainerInterface $container) : Expo ); } - public static function createOpenApiController(ContainerInterface $container) : OpenApiController - { - return new OpenApiController( - $container->get(File::class), - $container->get(ServerSettings::class), - self::createDirectoryDocs(), - ); - } - public static function createHttpClient() : ClientInterface { return new GuzzleHttp\Client(['timeout' => 4]); @@ -259,9 +250,20 @@ public static function createLogger(ContainerInterface $container, Config $confi return $logger; } - public static function createRegistrationEnabledCheck(Config $config) : HttpController\Web\Middleware\ServerHasRegistrationEnabled + public static function createMiddlewareServerHasRegistrationEnabled(Config $config) : HttpController\Web\Middleware\ServerHasRegistrationEnabled { - return new HttpController\Web\Middleware\ServerHasRegistrationEnabled($config->getAsBool('ENABLE_REGISTRATION', false)); + return new HttpController\Web\Middleware\ServerHasRegistrationEnabled( + $config->getAsBool('ENABLE_REGISTRATION', false) + ); + } + + public static function createOpenApiController(ContainerInterface $container) : OpenApiController + { + return new OpenApiController( + $container->get(File::class), + $container->get(ServerSettings::class), + self::createDirectoryDocs(), + ); } public static function createSettingsController(ContainerInterface $container, Config $config) : SettingsController @@ -376,14 +378,14 @@ private static function createDirectoryAppRoot() : string return substr(__DIR__, 0, -strlen(self::SRC_DIRECTORY_NAME)); } - private static function createDirectoryStorage() : string + private static function createDirectoryDocs() : string { - return self::createDirectoryAppRoot() . 'storage/'; + return self::createDirectoryAppRoot() . 'docs/'; } - private static function createDirectoryDocs() : string + private static function createDirectoryStorage() : string { - return self::createDirectoryAppRoot() . 'docs/'; + return self::createDirectoryAppRoot() . 'storage/'; } private static function createDirectoryStorageApp() : string diff --git a/src/HttpController/Web/Middleware/ServerHasRegistrationEnabled.php b/src/HttpController/Web/Middleware/ServerHasRegistrationEnabled.php index f2a6e19f..5c2f8cc5 100644 --- a/src/HttpController/Web/Middleware/ServerHasRegistrationEnabled.php +++ b/src/HttpController/Web/Middleware/ServerHasRegistrationEnabled.php @@ -17,6 +17,6 @@ public function __invoke() : ?Response return null; } - return Response::createSeeOther("/"); + return Response::createForbidden(); } } diff --git a/src/HttpController/Web/Middleware/UserHasJellyfinToken.php b/src/HttpController/Web/Middleware/UserHasJellyfinToken.php index 269ac3dd..85895627 100644 --- a/src/HttpController/Web/Middleware/UserHasJellyfinToken.php +++ b/src/HttpController/Web/Middleware/UserHasJellyfinToken.php @@ -15,14 +15,14 @@ public function __construct( ) { } - // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter public function __invoke() : ?Response { $jellyfinAuthentication = $this->userApi->findJellyfinAuthentication($this->authenticationService->getCurrentUserId()); - if ($jellyfinAuthentication === null) { - return Response::createBadRequest(JellyfinInvalidAuthentication::create()->getMessage()); + + if ($jellyfinAuthentication !== null) { + return null; } - return null; + return Response::createBadRequest(JellyfinInvalidAuthentication::create()->getMessage()); } } diff --git a/src/HttpController/Web/Middleware/UserIsAdmin.php b/src/HttpController/Web/Middleware/UserIsAdmin.php index 580f81be..583cc6de 100644 --- a/src/HttpController/Web/Middleware/UserIsAdmin.php +++ b/src/HttpController/Web/Middleware/UserIsAdmin.php @@ -14,10 +14,10 @@ public function __construct( public function __invoke() : ?Response { - if ($this->authenticationService->getCurrentUser()->isAdmin() === false) { - return Response::createSeeOther('/'); + if ($this->authenticationService->getCurrentUser()->isAdmin() === true) { + return null; } - return null; + return Response::createForbidden(); } } diff --git a/src/HttpController/Web/Middleware/UserIsAuthenticated.php b/src/HttpController/Web/Middleware/UserIsAuthenticated.php index 1a15cc44..ddc0af62 100644 --- a/src/HttpController/Web/Middleware/UserIsAuthenticated.php +++ b/src/HttpController/Web/Middleware/UserIsAuthenticated.php @@ -14,10 +14,10 @@ public function __construct( public function __invoke() : ?Response { - if ($this->authenticationService->isUserAuthenticated() === false) { - return Response::createSeeOther("/login"); + if ($this->authenticationService->isUserAuthenticated() === true) { + return null; } - return null; + return Response::createForbidden(); } } diff --git a/src/HttpController/Web/Middleware/UserIsUnauthenticated.php b/src/HttpController/Web/Middleware/UserIsUnauthenticated.php index 110588f3..e84d7e8f 100644 --- a/src/HttpController/Web/Middleware/UserIsUnauthenticated.php +++ b/src/HttpController/Web/Middleware/UserIsUnauthenticated.php @@ -14,12 +14,12 @@ public function __construct( public function __invoke() : ?Response { - if ($this->authenticationService->isUserAuthenticated() === true) { - $userName = $this->authenticationService->getCurrentUser()->getName(); - - return Response::createSeeOther("/users/$userName/dashboard"); + if ($this->authenticationService->isUserAuthenticated() === false) { + return null; } - return null; + $userName = $this->authenticationService->getCurrentUser()->getName(); + + return Response::createSeeOther("/users/$userName/dashboard"); } } From 4af840f3b2e8875b36af848bddc92ed71da270cc Mon Sep 17 00:00:00 2001 From: Lee Peuker Date: Thu, 7 Sep 2023 15:50:56 +0200 Subject: [PATCH 11/11] Naming --- src/HttpController/Web/SettingsController.php | 2 +- .../page/settings-integration-jellyfin.html.twig | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/HttpController/Web/SettingsController.php b/src/HttpController/Web/SettingsController.php index 01db7f3e..5dd2afbc 100644 --- a/src/HttpController/Web/SettingsController.php +++ b/src/HttpController/Web/SettingsController.php @@ -280,7 +280,7 @@ public function renderJellyfinPage() : Response 'isActive' => $applicationUrl !== null, 'jellyfinWebhookUrl' => $webhookUrl ?? '-', 'jellyfinServerUrl' => $jellyfinServerUrl, - 'jellyfinisAuthenticated' => $jellyfinAuthentication !== null, + 'jellyfinIsAuthenticated' => $jellyfinAuthentication !== null, 'jellyfinUsername' => $jellyfinUsername?->getUsername(), 'jellyfinDeviceId' => $jellyfinDeviceId, 'scrobbleWatches' => $user->hasJellyfinScrobbleWatchesEnabled(), diff --git a/templates/page/settings-integration-jellyfin.html.twig b/templates/page/settings-integration-jellyfin.html.twig index c6b28af3..c111327a 100644 --- a/templates/page/settings-integration-jellyfin.html.twig +++ b/templates/page/settings-integration-jellyfin.html.twig @@ -98,7 +98,7 @@
-
+
-
+

Username: {{ jellyfinUsername }}

@@ -212,7 +212,7 @@
Jellyfin sync
- @@ -246,7 +246,7 @@ data-bs-target="#exportHistoryModal" data-bs-toggle="modal" id="jellyfinHistoryExportButton" - {% if jellyfinisAuthenticated == false %}disabled{% endif %}> + {% if jellyfinIsAuthenticated == false %}disabled{% endif %}> Export history to Jellyfin
@@ -257,7 +257,7 @@ value="1" id="automaticWatchStateSyncCheckbox" name="scrobbleWatches" - {% if jellyfinisAuthenticated == false %}disabled{% endif %} + {% if jellyfinIsAuthenticated == false %}disabled{% endif %} {% if jellyfinSyncEnabled == true %}checked{% endif %} style="margin-right: 0.2rem"> @@ -265,7 +265,7 @@
-