query('page', 1)); $comments = PostComment::with(['user', 'user.profile']) ->where('post_id', $post->id) ->orderByDesc('is_highlighted') // highlighted first ->orderBy('created_at') ->paginate(20, ['*'], 'page', $page); $formatted = $comments->getCollection()->map(fn ($c) => $this->formatComment($c)); return response()->json([ 'data' => $formatted, 'meta' => [ 'total' => $comments->total(), 'current_page' => $comments->currentPage(), 'last_page' => $comments->lastPage(), 'per_page' => $comments->perPage(), ], ]); } // ───────────────────────────────────────────────────────────────────────── // Store // ───────────────────────────────────────────────────────────────────────── public function store(CreateCommentRequest $request, int $postId): JsonResponse { $user = $request->user(); // Rate limit: 30 comments per hour $key = 'comment_post:' . $user->id; if (RateLimiter::tooManyAttempts($key, 30)) { $seconds = RateLimiter::availableIn($key); return response()->json([ 'message' => "You're commenting too quickly. Please wait {$seconds} seconds.", ], 429); } RateLimiter::hit($key, 3600); $post = Post::findOrFail($postId); $body = ContentSanitizer::render($request->input('body')); $comment = PostComment::create([ 'post_id' => $post->id, 'user_id' => $user->id, 'body' => $body, ]); $this->counters->incrementComments($post); // Fire event for notification if ($post->user_id !== $user->id) { event(new PostCommented($post, $comment, $user)); } $comment->load(['user', 'user.profile']); return response()->json(['comment' => $this->formatComment($comment)], 201); } // ───────────────────────────────────────────────────────────────────────── // Destroy // ───────────────────────────────────────────────────────────────────────── public function destroy(Request $request, int $postId, int $commentId): JsonResponse { $comment = PostComment::where('post_id', $postId)->findOrFail($commentId); Gate::authorize('delete', $comment); $comment->delete(); $this->counters->decrementComments(Post::findOrFail($postId)); return response()->json(['message' => 'Comment deleted.']); } // ───────────────────────────────────────────────────────────────────────── // Format // ───────────────────────────────────────────────────────────────────────── private function formatComment(PostComment $comment): array { return [ 'id' => $comment->id, 'body' => $comment->body, 'is_highlighted' => (bool) $comment->is_highlighted, 'created_at' => $comment->created_at->toISOString(), 'author' => [ 'id' => $comment->user->id, 'username' => $comment->user->username, 'name' => $comment->user->name, 'avatar' => $comment->user->profile?->avatar_url ?? null, 'level' => (int) ($comment->user->level ?? 1), 'rank' => (string) ($comment->user->rank ?? 'Newbie'), ], ]; } }