user()->tokenCan('press-releases:read'), 403); $pressRelease = $this->findOwnedPressRelease($pressRelease, $request); abort_unless($pressRelease !== null, 403); return PressReleaseImageResource::collection( $pressRelease->images()->orderBy('sort_order')->orderBy('id')->get() ); } public function store(StorePressReleaseImageRequest $request, int $pressRelease): JsonResponse { $pressRelease = $this->findOwnedPressRelease($pressRelease, $request); abort_unless($pressRelease !== null, 403); if (! $this->canChangeImages($pressRelease)) { return response()->json([ 'message' => 'Only draft or rejected press releases may be edited.', ], 409); } $validated = $request->validated(); /** @var UploadedFile $file */ $file = $request->file('image'); try { $stored = $this->imageService->storePressReleaseImage($file, $pressRelease->id); } catch (RuntimeException $exception) { return response()->json([ 'message' => $exception->getMessage(), ], 422); } if ((bool) ($validated['is_preview'] ?? false)) { $pressRelease->images()->update(['is_preview' => false]); } $image = $pressRelease->images()->create([ 'disk' => 'public', 'path' => $stored['path'], 'variants' => $stored['variants'], 'title' => $validated['title'] ?? null, 'description' => $validated['description'] ?? null, 'copyright' => $validated['copyright'] ?? null, 'is_preview' => (bool) ($validated['is_preview'] ?? false), 'sort_order' => ((int) $pressRelease->images()->max('sort_order')) + 1, 'width' => $stored['width'], 'height' => $stored['height'], 'mime' => $stored['mime'], ]); return PressReleaseImageResource::make($image) ->response() ->setStatusCode(201); } public function destroy(Request $request, int $pressReleaseImage): Response|JsonResponse { abort_unless($request->user()->tokenCan('press-release-images:write'), 403); $image = PressReleaseImage::query() ->whereKey($pressReleaseImage) ->whereHas('pressRelease', fn ($query) => $query->withoutGlobalScopes()->where('user_id', $request->user()->id)) ->with(['pressRelease' => fn ($query) => $query->withoutGlobalScopes()]) ->first(); abort_unless($image !== null, 403); if (! $this->canChangeImages($image->pressRelease)) { return response()->json([ 'message' => 'Only draft or rejected press releases may be edited.', ], 409); } $this->imageService->deletePressReleaseImage($image->disk, $image->path, $image->variants); $image->delete(); return response()->noContent(); } private function findOwnedPressRelease(int $pressReleaseId, Request $request): ?PressRelease { return PressRelease::withoutGlobalScopes() ->whereKey($pressReleaseId) ->where('user_id', $request->user()->id) ->first(); } private function canChangeImages(PressRelease $pressRelease): bool { $status = $pressRelease->status instanceof PressReleaseStatus ? $pressRelease->status->value : (string) $pressRelease->status; return in_array($status, [PressReleaseStatus::Draft->value, PressReleaseStatus::Rejected->value], true); } }