-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathurls.py
More file actions
123 lines (102 loc) · 4.28 KB
/
Copy pathurls.py
File metadata and controls
123 lines (102 loc) · 4.28 KB
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
from django.conf import settings
from django.contrib import admin
from django.http import HttpRequest, HttpResponse, HttpResponseNotFound
from django.template.loader import render_to_string
from django.urls import include, path, re_path
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
from meta.views import Meta # type: ignore[import-untyped]
from api.llm_schema import LLM_SPECTACULAR_SETTINGS
_INDEX_HTML = settings.BASE_DIR / "web" / "dist" / "index.html"
_SHARE_IMAGE_SIZE = 600
class RequestMeta(Meta):
"""django-meta object that derives canonical host details from the request."""
def get_domain(self):
return self.request.get_host()
def get_protocol(self):
return self.request.scheme
def _index_html() -> str | None:
if not _INDEX_HTML.exists():
return None
return _INDEX_HTML.read_text(encoding="utf-8")
def _spa(request: HttpRequest) -> HttpResponse | HttpResponseNotFound:
index_html = _index_html()
if index_html is not None:
response = HttpResponse(index_html, content_type="text/html")
response["Cache-Control"] = "no-cache, no-store, must-revalidate"
return response
return HttpResponseNotFound("Frontend not built.")
def _share_image_url(thumbnail: dict) -> str:
"""Prefer the eagerly cropped derivative; fall back to the raw asset URL."""
return str(thumbnail.get("cropped_url") or thumbnail.get("url") or "")
def _inject_piece_metadata(index_html: str, request: HttpRequest, piece_id) -> str:
from api.models import Piece
from api.utils import image_to_dict
from api.workflow import get_state_friendly_name
piece = (
Piece.objects.select_related("thumbnail")
.prefetch_related("states", "states__image_links")
.filter(id=piece_id, shared=True)
.first()
)
if piece is None or piece.current_state is None:
return index_html
state_label = get_state_friendly_name(piece.current_state.state)
title = f"{piece.name} - {state_label}"
description = "Powered by PotterDoc"
url = request.build_absolute_uri(request.path)
thumbnail = image_to_dict(piece.thumbnail)
if thumbnail:
thumbnail["cropped_url"] = piece.get_thumbnail_cropped_url()
image_url = _share_image_url(thumbnail) if thumbnail else ""
if image_url.startswith("/"):
image_url = request.build_absolute_uri(image_url)
meta = RequestMeta(
request=request,
title=title,
description=description,
url=url,
image=image_url,
image_width=_SHARE_IMAGE_SIZE if image_url else None,
image_height=_SHARE_IMAGE_SIZE if image_url else None,
object_type="article",
site_name="PotterDoc",
twitter_type="summary_large_image",
use_og=True,
use_twitter=True,
use_title_tag=True,
)
tags = render_to_string("meta/meta.html", {"meta": meta}).strip()
index_html = index_html.replace("<title>PotterDoc</title>", tags, 1)
return index_html
def _piece_spa(request: HttpRequest, piece_id) -> HttpResponse | HttpResponseNotFound:
index_html = _index_html()
if index_html is None:
return HttpResponseNotFound("Frontend not built.")
response = HttpResponse(
_inject_piece_metadata(index_html, request, piece_id),
content_type="text/html",
)
response["Cache-Control"] = "no-cache, no-store, must-revalidate"
return response
urlpatterns = [
path(f"{settings.ADMIN_URL}/", admin.site.urls),
path("api/", include("api.urls")),
path("support/", include("helpdesk.urls")),
path("api/schema/", SpectacularAPIView.as_view(), name="schema"),
path(
"api/schema/llm/",
SpectacularAPIView.as_view(custom_settings=LLM_SPECTACULAR_SETTINGS),
name="schema-llm",
),
path(
"api/schema/swagger/",
SpectacularSwaggerView.as_view(url_name="schema"),
name="swagger",
),
path("pieces/<uuid:piece_id>", _piece_spa),
path("pieces/<uuid:piece_id>/showcase", _piece_spa),
# Catch-all: serve the React SPA for client routes only. File-like URLs
# (for example Vite chunk files) must fall through so static handling can
# return the real asset or a 404 instead of HTML.
re_path(rf"^(?!api/|{settings.ADMIN_URL}|static/|.*\..*$).*$", _spa),
]