refactor routes
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -28,52 +28,55 @@ 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();
|
|
||||||
|
|
||||||
return new JsonResponse([
|
$credentials = $this->entityManager->getRepository(S3Credential::class)->findAll();
|
||||||
'credentials' => array_map(function($cred) {
|
|
||||||
return [
|
|
||||||
'id' => $cred->getId(),
|
|
||||||
'access_key' => $cred->getAccessKey(),
|
|
||||||
'user_name' => $cred->getUserName(),
|
|
||||||
'is_active' => $cred->isActive(),
|
|
||||||
'created_at' => $cred->getCreatedAt()->format('Y-m-d H:i:s'),
|
|
||||||
'bucket_count' => $cred->getBuckets()->count()
|
|
||||||
];
|
|
||||||
}, $credentials)
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($request->getMethod() === 'POST') {
|
return new JsonResponse([
|
||||||
$data = json_decode($request->getContent(), true);
|
'credentials' => array_map(function($cred) {
|
||||||
|
return [
|
||||||
$accessKey = $data['access_key'] ?? 'AKIA' . strtoupper(bin2hex(random_bytes(10)));
|
'id' => $cred->getId(),
|
||||||
$secretKey = $data['secret_key'] ?? base64_encode(random_bytes(30));
|
'access_key' => $cred->getAccessKey(),
|
||||||
$userName = $data['user_name'] ?? null;
|
'user_name' => $cred->getUserName(),
|
||||||
|
'is_active' => $cred->isActive(),
|
||||||
$credential = $this->s3Service->createCredential($accessKey, $secretKey, $userName);
|
'created_at' => $cred->getCreatedAt()->format('Y-m-d H:i:s'),
|
||||||
|
'bucket_count' => $cred->getBuckets()->count()
|
||||||
return new JsonResponse([
|
];
|
||||||
'id' => $credential->getId(),
|
}, $credentials)
|
||||||
'access_key' => $credential->getAccessKey(),
|
]);
|
||||||
'secret_key' => $credential->getSecretKey(),
|
|
||||||
'user_name' => $credential->getUserName(),
|
|
||||||
'is_active' => $credential->isActive(),
|
|
||||||
'created_at' => $credential->getCreatedAt()->format('Y-m-d H:i:s')
|
|
||||||
], 201);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new JsonResponse(['error' => 'Method not allowed'], 405);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function credentialDetail(int $id, Request $request): JsonResponse
|
public function createCredential(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$resp = $this->checkAuth($request);
|
||||||
|
if ($resp !== null) {
|
||||||
|
return $resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = json_decode($request->getContent(), true);
|
||||||
|
|
||||||
|
$accessKey = $data['access_key'] ?? 'AKIA' . strtoupper(bin2hex(random_bytes(10)));
|
||||||
|
$secretKey = $data['secret_key'] ?? base64_encode(random_bytes(30));
|
||||||
|
$userName = $data['user_name'] ?? null;
|
||||||
|
|
||||||
|
$credential = $this->s3Service->createCredential($accessKey, $secretKey, $userName);
|
||||||
|
|
||||||
|
return new JsonResponse([
|
||||||
|
'id' => $credential->getId(),
|
||||||
|
'access_key' => $credential->getAccessKey(),
|
||||||
|
'secret_key' => $credential->getSecretKey(),
|
||||||
|
'user_name' => $credential->getUserName(),
|
||||||
|
'is_active' => $credential->isActive(),
|
||||||
|
'created_at' => $credential->getCreatedAt()->format('Y-m-d H:i:s')
|
||||||
|
], 201);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCredential(int $id, Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
$authResp = $this->checkAuth($request);
|
$authResp = $this->checkAuth($request);
|
||||||
if ($authResp !== null) {
|
if ($authResp !== null) {
|
||||||
@@ -85,117 +88,138 @@ 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(),
|
'secret_key' => $credential->getSecretKey(),
|
||||||
'secret_key' => $credential->getSecretKey(),
|
'user_name' => $credential->getUserName(),
|
||||||
'user_name' => $credential->getUserName(),
|
'is_active' => $credential->isActive(),
|
||||||
'is_active' => $credential->isActive(),
|
'created_at' => $credential->getCreatedAt()->format('Y-m-d H:i:s'),
|
||||||
'created_at' => $credential->getCreatedAt()->format('Y-m-d H:i:s'),
|
'buckets' => array_map(function($bucket) {
|
||||||
'buckets' => array_map(function($bucket) {
|
return [
|
||||||
return [
|
'name' => $bucket->getName(),
|
||||||
'name' => $bucket->getName(),
|
'region' => $bucket->getRegion(),
|
||||||
'region' => $bucket->getRegion(),
|
'created_at' => $bucket->getCreatedAt()->format('Y-m-d H:i:s')
|
||||||
'created_at' => $bucket->getCreatedAt()->format('Y-m-d H:i:s')
|
];
|
||||||
];
|
}, $credential->getBuckets()->toArray())
|
||||||
}, $credential->getBuckets()->toArray())
|
]);
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($request->getMethod() === 'PUT') {
|
|
||||||
$data = json_decode($request->getContent(), true);
|
|
||||||
|
|
||||||
if (isset($data['user_name'])) {
|
|
||||||
$credential->setUserName($data['user_name']);
|
|
||||||
}
|
|
||||||
if (isset($data['is_active'])) {
|
|
||||||
$credential->setIsActive($data['is_active']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->entityManager->flush();
|
|
||||||
|
|
||||||
return new JsonResponse(['message' => 'Credential updated']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($request->getMethod() === 'DELETE') {
|
|
||||||
$this->entityManager->remove($credential);
|
|
||||||
$this->entityManager->flush();
|
|
||||||
|
|
||||||
return new JsonResponse(['message' => 'Credential deleted']);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new JsonResponse(['error' => 'Method not allowed'], 405);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Buckets Management
|
public function updateCredential(int $id, Request $request): JsonResponse
|
||||||
public function buckets(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') {
|
$credential = $this->entityManager->getRepository(S3Credential::class)->find($id);
|
||||||
$buckets = $this->entityManager->getRepository(S3Bucket::class)->findAll();
|
|
||||||
|
|
||||||
return new JsonResponse([
|
if (!$credential) {
|
||||||
'buckets' => array_map(function($bucket) {
|
return new JsonResponse(['error' => 'Credential not found'], 404);
|
||||||
$objectCount = $this->entityManager->getRepository(S3Object::class)->count(['bucket' => $bucket]);
|
|
||||||
$totalSize = $this->entityManager->createQueryBuilder()
|
|
||||||
->select('SUM(o.size)')
|
|
||||||
->from(S3Object::class, 'o')
|
|
||||||
->where('o.bucket = :bucket')
|
|
||||||
->setParameter('bucket', $bucket)
|
|
||||||
->getQuery()
|
|
||||||
->getSingleScalarResult() ?: 0;
|
|
||||||
|
|
||||||
return [
|
|
||||||
'name' => $bucket->getName(),
|
|
||||||
'region' => $bucket->getRegion(),
|
|
||||||
'owner' => $bucket->getOwner()->getUserName() ?: $bucket->getOwner()->getAccessKey(),
|
|
||||||
'created_at' => $bucket->getCreatedAt()->format('Y-m-d H:i:s'),
|
|
||||||
'object_count' => $objectCount,
|
|
||||||
'total_size' => $totalSize,
|
|
||||||
'total_size_human' => $this->formatBytes($totalSize)
|
|
||||||
];
|
|
||||||
}, $buckets)
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->getMethod() === 'POST') {
|
$data = json_decode($request->getContent(), true);
|
||||||
$data = json_decode($request->getContent(), true);
|
|
||||||
|
|
||||||
$bucketName = $data['name'] ?? null;
|
if (isset($data['user_name'])) {
|
||||||
$ownerId = $data['owner_id'] ?? null;
|
$credential->setUserName($data['user_name']);
|
||||||
$region = $data['region'] ?? ($_ENV['APP_REGION'] ?? 'us-east-1');
|
}
|
||||||
|
if (isset($data['is_active'])) {
|
||||||
|
$credential->setIsActive($data['is_active']);
|
||||||
|
}
|
||||||
|
|
||||||
if (!$bucketName || !$ownerId) {
|
$this->entityManager->flush();
|
||||||
return new JsonResponse(['error' => 'Missing bucket name or owner'], 400);
|
|
||||||
}
|
|
||||||
|
|
||||||
$owner = $this->entityManager->getRepository(S3Credential::class)->find($ownerId);
|
return new JsonResponse(['message' => 'Credential updated']);
|
||||||
if (!$owner) {
|
}
|
||||||
return new JsonResponse(['error' => 'Owner not found'], 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
public function deleteCredential(int $id, Request $request): JsonResponse
|
||||||
$bucket = $this->s3Service->createBucket($bucketName, $owner, $region);
|
{
|
||||||
|
$authResp = $this->checkAuth($request);
|
||||||
|
if ($authResp !== null) {
|
||||||
|
return $authResp;
|
||||||
|
}
|
||||||
|
$credential = $this->entityManager->getRepository(S3Credential::class)->find($id);
|
||||||
|
|
||||||
return new JsonResponse([
|
if (!$credential) {
|
||||||
|
return new JsonResponse(['error' => 'Credential not found'], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->entityManager->remove($credential);
|
||||||
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
return new JsonResponse(['message' => 'Credential deleted']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buckets Management
|
||||||
|
public function listBuckets(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$authResp = $this->checkAuth($request);
|
||||||
|
if ($authResp !== null) {
|
||||||
|
return $authResp;
|
||||||
|
}
|
||||||
|
|
||||||
|
$buckets = $this->entityManager->getRepository(S3Bucket::class)->findAll();
|
||||||
|
|
||||||
|
return new JsonResponse([
|
||||||
|
'buckets' => array_map(function($bucket) {
|
||||||
|
$objectCount = $this->entityManager->getRepository(S3Object::class)->count(['bucket' => $bucket]);
|
||||||
|
$totalSize = $this->entityManager->createQueryBuilder()
|
||||||
|
->select('SUM(o.size)')
|
||||||
|
->from(S3Object::class, 'o')
|
||||||
|
->where('o.bucket = :bucket')
|
||||||
|
->setParameter('bucket', $bucket)
|
||||||
|
->getQuery()
|
||||||
|
->getSingleScalarResult() ?: 0;
|
||||||
|
|
||||||
|
return [
|
||||||
'name' => $bucket->getName(),
|
'name' => $bucket->getName(),
|
||||||
'region' => $bucket->getRegion(),
|
'region' => $bucket->getRegion(),
|
||||||
'owner' => $bucket->getOwner()->getUserName() ?: $bucket->getOwner()->getAccessKey(),
|
'owner' => $bucket->getOwner()->getUserName() ?: $bucket->getOwner()->getAccessKey(),
|
||||||
'created_at' => $bucket->getCreatedAt()->format('Y-m-d H:i:s')
|
'created_at' => $bucket->getCreatedAt()->format('Y-m-d H:i:s'),
|
||||||
], 201);
|
'object_count' => $objectCount,
|
||||||
} catch (\Exception $e) {
|
'total_size' => $totalSize,
|
||||||
return new JsonResponse(['error' => $e->getMessage()], 400);
|
'total_size_human' => $this->formatBytes($totalSize)
|
||||||
}
|
];
|
||||||
}
|
}, $buckets)
|
||||||
|
]);
|
||||||
return new JsonResponse(['error' => 'Method not allowed'], 405);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function bucketDetail(string $name, Request $request): JsonResponse
|
public function createBucket(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$authResp = $this->checkAuth($request);
|
||||||
|
if ($authResp !== null) {
|
||||||
|
return $authResp;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = json_decode($request->getContent(), true);
|
||||||
|
|
||||||
|
$bucketName = $data['name'] ?? null;
|
||||||
|
$ownerId = $data['owner_id'] ?? null;
|
||||||
|
$region = $data['region'] ?? ($_ENV['APP_REGION'] ?? 'us-east-1');
|
||||||
|
|
||||||
|
if (!$bucketName || !$ownerId) {
|
||||||
|
return new JsonResponse(['error' => 'Missing bucket name or owner'], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$owner = $this->entityManager->getRepository(S3Credential::class)->find($ownerId);
|
||||||
|
if (!$owner) {
|
||||||
|
return new JsonResponse(['error' => 'Owner not found'], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$bucket = $this->s3Service->createBucket($bucketName, $owner, $region);
|
||||||
|
|
||||||
|
return new JsonResponse([
|
||||||
|
'name' => $bucket->getName(),
|
||||||
|
'region' => $bucket->getRegion(),
|
||||||
|
'owner' => $bucket->getOwner()->getUserName() ?: $bucket->getOwner()->getAccessKey(),
|
||||||
|
'created_at' => $bucket->getCreatedAt()->format('Y-m-d H:i:s')
|
||||||
|
], 201);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return new JsonResponse(['error' => $e->getMessage()], 400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBucket(string $name, Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
$authResp = $this->checkAuth($request);
|
$authResp = $this->checkAuth($request);
|
||||||
if ($authResp !== null) {
|
if ($authResp !== null) {
|
||||||
@@ -207,46 +231,53 @@ 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));
|
|
||||||
|
|
||||||
return new JsonResponse([
|
return new JsonResponse([
|
||||||
'name' => $bucket->getName(),
|
'name' => $bucket->getName(),
|
||||||
'region' => $bucket->getRegion(),
|
'region' => $bucket->getRegion(),
|
||||||
'owner' => $bucket->getOwner()->getUserName() ?: $bucket->getOwner()->getAccessKey(),
|
'owner' => $bucket->getOwner()->getUserName() ?: $bucket->getOwner()->getAccessKey(),
|
||||||
'created_at' => $bucket->getCreatedAt()->format('Y-m-d H:i:s'),
|
'created_at' => $bucket->getCreatedAt()->format('Y-m-d H:i:s'),
|
||||||
'object_count' => count($objects),
|
'object_count' => count($objects),
|
||||||
'total_size' => $totalSize,
|
'total_size' => $totalSize,
|
||||||
'total_size_human' => $this->formatBytes($totalSize),
|
'total_size_human' => $this->formatBytes($totalSize),
|
||||||
'objects' => array_map(function($obj) {
|
'objects' => array_map(function($obj) {
|
||||||
return [
|
return [
|
||||||
'key' => $obj->getObjectKey(),
|
'key' => $obj->getObjectKey(),
|
||||||
'size' => $obj->getSize(),
|
'size' => $obj->getSize(),
|
||||||
'size_human' => $this->formatBytes($obj->getSize()),
|
'size_human' => $this->formatBytes($obj->getSize()),
|
||||||
'content_type' => $obj->getContentType(),
|
'content_type' => $obj->getContentType(),
|
||||||
'etag' => $obj->getEtag(),
|
'etag' => $obj->getEtag(),
|
||||||
'is_multipart' => $obj->isMultipart(),
|
'is_multipart' => $obj->isMultipart(),
|
||||||
'created_at' => $obj->getCreatedAt()->format('Y-m-d H:i:s')
|
'created_at' => $obj->getCreatedAt()->format('Y-m-d H:i:s')
|
||||||
];
|
];
|
||||||
}, $objects)
|
}, $objects)
|
||||||
]);
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->getMethod() === 'DELETE') {
|
try {
|
||||||
try {
|
$this->s3Service->deleteBucket($bucket);
|
||||||
$this->s3Service->deleteBucket($bucket);
|
return new JsonResponse(['message' => 'Bucket deleted']);
|
||||||
return new JsonResponse(['message' => 'Bucket deleted']);
|
} catch (\Exception $e) {
|
||||||
} catch (\Exception $e) {
|
return new JsonResponse(['error' => $e->getMessage()], 400);
|
||||||
return new JsonResponse(['error' => $e->getMessage()], 400);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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,73 +289,91 @@ 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);
|
|
||||||
|
|
||||||
return new JsonResponse([
|
return new JsonResponse([
|
||||||
'objects' => array_map(function($obj) {
|
'objects' => array_map(function($obj) {
|
||||||
return [
|
return [
|
||||||
'key' => $obj->getObjectKey(),
|
'key' => $obj->getObjectKey(),
|
||||||
'size' => $obj->getSize(),
|
'size' => $obj->getSize(),
|
||||||
'size_human' => $this->formatBytes($obj->getSize()),
|
'size_human' => $this->formatBytes($obj->getSize()),
|
||||||
'content_type' => $obj->getContentType(),
|
'content_type' => $obj->getContentType(),
|
||||||
'etag' => $obj->getEtag(),
|
'etag' => $obj->getEtag(),
|
||||||
'is_multipart' => $obj->isMultipart(),
|
'is_multipart' => $obj->isMultipart(),
|
||||||
'created_at' => $obj->getCreatedAt()->format('Y-m-d H:i:s')
|
'created_at' => $obj->getCreatedAt()->format('Y-m-d H:i:s')
|
||||||
];
|
];
|
||||||
}, $objects)
|
}, $objects)
|
||||||
]);
|
]);
|
||||||
}
|
|
||||||
|
|
||||||
if ($request->getMethod() === 'POST') {
|
|
||||||
$objectKey = $request->headers->get('X-Object-Key')
|
|
||||||
?? $request->query->get('key')
|
|
||||||
?? $request->request->get('object_key');
|
|
||||||
|
|
||||||
if (empty($objectKey)) {
|
|
||||||
return new JsonResponse(['error' => 'Missing object key'], 400);
|
|
||||||
}
|
|
||||||
|
|
||||||
$contentType = $request->headers->get('Content-Type', 'application/octet-stream');
|
|
||||||
$file = $request->files->get('file');
|
|
||||||
if ($file instanceof \Symfony\Component\HttpFoundation\File\UploadedFile) {
|
|
||||||
$contentType = $file->getMimeType() ?: $contentType;
|
|
||||||
$content = file_get_contents($file->getPathname());
|
|
||||||
} else {
|
|
||||||
$content = $request->getContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
$object = $this->s3Service->putObject($bucket, $objectKey, $content, $contentType);
|
|
||||||
|
|
||||||
return new JsonResponse([
|
|
||||||
'key' => $object->getObjectKey(),
|
|
||||||
'etag' => $object->getEtag(),
|
|
||||||
'size' => $object->getSize(),
|
|
||||||
'content_type' => $object->getContentType()
|
|
||||||
], 201);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($request->getMethod() === 'DELETE') {
|
|
||||||
$data = json_decode($request->getContent(), true);
|
|
||||||
$keys = $data['keys'] ?? [];
|
|
||||||
|
|
||||||
$deleted = [];
|
|
||||||
foreach ($keys as $key) {
|
|
||||||
$object = $this->s3Service->findObject($bucket, $key);
|
|
||||||
if ($object) {
|
|
||||||
$this->s3Service->deleteObject($object);
|
|
||||||
$deleted[] = $key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new JsonResponse(['deleted' => $deleted]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new JsonResponse(['error' => 'Method not allowed'], 405);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function objectDetail(string $bucketName, string $objectKey, Request $request): JsonResponse
|
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')
|
||||||
|
?? $request->query->get('key')
|
||||||
|
?? $request->request->get('object_key');
|
||||||
|
|
||||||
|
if (empty($objectKey)) {
|
||||||
|
return new JsonResponse(['error' => 'Missing object key'], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$contentType = $request->headers->get('Content-Type', 'application/octet-stream');
|
||||||
|
$file = $request->files->get('file');
|
||||||
|
if ($file instanceof \Symfony\Component\HttpFoundation\File\UploadedFile) {
|
||||||
|
$contentType = $file->getMimeType() ?: $contentType;
|
||||||
|
$content = file_get_contents($file->getPathname());
|
||||||
|
} else {
|
||||||
|
$content = $request->getContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
$object = $this->s3Service->putObject($bucket, $objectKey, $content, $contentType);
|
||||||
|
|
||||||
|
return new JsonResponse([
|
||||||
|
'key' => $object->getObjectKey(),
|
||||||
|
'etag' => $object->getEtag(),
|
||||||
|
'size' => $object->getSize(),
|
||||||
|
'content_type' => $object->getContentType()
|
||||||
|
], 201);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
$keys = $data['keys'] ?? [];
|
||||||
|
|
||||||
|
$deleted = [];
|
||||||
|
foreach ($keys as $key) {
|
||||||
|
$object = $this->s3Service->findObject($bucket, $key);
|
||||||
|
if ($object) {
|
||||||
|
$this->s3Service->deleteObject($object);
|
||||||
|
$deleted[] = $key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new JsonResponse(['deleted' => $deleted]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getObject(string $bucketName, string $objectKey, Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
$authResp = $this->checkAuth($request);
|
$authResp = $this->checkAuth($request);
|
||||||
if ($authResp !== null) {
|
if ($authResp !== null) {
|
||||||
@@ -342,28 +391,41 @@ 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(),
|
'size_human' => $this->formatBytes($object->getSize()),
|
||||||
'size_human' => $this->formatBytes($object->getSize()),
|
'content_type' => $object->getContentType(),
|
||||||
'content_type' => $object->getContentType(),
|
'etag' => $object->getEtag(),
|
||||||
'etag' => $object->getEtag(),
|
'is_multipart' => $object->isMultipart(),
|
||||||
'is_multipart' => $object->isMultipart(),
|
'part_count' => $object->getPartCount(),
|
||||||
'part_count' => $object->getPartCount(),
|
'metadata' => $object->getMetadata(),
|
||||||
'metadata' => $object->getMetadata(),
|
'storage_path' => $object->getStoragePath(),
|
||||||
'storage_path' => $object->getStoragePath(),
|
'created_at' => $object->getCreatedAt()->format('Y-m-d H:i:s'),
|
||||||
'created_at' => $object->getCreatedAt()->format('Y-m-d H:i:s'),
|
'updated_at' => $object->getUpdatedAt()->format('Y-m-d H:i:s')
|
||||||
'updated_at' => $object->getUpdatedAt()->format('Y-m-d H:i:s')
|
]);
|
||||||
]);
|
}
|
||||||
|
|
||||||
|
public function deleteObject(string $bucketName, string $objectKey, 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->getMethod() === 'DELETE') {
|
$object = $this->s3Service->findObject($bucket, $objectKey);
|
||||||
$this->s3Service->deleteObject($object);
|
|
||||||
return new JsonResponse(['message' => 'Object deleted']);
|
if (!$object) {
|
||||||
|
return new JsonResponse(['error' => 'Object not found'], 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new JsonResponse(['error' => 'Method not allowed'], 405);
|
$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,61 +497,64 @@ 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)
|
|
||||||
->createQueryBuilder('p')
|
|
||||||
->where('p.expiresAt > :now')
|
|
||||||
->setParameter('now', new \DateTime())
|
|
||||||
->orderBy('p.createdAt', 'DESC')
|
|
||||||
->setMaxResults(100)
|
|
||||||
->getQuery()
|
|
||||||
->getResult();
|
|
||||||
|
|
||||||
return new JsonResponse([
|
$urls = $this->entityManager->getRepository(\App\Entity\S3PresignedUrl::class)
|
||||||
'urls' => array_map(function($url) {
|
->createQueryBuilder('p')
|
||||||
return [
|
->where('p.expiresAt > :now')
|
||||||
'bucket_name' => $url->getBucketName(),
|
->setParameter('now', new \DateTime())
|
||||||
'object_key' => $url->getObjectKey(),
|
->orderBy('p.createdAt', 'DESC')
|
||||||
'method' => $url->getMethod(),
|
->setMaxResults(100)
|
||||||
'access_key' => $url->getAccessKey(),
|
->getQuery()
|
||||||
'expires_at' => $url->getExpiresAt()->format('Y-m-d H:i:s'),
|
->getResult();
|
||||||
'created_at' => $url->getCreatedAt()->format('Y-m-d H:i:s'),
|
|
||||||
'url' => $url->getUrl()
|
return new JsonResponse([
|
||||||
];
|
'urls' => array_map(function($url) {
|
||||||
}, $urls)
|
return [
|
||||||
]);
|
'bucket_name' => $url->getBucketName(),
|
||||||
|
'object_key' => $url->getObjectKey(),
|
||||||
|
'method' => $url->getMethod(),
|
||||||
|
'access_key' => $url->getAccessKey(),
|
||||||
|
'expires_at' => $url->getExpiresAt()->format('Y-m-d H:i:s'),
|
||||||
|
'created_at' => $url->getCreatedAt()->format('Y-m-d H:i:s'),
|
||||||
|
'url' => $url->getUrl()
|
||||||
|
];
|
||||||
|
}, $urls)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createPresignedUrl(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$authResp = $this->checkAuth($request);
|
||||||
|
if ($authResp !== null) {
|
||||||
|
return $authResp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->getMethod() === 'POST') {
|
$data = json_decode($request->getContent(), true);
|
||||||
$data = json_decode($request->getContent(), true);
|
|
||||||
|
|
||||||
$bucketName = $data['bucket_name'] ?? null;
|
$bucketName = $data['bucket_name'] ?? null;
|
||||||
$objectKey = $data['object_key'] ?? null;
|
$objectKey = $data['object_key'] ?? null;
|
||||||
$method = $data['method'] ?? 'GET';
|
$method = $data['method'] ?? 'GET';
|
||||||
$expiresIn = $data['expires_in'] ?? 3600;
|
$expiresIn = $data['expires_in'] ?? 3600;
|
||||||
$accessKey = $data['access_key'] ?? null;
|
$accessKey = $data['access_key'] ?? null;
|
||||||
|
|
||||||
if (!$bucketName || !$objectKey || !$accessKey) {
|
if (!$bucketName || !$objectKey || !$accessKey) {
|
||||||
return new JsonResponse(['error' => 'Missing required fields'], 400);
|
return new JsonResponse(['error' => 'Missing required fields'], 400);
|
||||||
}
|
|
||||||
|
|
||||||
$credential = $this->s3Service->findCredentialByAccessKey($accessKey);
|
|
||||||
if (!$credential) {
|
|
||||||
return new JsonResponse(['error' => 'Invalid access key'], 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
$url = $this->s3Service->generatePresignedUrl($bucketName, $objectKey, $credential, $method, $expiresIn);
|
|
||||||
|
|
||||||
return new JsonResponse(['url' => $url], 201);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new JsonResponse(['error' => 'Method not allowed'], 405);
|
$credential = $this->s3Service->findCredentialByAccessKey($accessKey);
|
||||||
|
if (!$credential) {
|
||||||
|
return new JsonResponse(['error' => 'Invalid access key'], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$url = $this->s3Service->generatePresignedUrl($bucketName, $objectKey, $credential, $method, $expiresIn);
|
||||||
|
|
||||||
|
return new JsonResponse(['url' => $url], 201);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Statistics
|
// Statistics
|
||||||
|
|||||||
@@ -18,28 +18,32 @@ 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')) {
|
if ($request->getSession()->get('console_logged_in')) {
|
||||||
return new RedirectResponse('/console');
|
return new RedirectResponse('/console');
|
||||||
}
|
}
|
||||||
|
|
||||||
$error = null;
|
return $this->render('console/login.html.twig', ['error' => null]);
|
||||||
if ($request->isMethod('POST')) {
|
}
|
||||||
$user = $request->request->get('username');
|
|
||||||
$pass = $request->request->get('password');
|
|
||||||
$envUser = $_ENV['CONSOLE_USER'] ?? 'admin';
|
|
||||||
$envPass = $_ENV['CONSOLE_PASS'] ?? 'password';
|
|
||||||
|
|
||||||
if ($user === $envUser && $pass === $envPass) {
|
public function loginSubmit(Request $request): Response
|
||||||
$request->getSession()->set('console_logged_in', true);
|
{
|
||||||
return new RedirectResponse('/console');
|
if ($request->getSession()->get('console_logged_in')) {
|
||||||
}
|
return new RedirectResponse('/console');
|
||||||
|
|
||||||
$error = 'Invalid credentials';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->render('console/login.html.twig', ['error' => $error]);
|
$user = $request->request->get('username');
|
||||||
|
$pass = $request->request->get('password');
|
||||||
|
$envUser = $_ENV['CONSOLE_USER'] ?? 'admin';
|
||||||
|
$envPass = $_ENV['CONSOLE_PASS'] ?? 'password';
|
||||||
|
|
||||||
|
if ($user === $envUser && $pass === $envPass) {
|
||||||
|
$request->getSession()->set('console_logged_in', true);
|
||||||
|
return new RedirectResponse('/console');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render('console/login.html.twig', ['error' => 'Invalid credentials']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function logout(Request $request): Response
|
public function logout(Request $request): Response
|
||||||
|
|||||||
Reference in New Issue
Block a user