Files
blog.pyaqa.ru/app/domain/entities/post.py
Sergey Vanyushkin ca4e8877a5 docs: add AI code generation requirements and comprehensive Google-style docstrings
- Add AI code generation requirements to AGENTS.md
- Add module-level docstrings to all 46 Python modules
- Add detailed Google-style docstrings to all classes and functions
- Remove all inline comments following self-documenting code principle
- Include Args, Returns, Raises sections in function docstrings
- Add Attributes and Examples sections to class docstrings
2026-05-02 13:15:21 +03:00

151 lines
4.1 KiB
Python

"""Domain entity for Blog Post.
This module defines the Post aggregate root entity that encapsulates
all business logic related to blog posts including publishing, content
management, and tag operations.
"""
from dataclasses import dataclass, field
from typing import Any
from app.domain.entities.base import BaseEntity
from app.domain.value_objects.content import Content
from app.domain.value_objects.slug import Slug
from app.domain.value_objects.title import Title
@dataclass(kw_only=True)
class Post(BaseEntity):
"""Blog post domain entity.
Represents a blog post with title, content, slug, and metadata.
Encapsulates business logic for post lifecycle management.
Attributes:
title: Post title value object with validation.
content: Post content value object with validation.
slug: URL-friendly identifier generated from title.
author_id: Identifier of the post author.
published: Publication status flag.
tags: List of tags associated with the post.
Example:
>>> post = Post.create(
... title_str="My First Post",
... content_str="This is the content...",
... author_id="user-123",
... tags=["python", "fastapi"]
... )
>>> post.publish()
"""
title: Title
content: Content
slug: Slug
author_id: str
published: bool = False
tags: list[str] = field(default_factory=list)
def publish(self) -> None:
"""Publish the post.
Sets the published flag to True and updates the timestamp.
"""
self.published = True
self.touch()
def unpublish(self) -> None:
"""Unpublish the post.
Sets the published flag to False and updates the timestamp.
"""
self.published = False
self.touch()
def update_content(self, content: Content) -> None:
"""Update post content.
Args:
content: New content value object.
"""
self.content = content
self.touch()
def update_title(self, title: Title) -> None:
"""Update post title and regenerate slug.
Args:
title: New title value object.
"""
self.title = title
self.slug = Slug.from_title(title.value)
self.touch()
def add_tag(self, tag: str) -> None:
"""Add a tag to the post.
Args:
tag: Tag string to add. Only adds if not already present.
"""
if tag not in self.tags:
self.tags.append(tag)
self.touch()
def remove_tag(self, tag: str) -> None:
"""Remove a tag from the post.
Args:
tag: Tag string to remove. Only removes if present.
"""
if tag in self.tags:
self.tags.remove(tag)
self.touch()
def to_dict(self) -> dict[str, Any]:
"""Convert entity to dictionary.
Returns:
Dictionary representation with all post attributes.
"""
return {
"id": str(self.id),
"title": self.title.value,
"content": self.content.value,
"slug": self.slug.value,
"author_id": self.author_id,
"published": self.published,
"tags": self.tags.copy(),
"created_at": self.created_at.isoformat(),
"updated_at": self.updated_at.isoformat(),
}
@classmethod
def create(
cls,
title_str: str,
content_str: str,
author_id: str,
tags: list[str] | None = None,
) -> "Post":
"""Factory method to create a new post.
Args:
title_str: Title string for the post.
content_str: Content string for the post.
author_id: Identifier of the post author.
tags: Optional list of tags.
Returns:
New Post instance with validated value objects.
"""
title = Title(title_str)
content = Content(content_str)
slug = Slug.from_title(title_str)
return cls(
title=title,
content=content,
slug=slug,
author_id=author_id,
tags=tags or [],
)