Cat Feeder  1.0.0
The Cat feeder project
Loading...
Searching...
No Matches
rapipdf_provider.py
Go to the documentation of this file.
1r"""
2# +==== BEGIN CatFeeder =================+
3# LOGO:
4# ..............(..../\
5# ...............)..(.')
6# ..............(../..)
7# ...............\‍(__)|
8# Inspired by Joan Stark
9# source https://www.asciiart.eu/
10# animals/cats
11# /STOP
12# PROJECT: CatFeeder
13# FILE: rapipdf_provider.py
14# CREATION DATE: 26-11-2025
15# LAST Modified: 2:10:5 24-01-2026
16# DESCRIPTION:
17# This is the backend server in charge of making the actual website work.
18# /STOP
19# COPYRIGHT: (c) Cat Feeder
20# PURPOSE: RapiPDF documentation provider implementation.
21# // AR
22# +==== END CatFeeder =================+
23"""
24import os
25from typing import TYPE_CHECKING
26from display_tty import Disp, initialise_logger
27from fastapi import Request, Response
28from . import rapipdf_constants as RAPIPDF_CONST
29from ...http_codes import HCI, HttpDataTypes
30from ...core.runtime_manager import RuntimeManager, RI
31from ...server_header import ServerHeaders
32from ...boilerplates import BoilerplateResponses, BoilerplateIncoming
33
34if TYPE_CHECKING:
35 from ...path_manager.path_manager import PathManager
36
37
39 """RapiPDF documentation provider.
40
41 Provides PDF generation interface for OpenAPI documentation.
42 """
43
44 disp: Disp = initialise_logger(__qualname__, False)
45
46 def __init__(self, openapi_url: str, api_title: str, success: int = 0, error: int = 84, debug: bool = False) -> None:
47 """Initialize RapiPDF provider.
48
49 Args:
50 openapi_url (str): URL to OpenAPI JSON schema.
51 api_title (str): Title of the API.
52 debug (bool, optional): Enable debug logging. Defaults to False.
53 """
54 self.disp.update_disp_debug(debug)
55 self.disp.log_debug("Initialising RapiPDF provider...")
56
57 self.success = success
58 self.error = error
59 self.openapi_url = openapi_url
60 self.api_title = api_title
61 self.runtime_manager: RuntimeManager = RI
62 self.server_headers_initialised: ServerHeaders = self.runtime_manager.get(
63 ServerHeaders)
64 self.boilerplate_responses_initialised: BoilerplateResponses = self.runtime_manager.get(
65 BoilerplateResponses)
66 self.boilerplate_incoming_initialised: BoilerplateIncoming = self.runtime_manager.get(
67 BoilerplateIncoming)
68
69 self.disp.log_debug("RapiPDF provider initialised")
70
71 async def get_documentation(self, request: Request) -> Response:
72 """Serve RapiPDF documentation page.
73
74 Args:
75 request (Request): The incoming request.
76
77 Returns:
78 Response: HTML response with RapiPDF interface.
79 """
80 func_title = "get_documentation"
81 self.disp.log_debug("Serving RapiPDF documentation", func_title)
82
83 token = self.boilerplate_incoming_initialised.get_token_if_present(
84 request)
85 self.disp.log_debug(f"token = {token}", func_title)
86
87 config_options = {}
88 for key, value in RAPIPDF_CONST.RAPIPDF_OPTIONS.items():
89 if isinstance(value, bool):
90 if value:
91 config_options[key] = "true"
92 else:
93 config_options[key] = "false"
94 else:
95 config_options[key] = value
96
97 pdf_primary = config_options.get("pdf-primary-color", "#4A90E2")
98 pdf_alternate = config_options.get("pdf-alternate-color", "#F5F5F5")
99 pdf_title = config_options.get("pdf-title", "API Documentation")
100 pdf_footer = config_options.get("pdf-footer-text", "")
101 include_api_list = config_options.get("include-api-list", "true")
102 include_api_details = config_options.get("include-api-details", "true")
103 include_security = config_options.get("include-security", "true")
104
105 if RAPIPDF_CONST.RAPIPDF_STYLE == "dark":
106 bg_color = "#1a1a1a"
107 text_color = "#ffffff"
108 status_text_color = "#000000"
109 else:
110 bg_color = "#ffffff"
111 text_color = "#000000"
112 status_text_color = "#333333"
113
114 html_content = f"""
115<!DOCTYPE html>
116<html lang="en">
117<head>
118 <meta charset="UTF-8">
119 <meta name="viewport" content="width=device-width, initial-scale=1.0">
120 <title>{self.api_title} - RapiPDF</title>
121 <script type="module" src="{RAPIPDF_CONST.RAPIPDF_CDN_JS_ENDPOINT}"></script>
122 <style>
123 body {{
124 margin: 0;
125 padding: 20px;
126 font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
127 background-color: {bg_color};
128 color: {text_color};
129 }}
130 .container {{
131 max-width: 1200px;
132 margin: 0 auto;
133 }}
134 h1 {{
135 margin-bottom: 10px;
136 }}
137 p {{
138 margin-bottom: 30px;
139 color: {text_color};
140 }}
141 rapi-pdf {{
142 --primary-color: {pdf_primary};
143 --input-bg: {bg_color};
144 --fg: {text_color};
145 --primary-text: white;
146 --font-size: 14px;
147 width: 100%;
148 max-width: 500px;
149 }}
150 </style>
151</head>
152<body>
153 <div class="container">
154 <h1>{self.api_title} - PDF Documentation</h1>
155 <p>Generate a comprehensive PDF document of the API specification.</p>
156
157 <rapi-pdf
158 spec-url="{self.openapi_url}"
159 style="{RAPIPDF_CONST.RAPIPDF_STYLE}"
160 pdf-title="{pdf_title}"
161 pdf-footer-text="{pdf_footer}"
162 pdf-primary-color="{pdf_primary}"
163 pdf-alternate-color="{pdf_alternate}"
164 include-api-list="{str(include_api_list).lower()}"
165 include-api-details="{str(include_api_details).lower()}"
166 include-security="{str(include_security).lower()}"
167 button-label="{RAPIPDF_CONST.RAPIPDF_BUTTON_LABEL}"
168 hide-input="false"
169 ></rapi-pdf>
170 </div>
171</body>
172</html>
173"""
174 return HCI.success(content=html_content, content_type=HttpDataTypes.HTML)
175
176 async def get_rapipdf_cdn_js_ressource(self, request: Request) -> Response:
177 """Serve the RapiPDF JavaScript library file.
178
179 Args:
180 request (Request): The incoming request.
181
182 Returns:
183 Response: JavaScript file response or error response if file not found.
184 """
185 file = RAPIPDF_CONST.RAPIPDF_CDN_JS
186 if not os.path.isfile(file):
187 error_msg: str = f"Filepath: {file} does not exist or is not a file"
188 self.disp.log_error(error_msg)
189 return HCI.not_found(error_msg, content_type=HttpDataTypes.TEXT, headers=self.server_headers_initialised.for_text())
190 return HCI.success(file, content_type=HttpDataTypes.JAVASCRIPT, headers=self.server_headers_initialised.for_javascript())
191
192 def inject_js_ressource(self, path_handler: "PathManager") -> int:
193 """Register the JavaScript resource endpoint with the path manager.
194
195 Args:
196 path_handler (PathManager): The path manager instance to register the endpoint with.
197
198 Returns:
199 int: Success or error code from the path registration.
200 """
201 return path_handler.add_path_if_not_exists(
202 RAPIPDF_CONST.RAPIPDF_CDN_JS_ENDPOINT,
204 "GET"
205 )
206
207 def get_url(self) -> str:
208 """Get the URL path for this documentation provider.
209
210 Returns:
211 str: The URL path.
212 """
213 return RAPIPDF_CONST.RAPIPDF_URL
None __init__(self, str openapi_url, str api_title, int success=0, int error=84, bool debug=False)