import os import markdown from fastapi import APIRouter, Request, HTTPException, Depends from fastapi.responses import HTMLResponse from deps import current_user router = APIRouter() # Whitelist allowed files. # We look for them in the root directory relative to 'app' parent. # Since app is in /app inside docker, the root volume mount is usually at /app or mapped. # Code Tour Step 828 shows 'app/main.py' path analysis. # If workdir is /app (docker), and files are in /app (root of repo mapped to /app), then "README.md" is at "./README.md". ALLOWED_DOCS = { "README.md": "Start Guide (Readme)", "QUICKSTART.md": "Schnellstart", "HANDBUCH.md": "Benutzerhandbuch", "CODE_TOUR.md": "Code Tour (Dev)", "ARCHITECTURE_ROLES_GROUPS.md": "Architektur", "DIARY_RAG_README.md": "Tagebuch & RAG Info", "CrumbTech.md": "Technische Details", "QDRANT_ACCESS.md": "Vektor DB Access", "docs_git.md": "Guide - Git & Versionierung", "deploy_security_fixes.sh": "Security Script (Source)" # Maybe viewing scripts is cool too? Let's stick to MD for now. } from config import get_settings @router.get("/docs", response_class=HTMLResponse) async def list_docs(req: Request): """ List available documentation files. """ available = [] base_path = _get_docs_base_path() for filename, title in ALLOWED_DOCS.items(): # Check root and subdirectories (1 level deep) full_path = _find_file(base_path, filename) if full_path: available.append({"name": title, "file": filename}) return req.app.state.render( req, "pages/docs_index.html", docs=available, page_title="Dokumentation" ) @router.get("/docs/{filename}", response_class=HTMLResponse) async def view_doc(req: Request, filename: str): """ Render a specific markdown file. """ if filename not in ALLOWED_DOCS: raise HTTPException(404, "File not found or not allowed.") base_path = _get_docs_base_path() file_path = _find_file(base_path, filename) if not file_path: raise HTTPException(404, "File not on server.") try: with open(file_path, "r", encoding="utf-8") as f: content = f.read() # Convert Markdown to HTML html_content = markdown.markdown( content, extensions=['tables', 'fenced_code', 'nl2br'] ) return req.app.state.render( req, "pages/doc_viewer.html", doc_title=ALLOWED_DOCS[filename], doc_content=html_content, filename=filename ) except Exception as e: raise HTTPException(500, f"Error rendering document: {e}") def _get_docs_base_path(): try: settings = get_settings() base_path = settings.docs_path except: base_path = "docs" if not os.path.isabs(base_path) and not os.path.exists(base_path): if os.path.exists("/docs_root"): base_path = "/docs_root" else: base_path = "." return base_path def _find_file(base_path, filename): """Find file in base_path or immediate subdirectories.""" # 1. Direct match direct = os.path.join(base_path, filename) if os.path.exists(direct): return direct # 2. Check subdirectories (max depth 1) if os.path.isdir(base_path): for entry in os.scandir(base_path): if entry.is_dir(): sub_path = os.path.join(entry.path, filename) if os.path.exists(sub_path): return sub_path return None