Plain is headed towards 1.0! Subscribe for development updates →

 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