Download templates_setup.py from ItsBounvy/bot_host: direct link, hf CLI and curl.
- Browser
- Download file 5.98 kB
-
https://huggingface.co/spaces/ItsBounvy/bot_host/resolve/main/templates_setup.py
- Command line
-
hf download hf://spaces/ItsBounvy/bot_host/templates_setup.py
-
curl -L -o templates_setup.py https://huggingface.co/spaces/ItsBounvy/bot_host/resolve/main/templates_setup.py
5.98 kB
| """Shared Jinja2 environment for the hosting panel. | |
| Extracted out of ``app.py`` so both ``app.py`` and ``routes.py`` can | |
| import ``templates`` without triggering a circular import. | |
| We deliberately keep this module free of FastAPI / DB imports β | |
| it's pure Jinja2 + the shared icon helper. | |
| CSRF token handling | |
| ------------------- | |
| The CSRF token is resolved per-render via the request's ``state`` | |
| (``request.state.csrf_token``) β set by ``_set_csrf_cookie`` in | |
| the same handler β with a fallback to the incoming cookie. Templates | |
| call ``{{ csrf_token() }}`` through a Jinja global callable that | |
| always receives the active render context (containing the request). | |
| """ | |
| from __future__ import annotations | |
| from typing import Any | |
| from fastapi.templating import Jinja2Templates | |
| from jinja2 import pass_context | |
| from config import PANEL_CONFIG | |
| from icons import panel_icon | |
| from i18n import gettext, ngettext, available_languages, _detect_lang | |
| templates = Jinja2Templates(directory=str(PANEL_CONFIG.templates_dir)) | |
| def _csrf_token(context) -> str: | |
| """Return the CSRF token for the current request. | |
| Resolution order: | |
| 1. ``request.state.csrf_token`` β pre-seeded by middleware before | |
| the route runs. Preferred on first render because | |
| ``request.cookies`` is empty at that point (the response | |
| cookie hasn't been written yet), so using it would produce | |
| an empty hidden input β Pydantic 422 "Field required". | |
| 2. ``request.cookies.get('csrf_token')`` β set by a previous | |
| request. The browser sends it back, the template uses it, | |
| and the response cookie matches. | |
| 3. Empty string β only happens if a template forgets to call | |
| ``_set_csrf_cookie`` before rendering. | |
| """ | |
| request = context.get("request") if hasattr(context, "get") else None | |
| if request is None: | |
| return "" | |
| state_token = getattr(getattr(request, "state", None), "csrf_token", None) | |
| if state_token: | |
| return state_token | |
| return request.cookies.get("csrf_token", "") | |
| def _panel_flashes(context) -> list: | |
| """Return the list of queued toast notifications for this request. | |
| Populated by ``_flash_middleware`` (app.py) just before the route | |
| runs; the middleware also schedules the cookie for deletion on the | |
| response. Templates should call this and pipe the result into | |
| ``window.PANEL_FLASHES`` so ``panel_flash.js`` can render them. | |
| Returning ``[]`` (never ``None``) keeps the template expression | |
| ``panel_flashes() | tojson`` simple. | |
| """ | |
| request = context.get("request") if hasattr(context, "get") else None | |
| if request is None: | |
| return [] | |
| return getattr(getattr(request, "state", None), "flashes", []) or [] | |
| def _panel_assets_v(context) -> str: | |
| """Per-deploy asset-bust token. | |
| Returns the current UNIX timestamp (truncated to seconds) so that | |
| ``{{ panel_assets_v() }}`` produces something like ``?v=1720123456``. | |
| We append this to ``/static/css/*.css`` and ``/static/js/*.js`` | |
| URLs to defeat the browser's "aggressive cache + same path = use | |
| cached copy" default after a deploy ships new animations / copy. | |
| Without the token, a user who landed on /dashboard before the | |
| deploy keeps serving the OLD CSS for the lifetime of their browser | |
| cache β and the new toast animations silently don't fire. | |
| Hot-reload note: the token changes on process start, so the user's | |
| very first request after each panel boot does a fresh GET for the | |
| asset. No DB hit, no rebuild, just a one-time CDN round-trip. | |
| """ | |
| import time as _time | |
| return str(int(_time.time())) | |
| def _gettext_context(context, source: str, **kwargs: Any) -> str: | |
| """Jinja wrapper around ``gettext`` that reads the language from | |
| ``request.state.panel_lang`` (set by middleware) or falls back to | |
| the cookie / env default.""" | |
| request = context.get("request") if hasattr(context, "get") else None | |
| lang = None | |
| if request is not None: | |
| lang = getattr(getattr(request, "state", None), "panel_lang", None) | |
| if not lang: | |
| # Fall back to cookie / env | |
| if request is not None: | |
| cookie_lang = request.cookies.get("panel_lang") | |
| if cookie_lang: | |
| lang = cookie_lang | |
| if not lang: | |
| lang = _detect_lang() | |
| # Temporarily override the env-based detection for this call | |
| import i18n as _i18n | |
| old = _i18n._detect_lang | |
| _i18n._detect_lang = lambda: lang | |
| try: | |
| return gettext(source, **kwargs) | |
| finally: | |
| _i18n._detect_lang = old | |
| def _ngettext_context(context, singular: str, plural: str, n: int, **kwargs: Any) -> str: | |
| """Jinja wrapper around ``ngettext``.""" | |
| request = context.get("request") if hasattr(context, "get") else None | |
| lang = None | |
| if request is not None: | |
| lang = getattr(getattr(request, "state", None), "panel_lang", None) | |
| if not lang: | |
| if request is not None: | |
| cookie_lang = request.cookies.get("panel_lang") | |
| if cookie_lang: | |
| lang = cookie_lang | |
| if not lang: | |
| lang = _detect_lang() | |
| import i18n as _i18n | |
| old = _i18n._detect_lang | |
| _i18n._detect_lang = lambda: lang | |
| try: | |
| return ngettext(singular, plural, n, **kwargs) | |
| finally: | |
| _i18n._detect_lang = old | |
| # Globals available to every template β keep this list small. | |
| templates.env.globals["panel_icon"] = panel_icon | |
| templates.env.globals["panel_title"] = PANEL_CONFIG.panel_title | |
| templates.env.globals["csrf_token"] = _csrf_token | |
| templates.env.globals["_"] = _gettext_context | |
| templates.env.globals["ngettext"] = _ngettext_context | |
| templates.env.globals["available_languages"] = available_languages | |
| templates.env.globals["_detect_lang"] = _detect_lang | |
| templates.env.globals["panel_flashes"] = _panel_flashes | |
| templates.env.globals["panel_assets_v"] = _panel_assets_v | |