mirror of https://git.sr.ht/~tsileo/microblog.pub
113 lines
2.7 KiB
Python
113 lines
2.7 KiB
Python
|
from pathlib import Path
|
||
|
from typing import Any
|
||
|
from typing import Callable
|
||
|
|
||
|
from fastapi import APIRouter
|
||
|
from fastapi import Depends
|
||
|
from fastapi import Request
|
||
|
from starlette.responses import JSONResponse
|
||
|
|
||
|
_DATA_DIR = Path().parent.resolve() / "data"
|
||
|
_Handler = Callable[..., Any]
|
||
|
|
||
|
|
||
|
class HTMLPage:
|
||
|
def __init__(
|
||
|
self,
|
||
|
title: str,
|
||
|
html_file: str,
|
||
|
show_in_navbar: bool,
|
||
|
) -> None:
|
||
|
self.title = title
|
||
|
self.html_file = _DATA_DIR / html_file
|
||
|
self.show_in_navbar = show_in_navbar
|
||
|
|
||
|
|
||
|
class RawHandler:
|
||
|
def __init__(
|
||
|
self,
|
||
|
title: str,
|
||
|
handler: Any,
|
||
|
show_in_navbar: bool,
|
||
|
) -> None:
|
||
|
self.title = title
|
||
|
self.handler = handler
|
||
|
self.show_in_navbar = show_in_navbar
|
||
|
|
||
|
|
||
|
_CUSTOM_ROUTES: dict[str, HTMLPage | RawHandler] = {}
|
||
|
|
||
|
|
||
|
def register_html_page(
|
||
|
path: str,
|
||
|
*,
|
||
|
title: str,
|
||
|
html_file: str,
|
||
|
show_in_navbar: bool = True,
|
||
|
) -> None:
|
||
|
if path in _CUSTOM_ROUTES:
|
||
|
raise ValueError(f"{path} is already registered")
|
||
|
|
||
|
_CUSTOM_ROUTES[path] = HTMLPage(title, html_file, show_in_navbar)
|
||
|
|
||
|
|
||
|
def register_raw_handler(
|
||
|
path: str,
|
||
|
*,
|
||
|
title: str,
|
||
|
handler: _Handler,
|
||
|
show_in_navbar: bool = True,
|
||
|
) -> None:
|
||
|
if path in _CUSTOM_ROUTES:
|
||
|
raise ValueError(f"{path} is already registered")
|
||
|
|
||
|
_CUSTOM_ROUTES[path] = RawHandler(title, handler, show_in_navbar)
|
||
|
|
||
|
|
||
|
class ActivityPubResponse(JSONResponse):
|
||
|
media_type = "application/activity+json"
|
||
|
|
||
|
|
||
|
def _custom_page_handler(path: str, html_page: HTMLPage) -> Any:
|
||
|
from app import templates
|
||
|
from app.actor import LOCAL_ACTOR
|
||
|
from app.config import is_activitypub_requested
|
||
|
from app.database import AsyncSession
|
||
|
from app.database import get_db_session
|
||
|
|
||
|
async def _handler(
|
||
|
request: Request,
|
||
|
db_session: AsyncSession = Depends(get_db_session),
|
||
|
) -> templates.TemplateResponse | ActivityPubResponse:
|
||
|
if path == "/" and is_activitypub_requested(request):
|
||
|
return ActivityPubResponse(LOCAL_ACTOR.ap_actor)
|
||
|
|
||
|
return await templates.render_template(
|
||
|
db_session,
|
||
|
request,
|
||
|
"custom_page.html",
|
||
|
{
|
||
|
"page_content": html_page.html_file.read_text(),
|
||
|
"title": html_page.title,
|
||
|
},
|
||
|
)
|
||
|
|
||
|
return _handler
|
||
|
|
||
|
|
||
|
def get_custom_router() -> APIRouter | None:
|
||
|
if not _CUSTOM_ROUTES:
|
||
|
return None
|
||
|
|
||
|
router = APIRouter()
|
||
|
|
||
|
for path, handler in _CUSTOM_ROUTES.items():
|
||
|
if isinstance(handler, HTMLPage):
|
||
|
router.add_api_route(
|
||
|
path, _custom_page_handler(path, handler), methods=["GET"]
|
||
|
)
|
||
|
else:
|
||
|
router.add_api_route(path, handler.handler)
|
||
|
|
||
|
return router
|