"""Documentation API endpoints""" from fastapi import APIRouter, Depends, HTTPException from fastapi.responses import PlainTextResponse, JSONResponse, FileResponse from app.api.auth import get_current_user import logging import os import markdown from weasyprint import HTML, CSS from datetime import datetime import tempfile logger = logging.getLogger(__name__) router = APIRouter() # Documentation files directory DOCS_DIR = "/opt/depl0y/docs" DOCS_FILES = { "install": "INSTALL.md", "deployment": "DEPLOYMENT.md", "cloud-quickstart": "CLOUD_IMAGES_QUICKSTART.md", "cloud-guide": "CLOUD_IMAGES_GUIDE.md", "readme": "README.md", "proxmox-api-tokens": "PROXMOX_API_TOKENS.md", "cloud-index": "docs/CLOUD_IMAGES_INDEX.md" } @router.get("/") def list_documentation(current_user=Depends(get_current_user)): """List all available documentation""" docs = [] for key, filename in DOCS_FILES.items(): filepath = os.path.join(DOCS_DIR, filename) if os.path.exists(filepath): size = os.path.getsize(filepath) docs.append({ "id": key, "filename": filename, "title": _get_title(key), "size": size, "available": True }) else: docs.append({ "id": key, "filename": filename, "title": _get_title(key), "available": False }) return {"docs": docs} @router.get("/{doc_id}") def get_documentation( doc_id: str, format: str = "markdown", current_user=Depends(get_current_user) ): """Get a specific documentation file""" if doc_id not in DOCS_FILES: raise HTTPException(status_code=404, detail="Documentation not found") filename = DOCS_FILES[doc_id] filepath = os.path.join(DOCS_DIR, filename) if not os.path.exists(filepath): raise HTTPException( status_code=404, detail=f"Documentation file {filename} not found on server" ) try: with open(filepath, 'r', encoding='utf-8') as f: content = f.read() if format == "json": return JSONResponse({ "id": doc_id, "filename": filename, "title": _get_title(doc_id), "content": content, "format": "markdown" }) else: # Return plain text markdown return PlainTextResponse(content, media_type="text/markdown") except Exception as e: logger.error(f"Failed to read documentation {doc_id}: {e}") raise HTTPException( status_code=500, detail=f"Failed to read documentation: {str(e)}" ) def _get_title(doc_id: str) -> str: """Get human-readable title for documentation""" titles = { "install": "Installation Guide", "deployment": "Deployment Guide", "cloud-quickstart": "Cloud Images - Quick Start", "cloud-guide": "Cloud Images - Complete Guide", "readme": "Getting Started with Depl0y", "proxmox-api-tokens": "Proxmox API Tokens Setup", "cloud-index": "Cloud Images Documentation Index" } return titles.get(doc_id, doc_id.replace("-", " ").title()) @router.get("/download/pdf") def download_documentation_pdf(current_user=Depends(get_current_user)): """Generate and download complete documentation as PDF""" try: # Order of documentation to include in PDF doc_order = [ "readme", "install", "deployment", "cloud-quickstart", "cloud-guide", "proxmox-api-tokens" ] # Build HTML content html_content = """ Depl0y Documentation

Depl0y

Complete Documentation

Automated VM Deployment Panel for Proxmox VE

Generated: """ + datetime.now().strftime("%B %d, %Y") + """

Version 1.1.3

Table of Contents

""" # Add each documentation section for doc_id in doc_order: if doc_id not in DOCS_FILES: continue filename = DOCS_FILES[doc_id] filepath = os.path.join(DOCS_DIR, filename) if not os.path.exists(filepath): logger.warning(f"Documentation file {filename} not found, skipping") continue try: with open(filepath, 'r', encoding='utf-8') as f: md_content = f.read() # Convert markdown to HTML html_section = markdown.markdown( md_content, extensions=['extra', 'codehilite', 'tables', 'toc'] ) html_content += f'
\n{html_section}\n
\n' except Exception as e: logger.error(f"Failed to process {doc_id}: {e}") continue html_content += """ """ # Generate PDF logger.info("Generating PDF from HTML...") # Create temporary file for PDF with tempfile.NamedTemporaryFile(delete=False, suffix='.pdf') as tmp_file: pdf_path = tmp_file.name # Generate PDF using WeasyPrint HTML(string=html_content).write_pdf(pdf_path) logger.info(f"PDF generated successfully at {pdf_path}") # Return PDF file filename = f"Depl0y_Documentation_{datetime.now().strftime('%Y%m%d')}.pdf" return FileResponse( pdf_path, media_type="application/pdf", filename=filename, headers={ "Content-Disposition": f"attachment; filename={filename}" } ) except Exception as e: logger.error(f"Failed to generate PDF: {e}", exc_info=True) raise HTTPException( status_code=500, detail=f"Failed to generate PDF: {str(e)}" )