1from functools import cached_property
2
3from plain.assets.views import AssetView
4from plain.http import (
5 Http404,
6 Response,
7 ResponseRedirect,
8)
9from plain.views import TemplateView, View
10
11from .exceptions import PageNotFoundError, RedirectPageError
12from .registry import pages_registry
13
14
15class PageViewMixin:
16 @cached_property
17 def page(self):
18 url_name = self.request.resolver_match.url_name
19
20 try:
21 return pages_registry.get_page_from_name(url_name)
22 except PageNotFoundError:
23 raise Http404()
24
25
26class PageView(PageViewMixin, TemplateView):
27 template_name = "page.html"
28
29 def get_template_names(self) -> list[str]:
30 """
31 Allow for more specific user templates like
32 markdown.html or html.html
33 """
34 if template_name := self.page.get_template_name():
35 return [template_name]
36
37 return super().get_template_names()
38
39 def get_template_context(self):
40 context = super().get_template_context()
41 context["page"] = self.page
42 self.page.set_template_context(context) # Pass the standard context through
43 return context
44
45
46class PageRedirectView(PageViewMixin, View):
47 def get(self):
48 url = self.page.vars.get("url")
49
50 if not url:
51 raise RedirectPageError("Redirect page is missing a url")
52
53 status_code = self.page.vars.get("status_code", 302)
54 return ResponseRedirect(url, status_code=status_code)
55
56
57class PageAssetView(PageViewMixin, AssetView):
58 def get_url_path(self):
59 return self.page.get_url_path()
60
61 def get_asset_path(self, path):
62 return self.page.absolute_path
63
64 def get_debug_asset_path(self, path):
65 return self.page.absolute_path
66
67
68class PageMarkdownView(PageViewMixin, View):
69 def get(self):
70 """Serve the markdown content without frontmatter."""
71 markdown_content = self.page._frontmatter.content
72 response = Response(markdown_content, content_type="text/plain; charset=utf-8")
73 response.headers["Vary"] = (
74 "Accept-Encoding" # Set Vary header for proper caching
75 )
76 return response