diff --git a/app/Http/Controllers/PostController.php b/app/Http/Controllers/PostController.php index eafc6995..26c7bec8 100644 --- a/app/Http/Controllers/PostController.php +++ b/app/Http/Controllers/PostController.php @@ -9,6 +9,7 @@ use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\View\View; +use Symfony\Component\HttpFoundation\BinaryFileResponse; use Symfony\Component\HttpFoundation\StreamedResponse; class PostController extends Controller @@ -268,7 +269,7 @@ public function uploadFiles(Board $board, Post $post, Request $request): JsonRes /** * 파일 다운로드 */ - public function downloadFile(Board $board, Post $post, int $fileId): StreamedResponse|RedirectResponse + public function downloadFile(Board $board, Post $post, int $fileId): BinaryFileResponse|StreamedResponse|RedirectResponse { // 게시판 일치 확인 if ($post->board_id !== $board->id) { @@ -283,6 +284,24 @@ public function downloadFile(Board $board, Post $post, int $fileId): StreamedRes return $this->postService->downloadFile($post, $fileId); } + /** + * 파일 미리보기 (이미지 인라인 표시) + */ + public function previewFile(Board $board, Post $post, int $fileId): BinaryFileResponse|StreamedResponse|RedirectResponse + { + // 게시판 일치 확인 + if ($post->board_id !== $board->id) { + abort(404); + } + + // 비밀글 접근 권한 확인 + if (! $post->canAccess(auth()->user())) { + return back()->with('error', '파일에 접근할 수 없습니다.'); + } + + return $this->postService->previewFile($post, $fileId); + } + /** * 파일 삭제 (AJAX) */ diff --git a/app/Models/Boards/File.php b/app/Models/Boards/File.php index cf8beb16..cc700d39 100644 --- a/app/Models/Boards/File.php +++ b/app/Models/Boards/File.php @@ -45,6 +45,10 @@ class File extends Model 'file_size', 'mime_type', 'file_type', + // New fields (API 방식) + 'document_id', + 'document_type', + // Legacy fields (하위 호환) 'fileable_id', 'fileable_type', 'description', @@ -219,4 +223,13 @@ public function scopeNonTemp($query) { return $query->where('is_temp', false); } + + /** + * 특정 문서의 파일들 + */ + public function scopeForDocument($query, int $documentId, string $documentType) + { + return $query->where('document_id', $documentId) + ->where('document_type', $documentType); + } } diff --git a/app/Models/Boards/Post.php b/app/Models/Boards/Post.php index 1632f7c8..db4a16be 100644 --- a/app/Models/Boards/Post.php +++ b/app/Models/Boards/Post.php @@ -8,7 +8,6 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; -use Illuminate\Database\Eloquent\Relations\MorphMany; use Illuminate\Database\Eloquent\SoftDeletes; /** @@ -138,11 +137,12 @@ public function customFieldValues(): HasMany } /** - * 첨부파일 (Polymorphic) + * 첨부파일 (document_id + document_type 기반) */ - public function files(): MorphMany + public function files(): HasMany { - return $this->morphMany(File::class, 'fileable'); + return $this->hasMany(File::class, 'document_id') + ->where('document_type', 'post'); } // ========================================================================= diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 92e86da8..ff8e9220 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -2,6 +2,8 @@ namespace App\Providers; +use App\Models\Boards\Post; +use App\Models\Tenants\Department; use App\Models\User; use App\Services\SidebarMenuService; use Illuminate\Database\Eloquent\Relations\Relation; @@ -24,9 +26,11 @@ public function register(): void */ public function boot(): void { - // Morph Map: mng/api 프로젝트 간 User 모델 경로 통일 + // Morph Map: Polymorphic 관계 모델 등록 Relation::enforceMorphMap([ 'user' => User::class, + 'post' => Post::class, + 'department' => Department::class, ]); // 사이드바에 메뉴 데이터 전달 diff --git a/app/Services/PostService.php b/app/Services/PostService.php index 95df2e60..2c6bfaa0 100644 --- a/app/Services/PostService.php +++ b/app/Services/PostService.php @@ -257,7 +257,7 @@ public function uploadFiles(Post $post, array $files): array // 파일 저장 Storage::disk('tenant')->put($filePath, file_get_contents($file)); - // DB 레코드 생성 + // DB 레코드 생성 (API 방식: document_id + document_type) $fileRecord = File::create([ 'tenant_id' => $tenantId, 'is_temp' => false, @@ -269,8 +269,8 @@ public function uploadFiles(Post $post, array $files): array 'file_size' => $file->getSize(), 'mime_type' => $file->getMimeType(), 'file_type' => $this->getFileType($file->getMimeType()), - 'fileable_type' => Post::class, - 'fileable_id' => $post->id, + 'document_type' => 'post', + 'document_id' => $post->id, 'uploaded_by' => auth()->id(), 'created_by' => auth()->id(), ]); @@ -381,4 +381,24 @@ public function downloadFile(Post $post, int $fileId) return $file->download(); } + + /** + * 파일 미리보기 (인라인 표시) + */ + public function previewFile(Post $post, int $fileId) + { + $file = $post->files()->find($fileId); + + if (! $file) { + abort(404, '파일을 찾을 수 없습니다.'); + } + + if (! $file->existsInStorage()) { + abort(404, '파일을 찾을 수 없습니다.'); + } + + return response()->file($file->getStoragePath(), [ + 'Content-Type' => $file->mime_type, + ]); + } } diff --git a/resources/views/posts/show.blade.php b/resources/views/posts/show.blade.php index eef0ba4d..d57b1135 100644 --- a/resources/views/posts/show.blade.php +++ b/resources/views/posts/show.blade.php @@ -87,6 +87,27 @@ function confirmDeletePost() { @endif + + @php + $imageFiles = $post->files->filter(fn($file) => $file->isImage()); + $otherFiles = $post->files->filter(fn($file) => !$file->isImage()); + @endphp + @if($imageFiles->isNotEmpty()) +
+
+ @foreach($imageFiles as $file) + + {{ $file->display_name ?? $file->original_name }} + + @endforeach +
+
+ @endif +
@@ -94,25 +115,19 @@ function confirmDeletePost() {
- - @if($post->files->isNotEmpty()) + + @if($otherFiles->isNotEmpty())

- 첨부파일 ({{ $post->files->count() }}개) + 첨부파일 ({{ $otherFiles->count() }}개)

- @foreach($post->files as $file) + @foreach($otherFiles as $file)
- @if($file->isImage()) - - - - @else - - - - @endif + + +
{{ $file->display_name ?? $file->original_name }} ({{ $file->getFormattedSize() }}) diff --git a/routes/web.php b/routes/web.php index 4d8b226a..a4f07c4c 100644 --- a/routes/web.php +++ b/routes/web.php @@ -123,6 +123,7 @@ // 파일 관리 Route::prefix('{post}/files')->name('files.')->group(function () { Route::get('/{fileId}/download', [PostController::class, 'downloadFile'])->name('download'); + Route::get('/{fileId}/preview', [PostController::class, 'previewFile'])->name('preview'); Route::post('/', [PostController::class, 'uploadFiles'])->name('upload'); Route::delete('/{fileId}', [PostController::class, 'deleteFile'])->name('delete'); });