File size: 7,134 Bytes
ec94fc1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c701395
 
 
 
 
 
 
 
ec94fc1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
"""API router β€” handbook endpoints.

Exposes REST endpoints that the PHP application calls over HTTP.
"""

from __future__ import annotations

import logging
from typing import Any

from fastapi import APIRouter, HTTPException, Query
from fastapi.responses import HTMLResponse, Response

from app.schemas.handbook import (
    ErrorResponse,
    FontDiagnosticsResponse,
    GlobalSectionsResponse,
    HandbookRequest,
    HealthResponse,
    SectionItem,
    UniversitySectionsResponse,
    UniversityPayload,
)

logger = logging.getLogger(__name__)

router = APIRouter()


# ── Root / HF health probe ──

@router.get("/", tags=["system"])
async def root():
    """Root endpoint β€” HF Spaces probes this URL for health checks."""
    return {"status": "ok"}


# ── Health check ──

@router.get("/health", response_model=HealthResponse, tags=["system"])
async def health_check():
    """Health check endpoint."""
    from app.core.config import get_settings
    settings = get_settings()
    return HealthResponse(
        status="ok",
        service=settings.app_name,
        version=settings.app_version,
    )


# ── Font diagnostics ──

@router.get("/diagnostics/fonts", tags=["system"])
async def font_diagnostics():
    """Font diagnostics endpoint. Mirrors PHP font_diagnostics.php."""
    from app.core.fonts import font_diagnostics as _diag
    try:
        result = _diag()
        return result
    except Exception as exc:
        raise HTTPException(status_code=500, detail=str(exc))


# ── Global sections (proxy/fetch) ──

@router.get("/api/v1/sections/global", tags=["sections"])
async def get_global_sections(catalog_id: int = Query(0, description="Catalog ID filter")):
    """Fetch global handbook sections from the upstream API.

    Returns normalised section data identical to what the PHP code produces.
    """
    from app.services.data_fetcher import fetch_global_sections

    try:
        sections = await fetch_global_sections(catalog_id)
        return {
            "ok": True,
            "general_sections": sections,
            "count": len(sections),
        }
    except Exception as exc:
        logger.exception("Failed to fetch global sections")
        raise HTTPException(status_code=502, detail=str(exc))


# ── University sections (proxy/fetch) ──

@router.get("/api/v1/sections/universities", tags=["sections"])
async def get_university_sections():
    """Fetch university handbook sections from the upstream API."""
    from app.services.data_fetcher import fetch_university_sections

    try:
        by_uni = await fetch_university_sections()
        return {
            "ok": True,
            "universities": by_uni,
            "count": len(by_uni),
        }
    except Exception as exc:
        logger.exception("Failed to fetch university sections")
        raise HTTPException(status_code=502, detail=str(exc))


# ── Generate handbook (HTML or PDF) ──

@router.get("/api/v1/handbook/pdf", tags=["handbook"])
async def generate_handbook_pdf_get(
    catalog_id: int = Query(0),
    include_inactive_programs: bool = Query(False),
    debug: bool = Query(False),
):
    """Generate the ISP Handbook as a PDF download (GET for easy PHP integration)."""
    from app.services.pdf_service import generate_handbook_pdf

    try:
        pdf_bytes = await generate_handbook_pdf(
            catalog_id=catalog_id,
            include_inactive_programs=include_inactive_programs,
            debug=debug,
        )
        return Response(
            content=pdf_bytes,
            media_type="application/pdf",
            headers={
                "Content-Disposition": 'attachment; filename="ISP_Handbook.pdf"',
                "Cache-Control": "private, max-age=0, must-revalidate",
            },
        )
    except Exception as exc:
        logger.exception("PDF generation failed")
        raise HTTPException(status_code=500, detail=str(exc))


@router.post("/api/v1/handbook/pdf", tags=["handbook"])
async def generate_handbook_pdf_post(request: HandbookRequest):
    """Generate the ISP Handbook as a PDF download (POST with body)."""
    from app.services.pdf_service import generate_handbook_pdf

    try:
        pdf_bytes = await generate_handbook_pdf(
            catalog_id=request.catalog_id,
            include_inactive_programs=request.include_inactive_programs,
            debug=request.debug,
        )
        return Response(
            content=pdf_bytes,
            media_type="application/pdf",
            headers={
                "Content-Disposition": 'attachment; filename="ISP_Handbook.pdf"',
                "Cache-Control": "private, max-age=0, must-revalidate",
            },
        )
    except Exception as exc:
        logger.exception("PDF generation failed")
        raise HTTPException(status_code=500, detail=str(exc))


@router.get("/api/v1/handbook/html", tags=["handbook"])
async def generate_handbook_html_get(
    catalog_id: int = Query(0),
    include_inactive_programs: bool = Query(False),
    debug: bool = Query(False),
):
    """Generate the ISP Handbook as raw HTML (useful for preview/debugging)."""
    from app.services.pdf_service import generate_handbook_html

    try:
        html = await generate_handbook_html(
            catalog_id=catalog_id,
            include_inactive_programs=include_inactive_programs,
            debug=debug,
        )
        return HTMLResponse(content=html)
    except Exception as exc:
        logger.exception("HTML generation failed")
        raise HTTPException(status_code=500, detail=str(exc))


@router.post("/api/v1/handbook/render", tags=["handbook"])
async def render_handbook(request: HandbookRequest):
    """Generate handbook in the requested format (pdf or html)."""
    if request.output_format == "html":
        from app.services.pdf_service import generate_handbook_html
        try:
            html = await generate_handbook_html(
                catalog_id=request.catalog_id,
                include_inactive_programs=request.include_inactive_programs,
                debug=request.debug,
            )
            return HTMLResponse(content=html)
        except Exception as exc:
            logger.exception("HTML generation failed")
            raise HTTPException(status_code=500, detail=str(exc))
    else:
        from app.services.pdf_service import generate_handbook_pdf
        try:
            pdf_bytes = await generate_handbook_pdf(
                catalog_id=request.catalog_id,
                include_inactive_programs=request.include_inactive_programs,
                debug=request.debug,
            )
            return Response(
                content=pdf_bytes,
                media_type="application/pdf",
                headers={
                    "Content-Disposition": 'attachment; filename="ISP_Handbook.pdf"',
                    "Cache-Control": "private, max-age=0, must-revalidate",
                },
            )
        except Exception as exc:
            logger.exception("PDF generation failed")
            raise HTTPException(status_code=500, detail=str(exc))