Coverage for an_website/endpoints/endpoints.py: 96.154%
26 statements
« prev ^ index » next coverage.py v7.6.4, created at 2024-11-16 19:56 +0000
« prev ^ index » next coverage.py v7.6.4, created at 2024-11-16 19:56 +0000
1# This program is free software: you can redistribute it and/or modify
2# it under the terms of the GNU Affero General Public License as
3# published by the Free Software Foundation, either version 3 of the
4# License, or (at your option) any later version.
5#
6# This program is distributed in the hope that it will be useful,
7# but WITHOUT ANY WARRANTY; without even the implied warranty of
8# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9# GNU Affero General Public License for more details.
10#
11# You should have received a copy of the GNU Affero General Public License
12# along with this program. If not, see <https://www.gnu.org/licenses/>.
14"""Show a list of all API endpoints."""
16from __future__ import annotations
18from typing import ClassVar, cast
20import orjson as json
22from .. import ORJSON_OPTIONS
23from ..utils.request_handler import APIRequestHandler, HTMLRequestHandler
24from ..utils.utils import ModuleInfo, Permission, name_to_id
27def get_module_info() -> ModuleInfo:
28 """Create and return the ModuleInfo for this module."""
29 return ModuleInfo(
30 handlers=(
31 ("/endpunkte", Endpoints),
32 ("/api/endpunkte", EndpointsAPI),
33 ),
34 name="API-Endpunkte",
35 description="Alle API-Endpunkte unserer Webseite",
36 path="/endpunkte",
37 aliases={
38 "/endpoints": "/endpunkte",
39 "/api": "/api/endpunkte",
40 "/api/endpoints": "/api/endpunkte",
41 },
42 keywords=("API", "Endpoints", "Endpunkte"),
43 )
46class Endpoints(HTMLRequestHandler):
47 """Endpoint page request handler."""
49 async def get(self, *, head: bool = False) -> None:
50 """Handle a GET request."""
51 if head:
52 return
53 return await self.render(
54 "pages/endpoints.html",
55 endpoints=self.get_endpoints(),
56 name_to_id=name_to_id,
57 )
59 def get_endpoints(
60 self,
61 ) -> list[dict[str, str | list[dict[str, str | list[str]]]]]:
62 """Get a list of all API endpoints and return it."""
63 endpoints: list[dict[str, str | list[dict[str, str | list[str]]]]] = []
64 for module_info in self.settings["MODULE_INFOS"]:
65 api_paths: list[dict[str, str | list[str]]] = [
66 {
67 "path": handler[0],
68 "methods": methods,
69 "content_types": list(handler[1].POSSIBLE_CONTENT_TYPES),
70 }
71 for handler in module_info.handlers
72 if handler[0].startswith("/api/")
73 if issubclass(handler[1], APIRequestHandler)
74 if (
75 methods := [
76 method.upper()
77 for method in handler[1].get_allowed_methods()
78 if (
79 perm := getattr(
80 getattr(handler[1], method.lower()),
81 "required_perms",
82 None,
83 )
84 )
85 is None
86 or self.is_authorized(cast(Permission, perm))
87 ]
88 )
89 if methods != ["OPTIONS"]
90 ]
91 if len(api_paths) > 0:
92 endpoints.append(
93 {
94 "name": module_info.name,
95 "description": module_info.description,
96 "endpoints": api_paths,
97 }
98 )
99 return endpoints
102class EndpointsAPI(APIRequestHandler, Endpoints):
103 """Show a list of all API endpoints."""
105 POSSIBLE_CONTENT_TYPES: ClassVar[tuple[str, ...]] = (
106 APIRequestHandler.POSSIBLE_CONTENT_TYPES + ("application/x-ndjson",)
107 )
109 async def get(self, *, head: bool = False) -> None:
110 """Handle a GET request."""
111 if self.content_type == "application/x-ndjson":
112 await self.finish(
113 b"\n".join(
114 json.dumps(endpoint, option=ORJSON_OPTIONS)
115 for endpoint in self.get_endpoints()
116 )
117 )
118 else:
119 await self.finish(self.dump(self.get_endpoints()))