mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 11:16:47 +00:00
chore(deps): the icons come from the committed cache, not django-bootstrap-icons
django-bootstrap-icons (last release July 2024) only read the SVG of
each {% bs_icon %} from static/icon_cache; for an icon not there it
fetched the SVG from a CDN while rendering the page, and it brought
defusedxml along. A 20-line template tag in webvirtcloud reads the
same files; the package, its CDN path and the BS_ICONS_CACHE setting
go. requests stays: websockify needs it.
This commit is contained in:
parent
74483fc5f3
commit
2573228569
5 changed files with 39 additions and 12 deletions
|
|
@ -1,8 +1,7 @@
|
|||
Django==5.2.18
|
||||
django_bootstrap5==26.3
|
||||
django-bootstrap-icons==0.9.0
|
||||
django-otp==1.7.4
|
||||
# for django-bootstrap-icons and websockify; a host's python3-requests would
|
||||
# for websockify; a host's python3-requests would
|
||||
# otherwise bring idna, requests and urllib3 with advisories
|
||||
idna>=3.15
|
||||
requests>=2.33.0
|
||||
|
|
|
|||
24
webvirtcloud/bootstrap_icons.py
Normal file
24
webvirtcloud/bootstrap_icons.py
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
"""{% bs_icon %}: a Bootstrap icon's SVG, inline, from static/icon_cache,
|
||||
which holds each icon a template uses at the size, color and classes it
|
||||
asks for (webvirtcloud/tests/test_icon_cache.py checks every template)."""
|
||||
|
||||
from functools import cache
|
||||
from pathlib import Path
|
||||
|
||||
from django import template
|
||||
from django.conf import settings
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
register = template.Library()
|
||||
|
||||
ICONS = Path(settings.BASE_DIR, "static", "icon_cache")
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def bs_icon(name, size=None, color=None, extra_classes=None):
|
||||
return _svg(f"{name}_{size}_{color}_{extra_classes}.svg".replace(" ", "_"))
|
||||
|
||||
|
||||
@cache # one file a literal of the templates
|
||||
def _svg(file_name):
|
||||
return mark_safe((ICONS / file_name).read_text(encoding="utf-8"))
|
||||
|
|
@ -62,7 +62,6 @@ INSTALLED_APPS = [
|
|||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
"django_bootstrap5",
|
||||
"django_bootstrap_icons",
|
||||
"django_otp",
|
||||
"django_otp.plugins.otp_totp",
|
||||
"drf_spectacular",
|
||||
|
|
@ -127,6 +126,7 @@ TEMPLATES = [
|
|||
],
|
||||
"libraries": {
|
||||
"common_tags": "webvirtcloud.common_tags",
|
||||
"bootstrap_icons": "webvirtcloud.bootstrap_icons",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -227,8 +227,6 @@ STATICFILES_DIRS = [BASE_DIR / "static"]
|
|||
STATIC_ROOT = BASE_DIR / "staticfiles"
|
||||
|
||||
|
||||
BS_ICONS_CACHE = Path.joinpath(BASE_DIR, 'static/icon_cache')
|
||||
|
||||
# Default primary key field type
|
||||
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
"""Every {% bs_icon %} of the templates is in the committed icon cache
|
||||
(BS_ICONS_CACHE). A missing one is fetched from the CDN when a page is
|
||||
rendered, or shown as an error where the server has no internet access."""
|
||||
(webvirtcloud/bootstrap_icons.py): a missing one is an error page."""
|
||||
|
||||
import re
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
from django.conf import settings
|
||||
from django.template import Context, Template
|
||||
|
||||
from webvirtcloud.bootstrap_icons import ICONS
|
||||
|
||||
BASE = Path(settings.BASE_DIR)
|
||||
CALL = re.compile(r"\{%\s*bs_icon\s+(.*?)\s*%\}")
|
||||
|
|
@ -16,7 +18,7 @@ KWARG = re.compile(r"""(\w+)=['"]([^'"]*)['"]""")
|
|||
|
||||
class IconCacheTestCase(unittest.TestCase):
|
||||
def test_every_template_icon_is_cached(self):
|
||||
cache = Path(settings.BS_ICONS_CACHE)
|
||||
cache = ICONS
|
||||
missing = []
|
||||
templates = [*BASE.glob("templates/**/*.html"), *BASE.glob("*/templates/**/*.html")]
|
||||
self.assertGreater(len(templates), 50) # the globs still find the templates
|
||||
|
|
@ -25,8 +27,13 @@ class IconCacheTestCase(unittest.TestCase):
|
|||
name = NAME.match(args)
|
||||
self.assertIsNotNone(name, f"{template}: icon name is not a literal: {args}")
|
||||
kw = dict(KWARG.findall(args))
|
||||
# the file name django-bootstrap-icons uses for its cache
|
||||
# the file name bs_icon reads
|
||||
cached = f"{name.group(1)}_{kw.get('size')}_{kw.get('color')}_{kw.get('extra_classes')}.svg".replace(" ", "_")
|
||||
if not (cache / cached).exists():
|
||||
missing.append(f"{template.relative_to(BASE)}: {cached}")
|
||||
self.assertEqual(missing, [])
|
||||
|
||||
def test_an_icon_is_its_svg_inline(self):
|
||||
html = Template("{% load bootstrap_icons %}{% bs_icon 'pencil' %}").render(Context())
|
||||
self.assertEqual(html, (ICONS / "pencil_None_None_None.svg").read_text(encoding="utf-8"))
|
||||
self.assertIn("<svg", html)
|
||||
|
|
|
|||
|
|
@ -18,14 +18,13 @@ class StaticFilesTestCase(SimpleTestCase):
|
|||
self.assertIn(SOURCE, [Path(d) for d in settings.STATICFILES_DIRS])
|
||||
|
||||
def test_no_collected_files_in_the_source_dir(self):
|
||||
for byproduct in ("staticfiles.json", "rest_framework", "bootstrap_icons"):
|
||||
for byproduct in ("staticfiles.json", "rest_framework"):
|
||||
self.assertFalse((SOURCE / byproduct).exists(), byproduct)
|
||||
self.assertEqual(list(SOURCE.rglob("*.gz")), [])
|
||||
|
||||
def test_collectstatic_gathers_source_and_app_assets(self):
|
||||
with tempfile.TemporaryDirectory() as root, override_settings(STATIC_ROOT=root):
|
||||
call_command("collectstatic", "--noinput", verbosity=0)
|
||||
for name in ("css/webvirtcloud.css", "rest_framework/css/bootstrap.min.css",
|
||||
"bootstrap_icons/css/bootstrap_icons.css"):
|
||||
for name in ("css/webvirtcloud.css", "rest_framework/css/bootstrap.min.css"):
|
||||
self.assertTrue((Path(root) / name).exists(), name)
|
||||
self.assertIsNotNone(finders.find("css/webvirtcloud.css"))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue