Source code for pydotorg.domains.codesamples.controllers

"""Code Samples domain API and page controllers."""

from __future__ import annotations

from typing import Annotated
from uuid import UUID

from advanced_alchemy.filters import LimitOffset
from litestar import Controller, delete, get, post, put
from litestar.exceptions import NotFoundException
from litestar.params import Body, Parameter
from litestar.response import Template

from pydotorg.domains.codesamples.schemas import (
    CodeSampleCreate,
    CodeSampleList,
    CodeSampleRead,
    CodeSampleUpdate,
)
from pydotorg.domains.codesamples.services import CodeSampleService


[docs] class CodeSampleController(Controller): """Controller for CodeSample CRUD operations.""" path = "/api/v1/code-samples" tags = ["Code Samples"] @get("/") async def list_code_samples( self, code_sample_service: CodeSampleService, limit_offset: LimitOffset, ) -> list[CodeSampleList]: """List all code samples with pagination.""" samples, _total = await code_sample_service.list_and_count(limit_offset) return [CodeSampleList.model_validate(sample) for sample in samples] @get("/{sample_id:uuid}") async def get_code_sample( self, code_sample_service: CodeSampleService, sample_id: Annotated[UUID, Parameter(title="Sample ID", description="The code sample ID")], ) -> CodeSampleRead: """Get a code sample by ID.""" sample = await code_sample_service.get(sample_id) return CodeSampleRead.model_validate(sample) @get("/slug/{slug:str}") async def get_code_sample_by_slug( self, code_sample_service: CodeSampleService, slug: Annotated[str, Parameter(title="Slug", description="The code sample slug")], ) -> CodeSampleRead: """Get a code sample by slug.""" sample = await code_sample_service.get_by_slug(slug) if not sample: raise NotFoundException(f"Code sample with slug {slug} not found") return CodeSampleRead.model_validate(sample) @get("/published") async def list_published_code_samples( self, code_sample_service: CodeSampleService, limit: Annotated[int, Parameter(ge=1, le=1000)] = 100, offset: Annotated[int, Parameter(ge=0)] = 0, ) -> list[CodeSampleList]: """List published code samples.""" samples = await code_sample_service.get_published_samples(limit=limit, offset=offset) return [CodeSampleList.model_validate(sample) for sample in samples] @post("/") async def create_code_sample( self, code_sample_service: CodeSampleService, data: Annotated[CodeSampleCreate, Body(title="Code Sample", description="Code sample to create")], ) -> CodeSampleRead: """Create a new code sample.""" sample = await code_sample_service.create(data.model_dump()) return CodeSampleRead.model_validate(sample) @put("/{sample_id:uuid}") async def update_code_sample( self, code_sample_service: CodeSampleService, data: Annotated[CodeSampleUpdate, Body(title="Code Sample", description="Code sample data to update")], sample_id: Annotated[UUID, Parameter(title="Sample ID", description="The code sample ID")], ) -> CodeSampleRead: """Update a code sample.""" update_data = data.model_dump(exclude_unset=True) sample = await code_sample_service.update(sample_id, update_data) return CodeSampleRead.model_validate(sample) @delete("/{sample_id:uuid}") async def delete_code_sample( self, code_sample_service: CodeSampleService, sample_id: Annotated[UUID, Parameter(title="Sample ID", description="The code sample ID")], ) -> None: """Delete a code sample.""" await code_sample_service.delete(sample_id)
[docs] class CodeSamplesPageController(Controller): """Controller for code samples HTML pages.""" path = "/code-samples" include_in_schema = False @get("/") async def code_samples_index( self, code_sample_service: CodeSampleService, ) -> Template: """Render the code samples index page.""" samples = await code_sample_service.get_published_samples(limit=50) return Template( template_name="codesamples/index.html.jinja2", context={ "samples": samples, "page_title": "Python Code Samples", }, ) @get("/{slug:str}/") async def code_sample_detail( self, code_sample_service: CodeSampleService, slug: str, ) -> Template: """Render the code sample detail page.""" sample = await code_sample_service.get_by_slug(slug) if not sample: raise NotFoundException(f"Code sample with slug {slug} not found") return Template( template_name="codesamples/detail.html.jinja2", context={ "sample": sample, "page_title": sample.title, }, )