# retoor <retoor@molodetz.nl>
import logging
from fastapi import APIRouter, Request
from fastapi.responses import HTMLResponse, RedirectResponse, Response
from devplacepy.templating import templates
from devplacepy.utils import (
get_current_user,
not_found,
is_admin as user_is_admin,
track_action,
)
from devplacepy.seo import base_seo_context, site_url, website_schema
from devplacepy.docs_api import render_group, build_services_group
from devplacepy.services.manager import service_manager
from devplacepy.database import get_setting
from devplacepy.constants import DEVII_GUEST_COOKIE
from devplacepy import docs_export, docs_live, docs_prose, docs_search
from devplacepy.routers.docs.pages import DOCS_PAGES, PAGES_BY_SLUG, nav_groups
logger = logging.getLogger(__name__)
router = APIRouter()
@router.get("/docs")
async def docs_root(request: Request):
return RedirectResponse(url="/docs/index.html", status_code=302)
def _export_context(request: Request):
user = get_current_user(request)
is_admin = user_is_admin(user)
return (
is_admin,
site_url(request),
user.get("username") if user else "",
user.get("api_key") if user else "",
)
@router.get("/docs/download.md")
async def docs_download_md(request: Request):
is_admin, base, username, api_key = _export_context(request)
markdown = docs_export.build_markdown(is_admin, base, username, api_key)
return Response(
content=markdown,
media_type="text/markdown; charset=utf-8",
headers={"Content-Disposition": 'attachment; filename="devplace-docs.md"'},
)
@router.get("/docs/download.html")
async def docs_download_html(request: Request):
is_admin, base, username, api_key = _export_context(request)
markdown = docs_export.build_markdown(is_admin, base, username, api_key)
return HTMLResponse(
content=docs_export.build_html(markdown),
headers={"Content-Disposition": 'attachment; filename="devplace-docs.html"'},
)
def _agent_search_state(request: Request, user, is_admin: bool) -> str:
svc = service_manager.get_service("devii")
if svc is None or not svc.is_enabled():
return "disabled"
if user:
owner_kind, owner_id = "user", user["uid"]
else:
owner_kind = "guest"
owner_id = request.cookies.get(DEVII_GUEST_COOKIE) or ""
if owner_kind == "guest" and not svc.guests_enabled():
return "disabled"
if owner_id:
limit = svc.daily_limit_for(owner_kind, is_admin)
if limit > 0 and svc.spent_24h(owner_kind, owner_id) >= limit:
return "quota"
return "ok"
@router.get("/docs/{slug}.html", response_class=HTMLResponse)
async def docs_page(request: Request, slug: str):
user = get_current_user(request)
is_admin = user_is_admin(user)
base = site_url(request)
visible_pages = [p for p in DOCS_PAGES if not p.get("admin") or is_admin]
if slug == "search":
query = request.query_params.get("q", "")
mode = get_setting("docs_search_mode", "agent")
state = _agent_search_state(request, user, is_admin) if mode == "agent" else "off"
use_agent = mode == "agent" and state == "ok"
quota_fallback = mode == "agent" and state == "quota"
results = None if use_agent else docs_search.search(query, user=user, is_admin=is_admin)
seo_ctx = base_seo_context(
request,
title="Search - Documentation",
description="Search the DevPlace developer documentation.",
robots="noindex",
breadcrumbs=[
{"name": "Home", "url": "/feed"},
{"name": "Docs", "url": "/docs/index.html"},
{"name": "Search", "url": "/docs/search.html"},
],
schemas=[website_schema(base)],
)
return templates.TemplateResponse(
request,
"docs_base.html",
{
**seo_ctx,
"request": request,
"user": user,
"pages": visible_pages,
"nav": nav_groups(visible_pages),
"current": "search",
"kind": "search",
"search_mode": "agent" if use_agent else "bm25",
"quota_fallback": quota_fallback,
"page_title_doc": "Search",
"search_query": query,
"search_results": results,
"base": base,
},
)
page = PAGES_BY_SLUG.get(slug)
if not page:
raise not_found("Documentation page not found")
if page.get("admin") and not is_admin:
raise not_found("Documentation page not found")
if user:
track_action(user["uid"], "docs.read", slug)
if page["kind"] == "live":
seo_ctx = base_seo_context(
request,
title=f"{page['title']} - Documentation",
description="Your live DevPlace stats, activity, and site data.",
robots="noindex",
breadcrumbs=[
{"name": "Home", "url": "/feed"},
{"name": "Docs", "url": "/docs/index.html"},
{"name": page["title"], "url": f"/docs/{slug}.html"},
],
schemas=[website_schema(base)],
)
return templates.TemplateResponse(
request,
"docs_base.html",
{
**seo_ctx,
"request": request,
"user": user,
"pages": visible_pages,
"nav": nav_groups(visible_pages),
"current": slug,
"kind": "live",
"facts": docs_live.build_live_facts(user),
"page_title_doc": page["title"],
"base": base,
},
)
prose_html = None
group = None
if page["kind"] == "prose":
prose_html = docs_prose.render_prose(
slug,
{
"base": base,
"user": user,
"username": user.get("username") if user else "",
"api_key": user.get("api_key") if user else "",
},
)
elif page.get("dynamic"):
group = build_services_group(service_manager.describe_all(), base)
else:
group = render_group(
slug,
base,
user.get("username") if user else "",
user.get("api_key") if user else "",
)
seo_ctx = base_seo_context(
request,
title=f"{page['title']} - Documentation",
description="DevPlace developer documentation.",
breadcrumbs=[
{"name": "Home", "url": "/feed"},
{"name": "Docs", "url": "/docs/index.html"},
{"name": page["title"], "url": f"/docs/{slug}.html"},
],
schemas=[website_schema(base)],
)
return templates.TemplateResponse(
request,
"docs_base.html",
{
**seo_ctx,
"request": request,
"user": user,
"pages": visible_pages,
"nav": nav_groups(visible_pages),
"current": slug,
"kind": page["kind"],
"group": group,
"prose_html": prose_html,
"page_title_doc": page["title"],
"base": base,
},
)