Merge pull request #9 from biondizzle/codex/refactor-route-handling-to-use-config/routes

Refactor API controllers to use explicit routes
This commit is contained in:
biondizzle
2025-06-05 21:07:12 -04:00
committed by GitHub
3 changed files with 465 additions and 333 deletions

View File

@@ -1,39 +1,92 @@
# Console API Routes # Console API Routes
console_api_credentials: console_api_credentials_list:
path: /api/credentials path: /api/credentials
controller: App\Controller\ConsoleApiController::credentials controller: App\Controller\ConsoleApiController::listCredentials
methods: [GET, POST] methods: [GET]
console_api_credential_detail: console_api_credentials_create:
path: /api/credentials
controller: App\Controller\ConsoleApiController::createCredential
methods: [POST]
console_api_credential_get:
path: /api/credentials/{id} path: /api/credentials/{id}
controller: App\Controller\ConsoleApiController::credentialDetail controller: App\Controller\ConsoleApiController::getCredential
methods: [GET, PUT, DELETE] methods: [GET]
requirements: requirements:
id: '\d+' id: '\d+'
console_api_buckets: console_api_credential_update:
path: /api/buckets path: /api/credentials/{id}
controller: App\Controller\ConsoleApiController::buckets controller: App\Controller\ConsoleApiController::updateCredential
methods: [GET, POST] methods: [PUT]
requirements:
id: '\d+'
console_api_bucket_detail: console_api_credential_delete:
path: /api/credentials/{id}
controller: App\Controller\ConsoleApiController::deleteCredential
methods: [DELETE]
requirements:
id: '\d+'
console_api_buckets_list:
path: /api/buckets
controller: App\Controller\ConsoleApiController::listBuckets
methods: [GET]
console_api_buckets_create:
path: /api/buckets
controller: App\Controller\ConsoleApiController::createBucket
methods: [POST]
console_api_bucket_get:
path: /api/buckets/{name} path: /api/buckets/{name}
controller: App\Controller\ConsoleApiController::bucketDetail controller: App\Controller\ConsoleApiController::getBucket
methods: [GET, DELETE] methods: [GET]
requirements: requirements:
name: '[a-z0-9\-\.]+' name: '[a-z0-9\-\.]+'
console_api_objects: console_api_bucket_delete:
path: /api/buckets/{name}
controller: App\Controller\ConsoleApiController::deleteBucket
methods: [DELETE]
requirements:
name: '[a-z0-9\-\.]+'
console_api_objects_list:
path: /api/buckets/{bucketName}/objects path: /api/buckets/{bucketName}/objects
controller: App\Controller\ConsoleApiController::objects controller: App\Controller\ConsoleApiController::listObjects
methods: [GET, POST, DELETE] methods: [GET]
requirements: requirements:
bucketName: '[a-z0-9\-\.]+' bucketName: '[a-z0-9\-\.]+'
console_api_object_detail: console_api_create_object:
path: /api/buckets/{bucketName}/objects
controller: App\Controller\ConsoleApiController::createObject
methods: [POST]
requirements:
bucketName: '[a-z0-9\-\.]+'
console_api_delete_objects:
path: /api/buckets/{bucketName}/objects
controller: App\Controller\ConsoleApiController::deleteObjects
methods: [DELETE]
requirements:
bucketName: '[a-z0-9\-\.]+'
console_api_object_get:
path: /api/buckets/{bucketName}/objects/{objectKey} path: /api/buckets/{bucketName}/objects/{objectKey}
controller: App\Controller\ConsoleApiController::objectDetail controller: App\Controller\ConsoleApiController::getObject
methods: [GET, DELETE] methods: [GET]
requirements:
bucketName: '[a-z0-9\-\.]+'
objectKey: '.+'
console_api_object_delete:
path: /api/buckets/{bucketName}/objects/{objectKey}
controller: App\Controller\ConsoleApiController::deleteObject
methods: [DELETE]
requirements: requirements:
bucketName: '[a-z0-9\-\.]+' bucketName: '[a-z0-9\-\.]+'
objectKey: '.+' objectKey: '.+'
@@ -53,10 +106,15 @@ console_api_multipart_uploads:
requirements: requirements:
bucketName: '[a-z0-9\-\.]+' bucketName: '[a-z0-9\-\.]+'
console_api_presigned_urls: console_api_presigned_urls_list:
path: /api/presigned-urls path: /api/presigned-urls
controller: App\Controller\ConsoleApiController::presignedUrls controller: App\Controller\ConsoleApiController::listPresignedUrls
methods: [GET, POST] methods: [GET]
console_api_presigned_urls_create:
path: /api/presigned-urls
controller: App\Controller\ConsoleApiController::createPresignedUrl
methods: [POST]
console_api_stats: console_api_stats:
path: /api/stats path: /api/stats
@@ -64,10 +122,15 @@ console_api_stats:
methods: [GET] methods: [GET]
# Console Authentication Routes # Console Authentication Routes
console_login: console_login_form:
path: /console/login path: /console/login
controller: App\Controller\ConsoleController::login controller: App\Controller\ConsoleController::loginForm
methods: [GET, POST] methods: [GET]
console_login_submit:
path: /console/login
controller: App\Controller\ConsoleController::loginSubmit
methods: [POST]
console_logout: console_logout:
path: /console/logout path: /console/logout

View File

@@ -28,13 +28,13 @@ class ConsoleApiController extends AbstractController
} }
// Credentials Management // Credentials Management
public function credentials(Request $request): JsonResponse public function listCredentials(Request $request): JsonResponse
{ {
$resp = $this->checkAuth($request); $resp = $this->checkAuth($request);
if (!empty($resp)) { if ($resp !== null) {
return $resp; return $resp;
} }
if ($request->getMethod() === 'GET') {
$credentials = $this->entityManager->getRepository(S3Credential::class)->findAll(); $credentials = $this->entityManager->getRepository(S3Credential::class)->findAll();
return new JsonResponse([ return new JsonResponse([
@@ -51,7 +51,13 @@ class ConsoleApiController extends AbstractController
]); ]);
} }
if ($request->getMethod() === 'POST') { public function createCredential(Request $request): JsonResponse
{
$resp = $this->checkAuth($request);
if ($resp !== null) {
return $resp;
}
$data = json_decode($request->getContent(), true); $data = json_decode($request->getContent(), true);
$accessKey = $data['access_key'] ?? 'AKIA' . strtoupper(bin2hex(random_bytes(10))); $accessKey = $data['access_key'] ?? 'AKIA' . strtoupper(bin2hex(random_bytes(10)));
@@ -70,10 +76,7 @@ class ConsoleApiController extends AbstractController
], 201); ], 201);
} }
return new JsonResponse(['error' => 'Method not allowed'], 405); public function getCredential(int $id, Request $request): JsonResponse
}
public function credentialDetail(int $id, Request $request): JsonResponse
{ {
$authResp = $this->checkAuth($request); $authResp = $this->checkAuth($request);
if ($authResp !== null) { if ($authResp !== null) {
@@ -85,7 +88,6 @@ class ConsoleApiController extends AbstractController
return new JsonResponse(['error' => 'Credential not found'], 404); return new JsonResponse(['error' => 'Credential not found'], 404);
} }
if ($request->getMethod() === 'GET') {
return new JsonResponse([ return new JsonResponse([
'id' => $credential->getId(), 'id' => $credential->getId(),
'access_key' => $credential->getAccessKey(), 'access_key' => $credential->getAccessKey(),
@@ -103,7 +105,18 @@ class ConsoleApiController extends AbstractController
]); ]);
} }
if ($request->getMethod() === 'PUT') { public function updateCredential(int $id, Request $request): JsonResponse
{
$authResp = $this->checkAuth($request);
if ($authResp !== null) {
return $authResp;
}
$credential = $this->entityManager->getRepository(S3Credential::class)->find($id);
if (!$credential) {
return new JsonResponse(['error' => 'Credential not found'], 404);
}
$data = json_decode($request->getContent(), true); $data = json_decode($request->getContent(), true);
if (isset($data['user_name'])) { if (isset($data['user_name'])) {
@@ -118,24 +131,32 @@ class ConsoleApiController extends AbstractController
return new JsonResponse(['message' => 'Credential updated']); return new JsonResponse(['message' => 'Credential updated']);
} }
if ($request->getMethod() === 'DELETE') { public function deleteCredential(int $id, Request $request): JsonResponse
{
$authResp = $this->checkAuth($request);
if ($authResp !== null) {
return $authResp;
}
$credential = $this->entityManager->getRepository(S3Credential::class)->find($id);
if (!$credential) {
return new JsonResponse(['error' => 'Credential not found'], 404);
}
$this->entityManager->remove($credential); $this->entityManager->remove($credential);
$this->entityManager->flush(); $this->entityManager->flush();
return new JsonResponse(['message' => 'Credential deleted']); return new JsonResponse(['message' => 'Credential deleted']);
} }
return new JsonResponse(['error' => 'Method not allowed'], 405);
}
// Buckets Management // Buckets Management
public function buckets(Request $request): JsonResponse public function listBuckets(Request $request): JsonResponse
{ {
$authResp = $this->checkAuth($request); $authResp = $this->checkAuth($request);
if ($authResp !== null) { if ($authResp !== null) {
return $authResp; return $authResp;
} }
if ($request->getMethod() === 'GET') {
$buckets = $this->entityManager->getRepository(S3Bucket::class)->findAll(); $buckets = $this->entityManager->getRepository(S3Bucket::class)->findAll();
return new JsonResponse([ return new JsonResponse([
@@ -162,7 +183,13 @@ class ConsoleApiController extends AbstractController
]); ]);
} }
if ($request->getMethod() === 'POST') { public function createBucket(Request $request): JsonResponse
{
$authResp = $this->checkAuth($request);
if ($authResp !== null) {
return $authResp;
}
$data = json_decode($request->getContent(), true); $data = json_decode($request->getContent(), true);
$bucketName = $data['name'] ?? null; $bucketName = $data['name'] ?? null;
@@ -192,10 +219,7 @@ class ConsoleApiController extends AbstractController
} }
} }
return new JsonResponse(['error' => 'Method not allowed'], 405); public function getBucket(string $name, Request $request): JsonResponse
}
public function bucketDetail(string $name, Request $request): JsonResponse
{ {
$authResp = $this->checkAuth($request); $authResp = $this->checkAuth($request);
if ($authResp !== null) { if ($authResp !== null) {
@@ -207,7 +231,6 @@ class ConsoleApiController extends AbstractController
return new JsonResponse(['error' => 'Bucket not found'], 404); return new JsonResponse(['error' => 'Bucket not found'], 404);
} }
if ($request->getMethod() === 'GET') {
$objects = $this->s3Service->listObjects($bucket); $objects = $this->s3Service->listObjects($bucket);
$totalSize = array_sum(array_map(fn($obj) => $obj->getSize(), $objects)); $totalSize = array_sum(array_map(fn($obj) => $obj->getSize(), $objects));
@@ -233,7 +256,18 @@ class ConsoleApiController extends AbstractController
]); ]);
} }
if ($request->getMethod() === 'DELETE') { public function deleteBucket(string $name, Request $request): JsonResponse
{
$authResp = $this->checkAuth($request);
if ($authResp !== null) {
return $authResp;
}
$bucket = $this->s3Service->findBucketByName($name);
if (!$bucket) {
return new JsonResponse(['error' => 'Bucket not found'], 404);
}
try { try {
$this->s3Service->deleteBucket($bucket); $this->s3Service->deleteBucket($bucket);
return new JsonResponse(['message' => 'Bucket deleted']); return new JsonResponse(['message' => 'Bucket deleted']);
@@ -242,11 +276,8 @@ class ConsoleApiController extends AbstractController
} }
} }
return new JsonResponse(['error' => 'Method not allowed'], 405);
}
// Objects Management // Objects Management
public function objects(string $bucketName, Request $request): JsonResponse public function listObjects(string $bucketName, Request $request): JsonResponse
{ {
$authResp = $this->checkAuth($request); $authResp = $this->checkAuth($request);
if ($authResp !== null) { if ($authResp !== null) {
@@ -258,7 +289,6 @@ class ConsoleApiController extends AbstractController
return new JsonResponse(['error' => 'Bucket not found'], 404); return new JsonResponse(['error' => 'Bucket not found'], 404);
} }
if ($request->getMethod() === 'GET') {
$prefix = $request->query->get('prefix', ''); $prefix = $request->query->get('prefix', '');
$objects = $this->s3Service->listObjects($bucket, $prefix); $objects = $this->s3Service->listObjects($bucket, $prefix);
@@ -277,7 +307,18 @@ class ConsoleApiController extends AbstractController
]); ]);
} }
if ($request->getMethod() === 'POST') { public function createObject(string $bucketName, Request $request): JsonResponse
{
$authResp = $this->checkAuth($request);
if ($authResp !== null) {
return $authResp;
}
$bucket = $this->s3Service->findBucketByName($bucketName);
if (!$bucket) {
return new JsonResponse(['error' => 'Bucket not found'], 404);
}
$objectKey = $request->headers->get('X-Object-Key') $objectKey = $request->headers->get('X-Object-Key')
?? $request->query->get('key') ?? $request->query->get('key')
?? $request->request->get('object_key'); ?? $request->request->get('object_key');
@@ -305,7 +346,18 @@ class ConsoleApiController extends AbstractController
], 201); ], 201);
} }
if ($request->getMethod() === 'DELETE') { public function deleteObjects(string $bucketName, Request $request): JsonResponse
{
$authResp = $this->checkAuth($request);
if ($authResp !== null) {
return $authResp;
}
$bucket = $this->s3Service->findBucketByName($bucketName);
if (!$bucket) {
return new JsonResponse(['error' => 'Bucket not found'], 404);
}
$data = json_decode($request->getContent(), true); $data = json_decode($request->getContent(), true);
$keys = $data['keys'] ?? []; $keys = $data['keys'] ?? [];
@@ -321,10 +373,7 @@ class ConsoleApiController extends AbstractController
return new JsonResponse(['deleted' => $deleted]); return new JsonResponse(['deleted' => $deleted]);
} }
return new JsonResponse(['error' => 'Method not allowed'], 405); public function getObject(string $bucketName, string $objectKey, Request $request): JsonResponse
}
public function objectDetail(string $bucketName, string $objectKey, Request $request): JsonResponse
{ {
$authResp = $this->checkAuth($request); $authResp = $this->checkAuth($request);
if ($authResp !== null) { if ($authResp !== null) {
@@ -342,7 +391,6 @@ class ConsoleApiController extends AbstractController
return new JsonResponse(['error' => 'Object not found'], 404); return new JsonResponse(['error' => 'Object not found'], 404);
} }
if ($request->getMethod() === 'GET') {
return new JsonResponse([ return new JsonResponse([
'key' => $object->getObjectKey(), 'key' => $object->getObjectKey(),
'size' => $object->getSize(), 'size' => $object->getSize(),
@@ -358,12 +406,26 @@ class ConsoleApiController extends AbstractController
]); ]);
} }
if ($request->getMethod() === 'DELETE') { public function deleteObject(string $bucketName, string $objectKey, Request $request): JsonResponse
$this->s3Service->deleteObject($object); {
return new JsonResponse(['message' => 'Object deleted']); $authResp = $this->checkAuth($request);
if ($authResp !== null) {
return $authResp;
}
$bucket = $this->s3Service->findBucketByName($bucketName);
if (!$bucket) {
return new JsonResponse(['error' => 'Bucket not found'], 404);
} }
return new JsonResponse(['error' => 'Method not allowed'], 405); $object = $this->s3Service->findObject($bucket, $objectKey);
if (!$object) {
return new JsonResponse(['error' => 'Object not found'], 404);
}
$this->s3Service->deleteObject($object);
return new JsonResponse(['message' => 'Object deleted']);
} }
public function createPresignedUpload(string $bucketName, string $objectKey, Request $request): JsonResponse public function createPresignedUpload(string $bucketName, string $objectKey, Request $request): JsonResponse
@@ -435,13 +497,13 @@ class ConsoleApiController extends AbstractController
} }
// Presigned URLs // Presigned URLs
public function presignedUrls(Request $request): JsonResponse public function listPresignedUrls(Request $request): JsonResponse
{ {
$authResp = $this->checkAuth($request); $authResp = $this->checkAuth($request);
if ($authResp !== null) { if ($authResp !== null) {
return $authResp; return $authResp;
} }
if ($request->getMethod() === 'GET') {
$urls = $this->entityManager->getRepository(\App\Entity\S3PresignedUrl::class) $urls = $this->entityManager->getRepository(\App\Entity\S3PresignedUrl::class)
->createQueryBuilder('p') ->createQueryBuilder('p')
->where('p.expiresAt > :now') ->where('p.expiresAt > :now')
@@ -466,7 +528,13 @@ class ConsoleApiController extends AbstractController
]); ]);
} }
if ($request->getMethod() === 'POST') { public function createPresignedUrl(Request $request): JsonResponse
{
$authResp = $this->checkAuth($request);
if ($authResp !== null) {
return $authResp;
}
$data = json_decode($request->getContent(), true); $data = json_decode($request->getContent(), true);
$bucketName = $data['bucket_name'] ?? null; $bucketName = $data['bucket_name'] ?? null;
@@ -489,9 +557,6 @@ class ConsoleApiController extends AbstractController
return new JsonResponse(['url' => $url], 201); return new JsonResponse(['url' => $url], 201);
} }
return new JsonResponse(['error' => 'Method not allowed'], 405);
}
// Statistics // Statistics
public function stats(Request $request): JsonResponse public function stats(Request $request): JsonResponse
{ {

View File

@@ -18,14 +18,21 @@ class ConsoleController extends AbstractController
return $this->render('console/index.html.twig'); return $this->render('console/index.html.twig');
} }
public function login(Request $request): Response public function loginForm(Request $request): Response
{
if ($request->getSession()->get('console_logged_in')) {
return new RedirectResponse('/console');
}
return $this->render('console/login.html.twig', ['error' => null]);
}
public function loginSubmit(Request $request): Response
{ {
if ($request->getSession()->get('console_logged_in')) { if ($request->getSession()->get('console_logged_in')) {
return new RedirectResponse('/console'); return new RedirectResponse('/console');
} }
$error = null;
if ($request->isMethod('POST')) {
$user = $request->request->get('username'); $user = $request->request->get('username');
$pass = $request->request->get('password'); $pass = $request->request->get('password');
$envUser = $_ENV['CONSOLE_USER'] ?? 'admin'; $envUser = $_ENV['CONSOLE_USER'] ?? 'admin';
@@ -36,10 +43,7 @@ class ConsoleController extends AbstractController
return new RedirectResponse('/console'); return new RedirectResponse('/console');
} }
$error = 'Invalid credentials'; return $this->render('console/login.html.twig', ['error' => 'Invalid credentials']);
}
return $this->render('console/login.html.twig', ['error' => $error]);
} }
public function logout(Request $request): Response public function logout(Request $request): Response