Merge pull request #7 from biondizzle/codex/build-presigned-url-upload-api

Add presigned upload support
This commit is contained in:
biondizzle
2025-06-05 19:44:22 -04:00
committed by GitHub
5 changed files with 135 additions and 4 deletions

View File

@@ -38,6 +38,14 @@ console_api_object_detail:
bucketName: '[a-z0-9\-\.]+'
objectKey: '.+'
console_api_presigned_upload:
path: /api/buckets/{bucketName}/objects/{objectKey}/presigned-upload
controller: App\Controller\ConsoleApiController::createPresignedUpload
methods: [POST]
requirements:
bucketName: '[a-z0-9\-\.]+'
objectKey: '.+'
console_api_multipart_uploads:
path: /api/buckets/{bucketName}/multipart-uploads
controller: App\Controller\ConsoleApiController::multipartUploads

View File

@@ -30,9 +30,9 @@ class ConsoleApiController extends AbstractController
// Credentials Management
public function credentials(Request $request): JsonResponse
{
$authResp = $this->checkAuth($request);
if ($authResp !== null) {
return $authResp;
$resp = $this->checkAuth($request);
if (!empty($resp)) {
return $resp;
}
if ($request->getMethod() === 'GET') {
$credentials = $this->entityManager->getRepository(S3Credential::class)->findAll();
@@ -338,6 +338,40 @@ class ConsoleApiController extends AbstractController
return new JsonResponse(['error' => 'Method not allowed'], 405);
}
public function createPresignedUpload(string $bucketName, string $objectKey, Request $request): JsonResponse
{
$resp = $this->checkAuth($request);
if (!empty($resp)) {
return $resp;
}
$bucket = $this->s3Service->findBucketByName($bucketName);
if (!$bucket) {
return new JsonResponse(['error' => 'Bucket not found'], 404);
}
$data = json_decode($request->getContent(), true);
$accessKey = $data['access_key'] ?? null;
$expiresIn = $data['expires_in'] ?? 3600;
$contentType = $data['content_type'] ?? 'application/octet-stream';
if (!$accessKey) {
return new JsonResponse(['error' => 'Missing access key'], 400);
}
$credential = $this->s3Service->findCredentialByAccessKey($accessKey);
if (!$credential) {
return new JsonResponse(['error' => 'Invalid access key'], 404);
}
// Create placeholder object
$this->s3Service->putObject($bucket, $objectKey, '', $contentType);
$url = $this->s3Service->generatePresignedUrl($bucketName, $objectKey, $credential, 'PUT', $expiresIn);
return new JsonResponse(['url' => $url], 201);
}
// Multipart Uploads
public function multipartUploads(string $bucketName, Request $request): JsonResponse
{
@@ -476,4 +510,4 @@ class ConsoleApiController extends AbstractController
return round($bytes / pow(1024, $i), 2) . ' ' . $units[$i];
}
}
}

View File

@@ -589,6 +589,32 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/CreatePresignedUrlResponse'
/api/buckets/{bucketName}/objects/{objectKey}/presigned-upload:
parameters:
- $ref: '#/components/parameters/BucketName'
- $ref: '#/components/parameters/ObjectKey'
post:
operationId: createPresignedUpload
tags:
- Management - Presigned URLs
summary: Create presigned upload URL
description: Creates an empty object and returns a presigned URL for uploading content
security:
- ApiKey: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreatePresignedUploadRequest'
responses:
'201':
description: Presigned URL created
content:
application/json:
schema:
$ref: '#/components/schemas/CreatePresignedUrlResponse'
components:
schemas:
CreatePresignedUrlResponse:
@@ -597,6 +623,24 @@ components:
url:
type: string
example: /my-bucket/file.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20230115%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20230115T103000Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=abc123&hash=def456
CreatePresignedUploadRequest:
type: object
required:
- access_key
properties:
access_key:
type: string
example: "AKIAIOSFODNN7EXAMPLE"
expires_in:
type: integer
minimum: 1
maximum: 604800
default: 3600
example: 3600
content_type:
type: string
default: "application/octet-stream"
example: "image/jpeg"
ObjectSummary:
type: object
properties:

View File

@@ -573,6 +573,32 @@
application/json:
schema:
$ref: './schemas.yaml#/CreatePresignedUrlRequest'
responses:
'201':
description: Presigned URL created
content:
application/json:
schema:
$ref: './schemas.yaml#/CreatePresignedUrlResponse'
/api/buckets/{bucketName}/objects/{objectKey}/presigned-upload:
parameters:
- $ref: './parameters.yaml#/BucketName'
- $ref: './parameters.yaml#/ObjectKey'
post:
operationId: createPresignedUpload
tags:
- Management - Presigned URLs
summary: Create presigned upload URL
description: Creates an empty object and returns a presigned URL for uploading content
security:
- ApiKey: []
requestBody:
required: true
content:
application/json:
schema:
$ref: './schemas.yaml#/CreatePresignedUploadRequest'
responses:
'201':
description: Presigned URL created

View File

@@ -628,6 +628,25 @@ CreatePresignedUrlRequest:
type: string
example: "AKIAIOSFODNN7EXAMPLE"
CreatePresignedUploadRequest:
type: object
required:
- access_key
properties:
access_key:
type: string
example: "AKIAIOSFODNN7EXAMPLE"
expires_in:
type: integer
minimum: 1
maximum: 604800
default: 3600
example: 3600
content_type:
type: string
default: "application/octet-stream"
example: "image/jpeg"
CreatePresignedUrlResponse:
type: object
properties: