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.
101 lines
3.1 KiB
Python
101 lines
3.1 KiB
Python
"""Create comment use case.
|
|
|
|
This module implements the use case for creating comments on blog posts.
|
|
Supports both top-level comments and nested replies via parent_id.
|
|
"""
|
|
|
|
from uuid import UUID
|
|
|
|
from app.application.dtos.comment import CommentResponseDTO
|
|
from app.application.interfaces import TransactionManager
|
|
from app.domain.entities.comment import Comment
|
|
from app.domain.exceptions import NotFoundException
|
|
from app.domain.repositories import CommentRepository, PostRepository
|
|
|
|
|
|
class CreateCommentUseCase:
|
|
"""Use case for creating a comment on a blog post.
|
|
|
|
Handles top-level comments and replies to existing comments.
|
|
Validates that the target post exists before creating.
|
|
|
|
Attributes:
|
|
_post_repo: Repository for post data access.
|
|
_comment_repo: Repository for comment data access.
|
|
_tx_manager: Transaction manager for commit control.
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
post_repo: PostRepository,
|
|
comment_repo: CommentRepository,
|
|
tx_manager: TransactionManager,
|
|
) -> None:
|
|
"""Initialize use case with dependencies.
|
|
|
|
Args:
|
|
post_repo: Repository for post operations.
|
|
comment_repo: Repository for comment operations.
|
|
tx_manager: Transaction manager instance.
|
|
"""
|
|
self._post_repo = post_repo
|
|
self._comment_repo = comment_repo
|
|
self._tx_manager = tx_manager
|
|
|
|
async def execute(
|
|
self,
|
|
post_id: UUID,
|
|
author_id: str,
|
|
content: str,
|
|
parent_id: UUID | None = None,
|
|
) -> CommentResponseDTO:
|
|
"""Execute the use case to create a comment.
|
|
|
|
Args:
|
|
post_id: UUID of the post to comment on.
|
|
author_id: Identifier of the comment author.
|
|
content: Comment content (Markdown supported).
|
|
parent_id: Optional UUID of parent comment for replies.
|
|
|
|
Returns:
|
|
CommentResponseDTO with created comment data.
|
|
|
|
Raises:
|
|
NotFoundException: If the target post does not exist.
|
|
"""
|
|
post = await self._post_repo.get_by_id(post_id)
|
|
if not post:
|
|
raise NotFoundException(f"Post with id '{post_id}' not found")
|
|
|
|
comment = Comment.create(
|
|
post_id=post_id,
|
|
author_id=author_id,
|
|
content_str=content,
|
|
parent_id=parent_id,
|
|
)
|
|
|
|
await self._comment_repo.add(comment)
|
|
await self._tx_manager.commit()
|
|
|
|
return self._map_to_dto(comment)
|
|
|
|
def _map_to_dto(self, comment: Comment) -> CommentResponseDTO:
|
|
"""Map domain entity to response DTO.
|
|
|
|
Args:
|
|
comment: Domain Comment entity.
|
|
|
|
Returns:
|
|
CommentResponseDTO with all comment attributes.
|
|
"""
|
|
return CommentResponseDTO(
|
|
id=comment.id,
|
|
post_id=comment.post_id,
|
|
author_id=comment.author_id,
|
|
content=comment.content.value,
|
|
parent_id=comment.parent_id,
|
|
like_count=comment.like_count,
|
|
created_at=comment.created_at,
|
|
updated_at=comment.updated_at,
|
|
)
|