From 1e7a84d5160952ccf184475465e2c031ff445ad8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=ED=98=81=EC=84=B1?= Date: Fri, 20 Mar 2026 11:24:24 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20[file]=20path=20=EA=B8=B0=EB=B0=98=20pr?= =?UTF-8?q?esigned=20URL=20=EC=97=94=EB=93=9C=ED=8F=AC=EC=9D=B8=ED=8A=B8?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - POST /api/v1/files/presigned-url-by-path 추가 - file_id 없이 image_path만 있는 레거시 데이터 지원 --- .../Controllers/Api/V1/FileStorageController.php | 15 +++++++++++++++ routes/api/v1/files.php | 1 + 2 files changed, 16 insertions(+) diff --git a/app/Http/Controllers/Api/V1/FileStorageController.php b/app/Http/Controllers/Api/V1/FileStorageController.php index 71076d73..35b23dca 100644 --- a/app/Http/Controllers/Api/V1/FileStorageController.php +++ b/app/Http/Controllers/Api/V1/FileStorageController.php @@ -145,6 +145,21 @@ public function presignedUrl(int $id, Request $request) return ApiResponse::handle(fn () => ['url' => $url]); } + /** + * R2 Presigned URL 발급 (file_path 기반, 30분 유효) + */ + public function presignedUrlByPath(Request $request) + { + $path = $request->input('path'); + if (! $path) { + abort(400, 'path is required'); + } + + $url = Storage::disk('r2')->temporaryUrl($path, now()->addMinutes(30)); + + return ApiResponse::handle(fn () => ['url' => $url]); + } + /** * Soft delete file */ diff --git a/routes/api/v1/files.php b/routes/api/v1/files.php index bed1b821..6e483593 100644 --- a/routes/api/v1/files.php +++ b/routes/api/v1/files.php @@ -23,6 +23,7 @@ Route::get('/{id}/download', [FileStorageController::class, 'download'])->name('v1.files.download'); // 파일 다운로드 Route::get('/{id}/view', [FileStorageController::class, 'view'])->name('v1.files.view'); // 파일 인라인 보기 (이미지/PDF) Route::get('/{id}/presigned-url', [FileStorageController::class, 'presignedUrl'])->name('v1.files.presigned-url'); // R2 Presigned URL 발급 + Route::post('/presigned-url-by-path', [FileStorageController::class, 'presignedUrlByPath'])->name('v1.files.presigned-url-by-path'); // R2 Presigned URL (path 기반) Route::delete('/{id}', [FileStorageController::class, 'destroy'])->name('v1.files.destroy'); // 파일 삭제 (soft) Route::post('/{id}/restore', [FileStorageController::class, 'restore'])->name('v1.files.restore'); // 파일 복구 Route::delete('/{id}/permanent', [FileStorageController::class, 'permanentDelete'])->name('v1.files.permanent'); // 파일 영구 삭제