v0.165.0
  1import sys
  2from typing import TYPE_CHECKING, Any
  3
  4from jinja2.runtime import Context
  5from plain.runtime import settings
  6from plain.templates import Template
  7from plain.utils.safestring import SafeString, mark_safe
  8
  9from .registry import register_toolbar_item, registry
 10
 11if TYPE_CHECKING:
 12    from plain.http import Request
 13
 14try:
 15    from plain.auth import get_request_user
 16except ImportError:
 17    get_request_user: Any = None
 18
 19try:
 20    from plain.admin.impersonate import get_request_impersonator
 21except ImportError:
 22    get_request_impersonator: Any = None
 23
 24
 25class Toolbar:
 26    def __init__(self, context: Context) -> None:
 27        self.context = context
 28        self.request: Request = context["request"]
 29        self.version: str = settings.VERSION
 30
 31    def should_render(self) -> bool:
 32        if settings.DEBUG:
 33            return True
 34
 35        if get_request_impersonator and (
 36            impersonator := get_request_impersonator(self.request)
 37        ):
 38            return getattr(impersonator, "is_admin", False)
 39
 40        if get_request_user and (user := get_request_user(self.request)):
 41            return getattr(user, "is_admin", False)
 42
 43        return False
 44
 45    def get_items(self) -> list[ToolbarItem]:
 46        items = [item(self.context) for item in registry.get_items()]
 47        return [item for item in items if item.is_enabled()]
 48
 49
 50class ToolbarItem:
 51    name: str = ""
 52    panel_template_name: str = ""
 53    button_template_name: str = ""
 54
 55    def __init__(self, context: Context) -> None:
 56        self.context = context
 57        self.request: Request = context["request"]
 58
 59    def get_template_context(self) -> dict[str, Any]:
 60        context = dict(self.context)
 61        context["panel"] = self
 62        return context
 63
 64    def render_panel(self) -> SafeString:
 65        template = Template(self.panel_template_name)
 66        context = self.get_template_context()
 67        return mark_safe(template.render(context))
 68
 69    def render_button(self) -> SafeString:
 70        """Render the toolbar button for the minimized state."""
 71        template = Template(self.button_template_name)
 72        context = self.get_template_context()
 73        return mark_safe(template.render(context))
 74
 75    def is_enabled(self) -> bool:
 76        """Return whether this toolbar item should be displayed."""
 77        return True
 78
 79
 80@register_toolbar_item
 81class _ExceptionToolbarItem(ToolbarItem):
 82    name = "Exception"
 83    panel_template_name = "toolbar/exception.html"
 84    button_template_name = "toolbar/exception_button.html"
 85
 86    def __init__(self, context: Context) -> None:
 87        super().__init__(context)
 88        exception = sys.exception()
 89        if exception:
 90            from .exceptions import ExceptionContext
 91
 92            self.exception_context: ExceptionContext | None = ExceptionContext(
 93                exception
 94            )
 95        else:
 96            self.exception_context = None
 97
 98    def is_enabled(self) -> bool:
 99        return self.exception_context is not None
100
101    def get_template_context(self) -> dict[str, Any]:
102        ctx = super().get_template_context()
103        ctx["exception_context"] = self.exception_context
104        return ctx
105
106
107@register_toolbar_item
108class _RequestToolbarItem(ToolbarItem):
109    name = "Request"
110    panel_template_name = "toolbar/request.html"