Plain is headed towards 1.0! Subscribe for development updates →

 1import sys
 2import traceback
 3
 4from plain.runtime import settings
 5from plain.templates import Template
 6from plain.urls.exceptions import Resolver404
 7from plain.utils.safestring import mark_safe
 8
 9from .registry import register_toolbar_panel, registry
10
11
12class Toolbar:
13    def __init__(self, request):
14        self.request = request
15        self.version = settings.APP_VERSION
16
17    def should_render(self):
18        if settings.DEBUG:
19            return True
20
21        if hasattr(self.request, "impersonator"):
22            return self.request.impersonator.is_admin
23
24        if hasattr(self.request, "user"):
25            return self.request.user.is_admin
26
27        return False
28
29    def request_exception(self):
30        # We can capture the exception currently being handled here, if any.
31        exception = sys.exception()
32
33        if exception and not isinstance(exception, Resolver404):
34            exception._traceback_string = "".join(
35                traceback.format_tb(exception.__traceback__)
36            )
37            return exception
38
39    def get_panels(self):
40        panels = [panel(self.request) for panel in registry.get_panels()]
41
42        if self.request_exception():
43            exception = self.request_exception()
44            panels = [
45                _ExceptionToolbarPanel(self.request, exception),
46            ] + panels
47
48        return panels
49
50
51class ToolbarPanel:
52    name: str
53    template_name: str
54    button_template_name: str = ""
55
56    def __init__(self, request):
57        self.request = request
58
59    def get_template_context(self):
60        return {
61            "request": self.request,
62            "panel": self,
63        }
64
65    def render(self):
66        template = Template(self.template_name)
67        context = self.get_template_context()
68        return mark_safe(template.render(context))
69
70    def render_button(self):
71        """Render the toolbar button for the minimized state."""
72        if not self.button_template_name:
73            return ""
74        template = Template(self.button_template_name)
75        context = self.get_template_context()
76        return mark_safe(template.render(context))
77
78
79class _ExceptionToolbarPanel(ToolbarPanel):
80    name = "Exception"
81    template_name = "toolbar/exception.html"
82    button_template_name = "toolbar/exception_button.html"
83
84    def __init__(self, request, exception):
85        super().__init__(request)
86        self.exception = exception
87
88    def get_template_context(self):
89        context = super().get_template_context()
90        context["exception"] = self.exception
91        return context
92
93
94@register_toolbar_panel
95class _RequestToolbarPanel(ToolbarPanel):
96    name = "Request"
97    template_name = "toolbar/request.html"