"""Web UI routes for blog application. This module provides HTML endpoints for the blog web interface. Currently uses mock data for demonstration purposes. Integration with use cases will be added in future iterations. """ from datetime import datetime from uuid import uuid4 from fastapi import APIRouter, Request from fastapi.responses import HTMLResponse from fastapi.templating import Jinja2Templates router = APIRouter(prefix="/web", tags=["web"]) templates = Jinja2Templates(directory="app/presentation/templates") class MockPost: """Mock post object for UI demonstration. This class simulates a Post entity for template rendering before integration with actual use cases. Attributes: id: Unique identifier for the post. title: Post title value object. content: Post content value object. slug: URL-friendly slug. author_id: Identifier of the post author. published: Publication status flag. tags: List of tags associated with the post. created_at: Timestamp when the post was created. updated_at: Timestamp when the post was last updated. """ def __init__( self, id: str, title: str, content: str, slug: str, author_id: str, published: bool, tags: list[str], created_at: datetime | None = None, ) -> None: """Initialize mock post with provided attributes. Args: id: Unique identifier for the post. title: Post title string. content: Post content string. slug: URL-friendly slug string. author_id: Author identifier string. published: Whether the post is published. tags: List of tag strings. created_at: Optional creation timestamp, defaults to now. """ self.id = id self.title = MockValueObject(title) self.content = MockValueObject(content) self.slug = MockValueObject(slug) self.author_id = author_id self.published = published self.tags = tags self.created_at = created_at or datetime.now() self.updated_at = self.created_at class MockValueObject: """Mock value object for simulating domain value objects. Wraps a raw value to simulate the interface of domain value objects like Title, Content, and Slug. Attributes: value: The wrapped string value. """ def __init__(self, value: str) -> None: """Initialize with a string value. Args: value: The string value to wrap. """ self.value = value MOCK_POSTS = [ MockPost( id=str(uuid4()), title="Getting Started with FastAPI", content="FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.7+ based on standard Python type hints. It is designed to be easy to use while providing high performance.", slug="getting-started-with-fastapi", author_id="john_doe", published=True, tags=["python", "fastapi", "tutorial"], created_at=datetime(2026, 1, 15, 10, 30), ), MockPost( id=str(uuid4()), title="Understanding DDD Architecture", content="Domain-Driven Design (DDD) is an approach to software development that centers the development on programming a domain model that has a rich understanding of the processes and rules of a domain. The term was coined by Eric Evans in his book of the same title.", slug="understanding-ddd-architecture", author_id="jane_smith", published=True, tags=["ddd", "architecture", "software-design"], created_at=datetime(2026, 1, 14, 14, 45), ), MockPost( id=str(uuid4()), title="Draft Post Example", content="This is a draft post that hasn't been published yet. It demonstrates how unpublished posts appear in the UI.", slug="draft-post-example", author_id="john_doe", published=False, tags=["draft"], created_at=datetime(2026, 1, 13, 9, 0), ), ] @router.get("/", response_class=HTMLResponse) async def home(request: Request) -> HTMLResponse: """Render the home page with list of posts. Args: request: The HTTP request object for template context. Returns: HTMLResponse with rendered posts list template. """ return templates.TemplateResponse( request, "pages/index.html", { "posts": MOCK_POSTS, "active_page": "home", "current_page": 1, "has_prev": False, "has_next": False, }, ) @router.get("/posts", response_class=HTMLResponse) async def list_posts(request: Request) -> HTMLResponse: """Render the posts listing page. Args: request: The HTTP request object for template context. Returns: HTMLResponse with rendered posts list template. """ return templates.TemplateResponse( request, "pages/index.html", { "posts": MOCK_POSTS, "active_page": "posts", "current_page": 1, "has_prev": False, "has_next": True, }, ) @router.get("/posts/new", response_class=HTMLResponse) async def new_post_form(request: Request) -> HTMLResponse: """Render the new post creation form. Args: request: The HTTP request object for template context. Returns: HTMLResponse with rendered post form template. """ return templates.TemplateResponse( request, "pages/post_form.html", { "is_edit": False, "post": None, "active_page": "posts", }, ) @router.post("/posts/new", response_class=HTMLResponse) async def create_post(request: Request) -> HTMLResponse: """Handle new post creation form submission. Args: request: The HTTP request object containing form data. Returns: HTMLResponse redirecting to the home page. """ return templates.TemplateResponse( request, "pages/index.html", { "posts": MOCK_POSTS, "active_page": "home", "current_page": 1, "has_prev": False, "has_next": False, }, ) @router.get("/posts/{post_id}", response_class=HTMLResponse) async def post_detail(request: Request, post_id: str) -> HTMLResponse: """Render a single post detail page. Args: request: The HTTP request object for template context. post_id: The unique identifier of the post to display. Returns: HTMLResponse with rendered post detail template. """ post = next((p for p in MOCK_POSTS if str(p.id) == post_id), MOCK_POSTS[0]) return templates.TemplateResponse( request, "pages/post_detail.html", { "post": post, "active_page": "posts", }, ) @router.get("/posts/{post_id}/edit", response_class=HTMLResponse) async def edit_post_form(request: Request, post_id: str) -> HTMLResponse: """Render the post edit form. Args: request: The HTTP request object for template context. post_id: The unique identifier of the post to edit. Returns: HTMLResponse with rendered post form template. """ post = next((p for p in MOCK_POSTS if str(p.id) == post_id), MOCK_POSTS[0]) return templates.TemplateResponse( request, "pages/post_form.html", { "is_edit": True, "post": post, "active_page": "posts", }, ) @router.post("/posts/{post_id}/edit", response_class=HTMLResponse) async def update_post(request: Request, post_id: str) -> HTMLResponse: """Handle post update form submission. Args: request: The HTTP request object containing form data. post_id: The unique identifier of the post to update. Returns: HTMLResponse with rendered post detail template. """ post = next((p for p in MOCK_POSTS if str(p.id) == post_id), MOCK_POSTS[0]) return templates.TemplateResponse( request, "pages/post_detail.html", { "post": post, "active_page": "posts", }, ) @router.post("/posts/{post_id}/delete", response_class=HTMLResponse) async def delete_post(request: Request, post_id: str) -> HTMLResponse: """Handle post deletion. Args: request: The HTTP request object. post_id: The unique identifier of the post to delete. Returns: HTMLResponse redirecting to the home page. """ return templates.TemplateResponse( request, "pages/index.html", { "posts": MOCK_POSTS, "active_page": "home", "current_page": 1, "has_prev": False, "has_next": False, }, ) @router.get("/about", response_class=HTMLResponse) async def about(request: Request) -> HTMLResponse: """Render the about page. Args: request: The HTTP request object for template context. Returns: HTMLResponse with rendered about page template. """ return HTMLResponse( content=""" About - Blog

About

A modern blog built with FastAPI and DDD architecture.

Back to home """ )