Skip to content

Commit 080c00a

Browse files
committed
ISSUE-345: set up router
1 parent 9d05218 commit 080c00a

File tree

13 files changed

+327
-3
lines changed

13 files changed

+327
-3
lines changed

.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# .env
2+
API_BASE_URL=http://api.phplist.com/api/v2
3+

.gitignore

100644100755
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@
1414
/var/
1515
/vendor/
1616
.phpunit.result.cache
17+
.env

composer.json

100644100755
Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@
3030
},
3131
"require": {
3232
"php": "^8.1",
33-
"phplist/core": "v5.0.0-alpha7"
33+
"phplist/core": "v5.0.0-alpha7",
34+
"symfony/twig-bundle": "^6.4.0"
3435
},
3536
"require-dev": {
3637
"phpunit/phpunit": "^9.5",
@@ -83,8 +84,18 @@
8384
"symfony-web-dir": "public",
8485
"symfony-tests-dir": "tests",
8586
"phplist/core": {
86-
"bundles": [],
87-
"routes": {}
87+
"bundles": [
88+
"FOS\\RestBundle\\FOSRestBundle",
89+
"Symfony\\Bundle\\TwigBundle\\TwigBundle",
90+
"PhpList\\WebFrontend\\PhpListFrontendBundle"
91+
],
92+
"routes": {
93+
"rest-api": {
94+
"resource": "@PhpListFrontendBundle/Controller/",
95+
"type": "attribute",
96+
"prefix": "/"
97+
}
98+
}
8899
}
89100
}
90101
}

config/.gitkeep

Whitespace-only changes.

config/services.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# config/services.yaml
2+
services:
3+
_defaults:
4+
autowire: true
5+
autoconfigure: true
6+
public: false
7+
8+
PhpList\WebFrontend\:
9+
resource: '../src/'
10+
exclude:
11+
- '../src/DependencyInjection/'
12+
- '../src/Entity/'
13+
- '../src/Kernel.php'
14+
15+
PhpList\WebFrontend\Service\ApiClient:
16+
arguments:
17+
$baseUrl: '${env(API_BASE_URL):http://api.phplist.local/api/v2}'
18+
# calls:
19+
# - setAuthToken: ['%session.auth_token%']
20+
21+
PhpList\WebFrontend\Controller\:
22+
resource: '../src/Controller'
23+
public: true
24+
autowire: true
25+
tags: ['controller.service_arguments']
26+
27+
Symfony\Component\HttpFoundation\Session\SessionInterface: '@session'

src/.gitkeep

Whitespace-only changes.

src/Controller/SecurityController.php

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpList\WebFrontend\Controller;
6+
7+
use Exception;
8+
use GuzzleHttp\Exception\GuzzleException;
9+
use PhpList\WebFrontend\Service\ApiClient;
10+
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
11+
use Symfony\Component\HttpFoundation\Request;
12+
use Symfony\Component\HttpFoundation\RequestStack;
13+
use Symfony\Component\HttpFoundation\Response;
14+
use Symfony\Component\HttpFoundation\Session\SessionInterface;
15+
use Symfony\Component\Routing\Attribute\Route;
16+
17+
class SecurityController extends AbstractController
18+
{
19+
private ApiClient $apiClient;
20+
private SessionInterface $session;
21+
22+
public function __construct(ApiClient $apiClient, RequestStack $requestStack)
23+
{
24+
$this->apiClient = $apiClient;
25+
$this->session = $requestStack->getSession();
26+
}
27+
28+
#[Route('', name: 'login', methods: ['GET', 'POST'])]
29+
public function login(Request $request): Response
30+
{
31+
if ($this->session->has('auth_token')) {
32+
return $this->redirectToRoute('dashboard');
33+
}
34+
35+
$error = null;
36+
37+
if ($request->isMethod('POST')) {
38+
$username = $request->request->get('username');
39+
$password = $request->request->get('password');
40+
41+
try {
42+
$authData = $this->apiClient->authenticate($username, $password);
43+
44+
// Store token in session
45+
$this->session->set('auth_token', $authData['token']);
46+
47+
// Store user data if needed
48+
if (isset($authData['user'])) {
49+
$this->session->set('user', $authData['user']);
50+
}
51+
52+
// Set token for future API requests
53+
$this->apiClient->setAuthToken($authData['token']);
54+
55+
// Redirect to dashboard
56+
return $this->redirectToRoute('dashboard');
57+
} catch (Exception $e) {
58+
$error = 'Invalid credentials or server error: ' . $e->getMessage();
59+
} catch (GuzzleException $e) {
60+
$error = 'Invalid credentials or server error: ' . $e->getMessage();
61+
}
62+
}
63+
64+
return $this->render('security/login.html.twig', [
65+
'error' => $error,
66+
]);
67+
}
68+
69+
#[Route('/logout', name: 'logout')]
70+
public function logout(): Response
71+
{
72+
// Clear session data
73+
$this->session->remove('auth_token');
74+
$this->session->remove('user');
75+
76+
return $this->redirectToRoute('login');
77+
}
78+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpList\WebFrontend\DependencyInjection;
6+
7+
use Exception;
8+
use InvalidArgumentException;
9+
use Symfony\Component\Config\FileLocator;
10+
use Symfony\Component\DependencyInjection\ContainerBuilder;
11+
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
12+
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
13+
14+
class PhpListFrontendExtension extends Extension
15+
{
16+
/**
17+
* Loads a specific configuration.
18+
*
19+
* @param array $configs configuration values
20+
* @param ContainerBuilder $container
21+
*
22+
* @return void
23+
*
24+
* @throws InvalidArgumentException|Exception if the provided tag is not defined in this extension
25+
*/
26+
public function load(array $configs, ContainerBuilder $container): void
27+
{
28+
// @phpstan-ignore-next-line
29+
$configs;
30+
$loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../../config'));
31+
$loader->load('services.yml');
32+
}
33+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespace PhpList\WebFrontend\EventSubscriber;
4+
5+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
6+
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
7+
use Symfony\Component\HttpKernel\KernelEvents;
8+
use GuzzleHttp\Exception\ClientException;
9+
10+
class UnauthorizedSubscriber implements EventSubscriberInterface
11+
{
12+
public static function getSubscribedEvents(): array
13+
{
14+
return [
15+
KernelEvents::EXCEPTION => 'onKernelException',
16+
];
17+
}
18+
19+
public function onKernelException(ExceptionEvent $event): void
20+
{
21+
$exception = $event->getThrowable();
22+
23+
if ($exception instanceof ClientException && $exception->getCode() === 401) {
24+
// Redirect to login page or handle unauthorized access
25+
}
26+
}
27+
}

src/PhpListFrontendBundle.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpList\WebFrontend;
6+
7+
use Symfony\Component\HttpKernel\Bundle\Bundle;
8+
9+
class PhpListFrontendBundle extends Bundle
10+
{
11+
}

0 commit comments

Comments
 (0)