diff --git a/config/routes.php b/config/routes.php index 6f61ec71..6cc0ce8b 100644 --- a/config/routes.php +++ b/config/routes.php @@ -11,6 +11,9 @@ $route->get('/', function () { }); $route->get('/credits', 'CreditsController@index'); +// Authentication +$route->get('/logout', 'AuthController@logout'); + // Stats $route->get('/metrics', 'Metrics\\Controller@metrics'); $route->get('/stats', 'Metrics\\Controller@stats'); diff --git a/includes/pages/guest_login.php b/includes/pages/guest_login.php index b079b9fe..d152a092 100644 --- a/includes/pages/guest_login.php +++ b/includes/pages/guest_login.php @@ -24,14 +24,6 @@ function register_title() return __('Register'); } -/** - * @return string - */ -function logout_title() -{ - return __('Logout'); -} - /** * Engel registrieren * @@ -378,16 +370,6 @@ function entry_required() return ''; } -/** - * @return bool - */ -function guest_logout() -{ - session()->invalidate(); - redirect(page_link_to('start')); - return true; -} - /** * @return string */ diff --git a/src/Controllers/AuthController.php b/src/Controllers/AuthController.php new file mode 100644 index 00000000..cdaee167 --- /dev/null +++ b/src/Controllers/AuthController.php @@ -0,0 +1,36 @@ +response = $response; + $this->session = $session; + $this->url = $url; + } + + /** + * @return Response + */ + public function logout() + { + $this->session->invalidate(); + + return $this->response->redirectTo($this->url->to('/')); + } +} diff --git a/src/Http/Response.php b/src/Http/Response.php index 58cd7662..1a7c8209 100644 --- a/src/Http/Response.php +++ b/src/Http/Response.php @@ -121,4 +121,27 @@ class Response extends SymfonyResponse implements ResponseInterface return $new; } + + /** + * Return an redirect instance + * + * This method retains the immutability of the message and returns + * an instance with the updated status and headers + * + * @param string $path + * @param int $status + * @param array $headers + * @return Response + */ + public function redirectTo($path, $status = 302, $headers = []) + { + $response = $this->withStatus($status); + $response = $response->withHeader('location', $path); + + foreach ($headers as $name => $value) { + $response = $response->withAddedHeader($name, $value); + } + + return $response; + } } diff --git a/src/Http/UrlGeneratorServiceProvider.php b/src/Http/UrlGeneratorServiceProvider.php index 9b9988aa..774e3e35 100644 --- a/src/Http/UrlGeneratorServiceProvider.php +++ b/src/Http/UrlGeneratorServiceProvider.php @@ -11,5 +11,6 @@ class UrlGeneratorServiceProvider extends ServiceProvider $urlGenerator = $this->app->make(UrlGenerator::class); $this->app->instance(UrlGenerator::class, $urlGenerator); $this->app->instance('http.urlGenerator', $urlGenerator); + $this->app->bind(UrlGeneratorInterface::class, UrlGenerator::class); } } diff --git a/src/Middleware/LegacyMiddleware.php b/src/Middleware/LegacyMiddleware.php index bd3987d2..af2c6a70 100644 --- a/src/Middleware/LegacyMiddleware.php +++ b/src/Middleware/LegacyMiddleware.php @@ -183,10 +183,6 @@ class LegacyMiddleware implements MiddlewareInterface $title = register_title(); $content = guest_register(); return [$title, $content]; - case 'logout': - $title = logout_title(); - $content = guest_logout(); - return [$title, $content]; case 'admin_questions': $title = admin_questions_title(); $content = admin_questions(); diff --git a/tests/Unit/Controllers/AuthControllerTest.php b/tests/Unit/Controllers/AuthControllerTest.php new file mode 100644 index 00000000..c5349cda --- /dev/null +++ b/tests/Unit/Controllers/AuthControllerTest.php @@ -0,0 +1,42 @@ +createMock(Response::class); + /** @var SessionInterface|MockObject $session */ + $session = $this->getMockForAbstractClass(SessionInterface::class); + /** @var UrlGeneratorInterface|MockObject $url */ + $url = $this->getMockForAbstractClass(UrlGeneratorInterface::class); + + $session->expects($this->once()) + ->method('invalidate'); + + $response->expects($this->once()) + ->method('redirectTo') + ->with('https://foo.bar/'); + + $url->expects($this->once()) + ->method('to') + ->with('/') + ->willReturn('https://foo.bar/'); + + $controller = new AuthController($response, $session, $url); + $controller->logout(); + } +} diff --git a/tests/Unit/Controllers/CreditsControllerTest.php b/tests/Unit/Controllers/CreditsControllerTest.php index 3ce92cb1..42ea4ea1 100644 --- a/tests/Unit/Controllers/CreditsControllerTest.php +++ b/tests/Unit/Controllers/CreditsControllerTest.php @@ -1,6 +1,6 @@ withView('foo'); } + + /** + * @covers \Engelsystem\Http\Response::redirectTo + */ + public function testRedirectTo() + { + $response = new Response(); + $newResponse = $response->redirectTo('http://foo.bar/lorem', 301, ['test' => 'ing']); + + $this->assertNotEquals($response, $newResponse); + $this->assertEquals(301, $newResponse->getStatusCode()); + $this->assertArraySubset( + [ + 'location' => ['http://foo.bar/lorem'], + 'test' => ['ing'], + ], + $newResponse->getHeaders() + ); + } } diff --git a/tests/Unit/Http/UrlGeneratorServiceProviderTest.php b/tests/Unit/Http/UrlGeneratorServiceProviderTest.php index c396c05a..61bf3e7c 100644 --- a/tests/Unit/Http/UrlGeneratorServiceProviderTest.php +++ b/tests/Unit/Http/UrlGeneratorServiceProviderTest.php @@ -3,6 +3,7 @@ namespace Engelsystem\Test\Unit\Http; use Engelsystem\Http\UrlGenerator; +use Engelsystem\Http\UrlGeneratorInterface; use Engelsystem\Http\UrlGeneratorServiceProvider; use Engelsystem\Test\Unit\ServiceProviderTest; use PHPUnit\Framework\MockObject\MockObject; @@ -25,7 +26,8 @@ class UrlGeneratorServiceProviderTest extends ServiceProviderTest ->method('instance') ->withConsecutive( [UrlGenerator::class, $urlGenerator], - ['http.urlGenerator', $urlGenerator] + ['http.urlGenerator', $urlGenerator], + [UrlGeneratorInterface::class, $urlGenerator] ); $serviceProvider = new UrlGeneratorServiceProvider($app);