user(); assert($viewer !== null); Gate::forUser($viewer)->authorize('view', $file); return response()->json($this->payload($viewer, $file)); } public function store(Request $request, File $file): JsonResponse { $viewer = $request->user(); assert($viewer !== null); Gate::forUser($viewer)->authorize('view', $file); $validated = $request->validate([ 'body' => ['required', 'string', 'max:5000'], 'visibility' => ['required', Rule::enum(CommentVisibility::class)], 'reply_to' => ['nullable', 'integer'], ]); $this->comments->post( $file, $viewer, CommentVisibility::from($validated['visibility']), $validated['body'], $this->replyTarget($viewer, $file, $validated['reply_to'] ?? null), ); return response()->json($this->payload($viewer, $file), 201); } public function update(Request $request, FileComment $comment): JsonResponse { $viewer = $request->user(); assert($viewer !== null); Gate::forUser($viewer)->authorize('update', $comment); $validated = $request->validate(['body' => ['required', 'string', 'max:5000']]); $this->comments->edit($comment, $validated['body']); return response()->json($this->payload($viewer, $comment->file)); } public function destroy(Request $request, FileComment $comment): JsonResponse { $viewer = $request->user(); assert($viewer !== null); Gate::forUser($viewer)->authorize('delete', $comment); $file = $comment->file; $this->comments->remove($comment); return response()->json($this->payload($viewer, $file)); } /** * @return array */ private function payload(User $viewer, File $file): array { return $this->presenter->thread($viewer, $file); } /** * The comment being answered, resolved through the same scope that * decided what this viewer may read. A reply can therefore only ever * join a conversation they were already shown — an id they were not * given resolves to null and the comment is treated as a fresh one, * rather than 403ing on something they cannot be told exists. */ private function replyTarget(User $viewer, File $file, ?int $id): ?FileComment { if ($id === null) { return null; } return $this->scope->for($viewer, $file)->whereKey($id)->first(); } }