All checks were successful
ci/woodpecker/pr/pipeline Pipeline was successful
Implement full comments system: domain entities (Comment, CommentLike), value objects (CommentContent), use cases (CRUD, like toggle), SQLAlchemy repository, API v1 endpoints, web UI with comment form and nested replies, i18n translations (EN/RU/FR/DE), and E2E tests. Fix nested reply (reply-to-reply) not displaying — the flat reply_comments dict was only queried for top-level comment IDs, so deeply nested replies were saved to DB (incrementing comment count) but never rendered. Switch to a recursive Jinja2 macro that renders any nesting depth.
132 lines
3.4 KiB
Python
132 lines
3.4 KiB
Python
"""Comments API routes.
|
|
|
|
This module defines FastAPI routes for comment operations including
|
|
CRUD and like/unlike toggle.
|
|
"""
|
|
|
|
from uuid import UUID
|
|
|
|
from dishka.integrations.fastapi import DishkaRoute
|
|
from fastapi import APIRouter, status
|
|
|
|
from app.presentation.api.deps import (
|
|
CreateCommentDep,
|
|
CurrentRoleDep,
|
|
CurrentUserDep,
|
|
DeleteCommentDep,
|
|
ListCommentsDep,
|
|
ToggleCommentLikeDep,
|
|
)
|
|
from app.presentation.schemas import (
|
|
CommentCreateSchema,
|
|
CommentLikeResponseSchema,
|
|
CommentResponseSchema,
|
|
)
|
|
|
|
router = APIRouter(tags=["comments"], route_class=DishkaRoute)
|
|
|
|
|
|
@router.post(
|
|
"/posts/{post_id}/comments",
|
|
response_model=CommentResponseSchema,
|
|
status_code=status.HTTP_201_CREATED,
|
|
summary="Create a comment on a post",
|
|
)
|
|
async def create_comment(
|
|
post_id: UUID,
|
|
schema: CommentCreateSchema,
|
|
use_case: CreateCommentDep,
|
|
current_user_id: CurrentUserDep,
|
|
) -> CommentResponseSchema:
|
|
"""Create a comment on a blog post.
|
|
|
|
Args:
|
|
post_id: UUID of the post to comment on.
|
|
schema: Comment creation data.
|
|
use_case: CreateCommentUseCase dependency.
|
|
current_user_id: Authenticated user ID.
|
|
|
|
Returns:
|
|
CommentResponseSchema with created comment data.
|
|
"""
|
|
result = await use_case.execute(
|
|
post_id=post_id,
|
|
author_id=current_user_id,
|
|
content=schema.content,
|
|
parent_id=schema.parent_id,
|
|
)
|
|
return CommentResponseSchema(**result.__dict__)
|
|
|
|
|
|
@router.get(
|
|
"/posts/{post_id}/comments",
|
|
response_model=list[CommentResponseSchema],
|
|
summary="List comments for a post",
|
|
)
|
|
async def list_comments(
|
|
post_id: UUID,
|
|
use_case: ListCommentsDep,
|
|
) -> list[CommentResponseSchema]:
|
|
"""Get all comments for a blog post.
|
|
|
|
Args:
|
|
post_id: UUID of the post.
|
|
use_case: ListCommentsUseCase dependency.
|
|
|
|
Returns:
|
|
List of CommentResponseSchema for the post.
|
|
"""
|
|
results = await use_case.execute(post_id=post_id)
|
|
return [CommentResponseSchema(**r.__dict__) for r in results]
|
|
|
|
|
|
@router.delete(
|
|
"/comments/{comment_id}",
|
|
status_code=status.HTTP_204_NO_CONTENT,
|
|
summary="Delete a comment",
|
|
)
|
|
async def delete_comment(
|
|
comment_id: UUID,
|
|
use_case: DeleteCommentDep,
|
|
current_user_id: CurrentUserDep,
|
|
role: CurrentRoleDep,
|
|
) -> None:
|
|
"""Delete a comment.
|
|
|
|
Users can delete their own comments.
|
|
|
|
Args:
|
|
comment_id: UUID of the comment to delete.
|
|
use_case: DeleteCommentUseCase dependency.
|
|
current_user_id: Authenticated user ID.
|
|
role: Current user role.
|
|
"""
|
|
await use_case.execute(comment_id=comment_id, user_id=current_user_id)
|
|
|
|
|
|
@router.post(
|
|
"/comments/{comment_id}/like",
|
|
response_model=CommentLikeResponseSchema,
|
|
summary="Toggle like on a comment",
|
|
)
|
|
async def toggle_comment_like(
|
|
comment_id: UUID,
|
|
use_case: ToggleCommentLikeDep,
|
|
current_user_id: CurrentUserDep,
|
|
) -> CommentLikeResponseSchema:
|
|
"""Toggle like/unlike on a comment.
|
|
|
|
If the user already liked the comment, the like is removed (unlike).
|
|
Otherwise, a new like is added.
|
|
|
|
Args:
|
|
comment_id: UUID of the comment.
|
|
use_case: ToggleCommentLikeUseCase dependency.
|
|
current_user_id: Authenticated user ID.
|
|
|
|
Returns:
|
|
CommentLikeResponseSchema with updated like_count.
|
|
"""
|
|
result = await use_case.execute(comment_id, current_user_id)
|
|
return CommentLikeResponseSchema(id=result.id, like_count=result.like_count)
|