|
1 | 1 | from datetime import UTC, datetime, timedelta |
| 2 | +from pathlib import Path |
2 | 3 | from typing import TYPE_CHECKING, ClassVar, Self |
3 | 4 |
|
| 5 | +import aiofiles |
| 6 | +from aiocache import Cache, cached |
4 | 7 | from fastapi import Response |
5 | 8 | from pydantic import HttpUrl |
6 | 9 | from sqlalchemy import Select, select |
7 | 10 | from sqlalchemy.ext.asyncio import AsyncSession |
8 | 11 | from starlette.requests import Request |
9 | 12 |
|
10 | 13 | from futuramaapi.core import settings |
| 14 | +from futuramaapi.helpers import render_markdown |
11 | 15 | from futuramaapi.helpers.pydantic import BaseModel, Field |
12 | 16 | from futuramaapi.mixins.pydantic import BaseModelTemplateMixin, ProjectContext |
13 | 17 | from futuramaapi.repositories import FilterStatementKwargs |
@@ -106,3 +110,26 @@ async def from_request(cls, request: Request) -> Self: |
106 | 110 | return cls( |
107 | 111 | urls=[url.path for url in app.public_urls], |
108 | 112 | ) |
| 113 | + |
| 114 | + |
| 115 | +@cached( |
| 116 | + ttl=None, |
| 117 | + cache=Cache.MEMORY, |
| 118 | +) |
| 119 | +async def _get_rendered_content() -> str: |
| 120 | + path: Path = Path(settings.project_root) / "CHANGELOG.md" |
| 121 | + async with aiofiles.open(path, encoding="utf-8") as f: |
| 122 | + raw_content = await f.read() |
| 123 | + return render_markdown(raw_content) |
| 124 | + |
| 125 | + |
| 126 | +class Changelog(BaseModel, BaseModelTemplateMixin): |
| 127 | + content: str |
| 128 | + |
| 129 | + template_name: ClassVar[str] = "changelog.html" |
| 130 | + |
| 131 | + @classmethod |
| 132 | + async def from_request(cls, session: AsyncSession, request: Request, /) -> Self: |
| 133 | + return cls( |
| 134 | + content=await _get_rendered_content(), |
| 135 | + ) |
0 commit comments