user(); $items = collect(); foreach (array_keys(AdminContent::REVIEWABLE) as $resource) { $model = AdminContent::model($resource); if ($user->cannot("{$resource}.publish")) { continue; } $model::query() ->awaitingReviewBy($user) ->with(['reviewRequester', 'reviewer']) ->get() ->each(fn (Model $record) => $items->push($this->summary($resource, $record))); } return response()->json([ 'data' => $items->sortBy('requested_at')->values(), ]); } /** * The thread: requests, returns, publications and comments, newest first. */ public function thread(Request $request): AnonymousResourceCollection { $record = $this->record($request); $this->authorize('view', $record); return ReviewCommentResource::collection( $record->reviewComments()->with('user')->paginate(perPage: min($request->integer('per_page', 25), 100)), ); } /** * Ask for it to be reviewed — the only way somebody without the publish * permission has of putting their work live. */ public function request(Request $request): JsonResponse { $record = $this->record($request); $this->authorize('update', $record); $data = $request->validate([ 'reviewer_id' => ['sometimes', 'nullable', 'integer', 'exists:users,id'], 'note' => ['sometimes', 'nullable', 'string', 'max:2000'], ]); if ($record->isAwaitingReview() || $record->isPublishedNow()) { throw ValidationException::withMessages(['review' => [__('rules.reviews.not_requestable')]]); } $reviewer = isset($data['reviewer_id']) ? User::find($data['reviewer_id']) : null; if ($reviewer !== null && $reviewer->cannot($record->getTable().'.publish')) { throw ValidationException::withMessages(['reviewer_id' => [__('rules.reviews.not_a_reviewer')]]); } $record->requestReview($reviewer, $data['note'] ?? null, $request->user()); return $this->answer($record); } /** * Send it back to whoever asked, saying why. */ public function return(Request $request): JsonResponse { $record = $this->record($request); $this->authorize($record->getTable().'.publish'); $data = $request->validate(['note' => ['required', 'string', 'max:2000']]); if (! $record->isAwaitingReview()) { throw ValidationException::withMessages(['review' => [__('rules.reviews.not_awaiting')]]); } $record->returnForChanges($data['note'], $request->user()); return $this->answer($record); } public function comment(Request $request): JsonResponse { $record = $this->record($request); $this->authorize('view', $record); $data = $request->validate(['body' => ['required', 'string', 'max:2000']]); return ReviewCommentResource::make($record->comment($data['body'], $request->user())->load('user')) ->response() ->setStatusCode(201); } /** * Approve: on the site now, or from `at`. Either way the review, if there * was one, is answered. */ public function publish(Request $request): JsonResponse { $record = $this->record($request); $this->authorize($record->getTable().'.publish'); $data = $request->validate(['at' => ['sometimes', 'nullable', 'date']]); Publisher::publish($record, filled($data['at'] ?? null) ? CarbonImmutable::parse($data['at']) : null); return $this->answer($record); } public function unpublish(Request $request): JsonResponse { $record = $this->record($request); $this->authorize($record->getTable().'.publish'); Publisher::unpublish($record); return $this->answer($record); } protected function answer(Model $record): JsonResponse { $record->refresh()->load(['reviewRequester', 'reviewer']); return response()->json(['data' => $this->summary(AdminContent::nameOf($record), $record)]); } /** * @return array */ protected function summary(string $resource, Model $record): array { return [ 'type' => $resource, 'id' => $record->getKey(), 'title' => ContentTypes::title($record), 'published' => $record->isPublishedNow(), 'published_at' => $record->published_at?->toIso8601String(), 'awaiting_review' => $record->isAwaitingReview(), 'requested_at' => $record->review_requested_at?->toIso8601String(), 'requested_by' => $record->reviewRequester ? ['id' => $record->reviewRequester->id, 'name' => $record->reviewRequester->name] : null, 'reviewer' => $record->reviewer ? ['id' => $record->reviewer->id, 'name' => $record->reviewer->name] : null, ]; } }