mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-10 04:06:47 +00:00
build: the themes ship compiled, libsass is no longer installed
A theme change compiled Bootswatch with libsass (34 MB, upstream deprecated) into two tracked files, which updates, rollbacks and new Docker containers then reset. The 27 themes now ship as static/css/themes/<theme>.min.css, built by "manage.py build_themes"; the Settings page only saves the theme name and every page links that file (zephyr when no settings are in context, as on the 500 page). libsass moves to dev/requirements.txt; a test checks that each shipped file is its theme compiled from dev/scss. The "Theme SASS Path" setting is removed, and the theme default "flaty", a typo that never applied, becomes zephyr, the theme those installs showed. The update and rollback steps restore an older version's rewritten theme files only where they are modified.
This commit is contained in:
parent
28a73519d7
commit
41468c700d
43 changed files with 315 additions and 298 deletions
|
|
@ -1,99 +1,30 @@
|
|||
"""The theme name posted on the settings page must be one of the themes in
|
||||
SASS_DIR/wvc-themes: it is written into @import paths and the compiled CSS."""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
"""The settings page picks one of the prebuilt themes in static/css/themes;
|
||||
every page links the chosen theme's file."""
|
||||
|
||||
from appsettings.models import AppSettings
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.messages import get_messages
|
||||
from django.test import TestCase, override_settings
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
from lxml import html
|
||||
|
||||
|
||||
class ThemeNameTests(TestCase):
|
||||
def setUp(self):
|
||||
self.client.force_login(User.objects.create_superuser("th-admin", "th@example.com", "pw"))
|
||||
self.sass = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(self.sass.cleanup)
|
||||
os.makedirs(os.path.join(self.sass.name, "wvc-themes", "flatly"))
|
||||
AppSettings.objects.filter(key="SASS_DIR").update(value=self.sass.name)
|
||||
self.before = AppSettings.objects.get(key="BOOTSTRAP_THEME").value
|
||||
|
||||
def theme_link(self, url):
|
||||
(href,) = html.fromstring(self.client.get(url).content).xpath("//link[@id='wvc_css']/@href")
|
||||
return href
|
||||
|
||||
def test_a_name_that_is_not_a_theme_is_refused(self):
|
||||
for theme in ("../../etc", "flatly';@import '/etc/passwd", "nope", ""):
|
||||
for theme in ("../../etc", "flatly.min.css", "nope", ""):
|
||||
with self.subTest(theme=theme):
|
||||
self.client.post(reverse("appsettings"), {"BOOTSTRAP_THEME": theme})
|
||||
self.assertFalse(os.path.exists(os.path.join(self.sass.name, "wvc-main.scss")))
|
||||
self.assertEqual(AppSettings.objects.get(key="BOOTSTRAP_THEME").value, self.before)
|
||||
|
||||
|
||||
class SassDirTests(TestCase):
|
||||
"""SASS_DIR must be a directory inside the project: the page lists it and
|
||||
writes wvc-main.scss into it."""
|
||||
|
||||
def setUp(self):
|
||||
self.client.force_login(User.objects.create_superuser("sd-admin", "sd@example.com", "pw"))
|
||||
self.before = AppSettings.objects.get(key="SASS_DIR").value
|
||||
|
||||
def test_a_directory_outside_the_project_is_refused(self):
|
||||
outside = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(outside.cleanup)
|
||||
for value in (outside.name, "/etc", "../", "dev/scss/../../..", "no/such/dir"):
|
||||
with self.subTest(value=value):
|
||||
self.client.post(reverse("appsettings"), {"SASS_DIR": value})
|
||||
self.assertEqual(AppSettings.objects.get(key="SASS_DIR").value, self.before)
|
||||
|
||||
def test_the_project_scss_directory_is_accepted(self):
|
||||
self.client.post(reverse("appsettings"), {"SASS_DIR": "dev/scss"})
|
||||
self.assertEqual(AppSettings.objects.get(key="SASS_DIR").value, "dev/scss")
|
||||
|
||||
def test_a_stored_directory_outside_the_project_is_not_used(self):
|
||||
outside = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(outside.cleanup)
|
||||
os.makedirs(os.path.join(outside.name, "wvc-themes", "flatly"))
|
||||
AppSettings.objects.filter(key="SASS_DIR").update(value=outside.name)
|
||||
def test_pages_link_the_chosen_theme(self):
|
||||
self.assertEqual(self.theme_link(reverse("appsettings")), "/static/css/themes/zephyr.min.css")
|
||||
self.client.post(reverse("appsettings"), {"BOOTSTRAP_THEME": "flatly"})
|
||||
self.assertFalse(os.path.exists(os.path.join(outside.name, "wvc-main.scss")))
|
||||
|
||||
|
||||
class ThemeCssTests(TestCase):
|
||||
"""A theme change also rewrites the collected wvc-main.min.css: nginx
|
||||
serves STATIC_ROOT, not static/."""
|
||||
|
||||
def setUp(self):
|
||||
self.client.force_login(User.objects.create_superuser("tc-admin", "tc@example.com", "pw"))
|
||||
project = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(project.cleanup)
|
||||
self.project = Path(project.name)
|
||||
shutil.copytree(Path(settings.BASE_DIR, "dev", "scss"), self.project / "dev" / "scss")
|
||||
(self.project / "static" / "css").mkdir(parents=True)
|
||||
cwd = os.getcwd()
|
||||
os.chdir(self.project)
|
||||
self.addCleanup(os.chdir, cwd)
|
||||
AppSettings.objects.filter(key="SASS_DIR").update(value="dev/scss")
|
||||
|
||||
def change_theme(self, static_root):
|
||||
with override_settings(BASE_DIR=self.project, STATIC_ROOT=static_root):
|
||||
response = self.client.post(reverse("appsettings"), {"BOOTSTRAP_THEME": "flatly"})
|
||||
self.assertIn("Theme is changed. Now: flatly", [str(m) for m in get_messages(response.wsgi_request)])
|
||||
self.assertEqual(AppSettings.objects.get(key="BOOTSTRAP_THEME").value, "flatly")
|
||||
source = (self.project / "static" / "css" / "wvc-main.min.css").read_text()
|
||||
self.assertIn(".btn", source)
|
||||
return source
|
||||
|
||||
def test_the_collected_css_is_the_new_theme(self):
|
||||
served = self.project / "staticfiles" / "css" / "wvc-main.min.css"
|
||||
served.parent.mkdir(parents=True)
|
||||
served.write_text("old theme")
|
||||
self.assertEqual(served.read_text(), "old theme")
|
||||
self.assertEqual(self.change_theme(self.project / "staticfiles"), served.read_text())
|
||||
|
||||
def test_without_collected_css_only_the_source_is_written(self):
|
||||
(self.project / "staticfiles").mkdir()
|
||||
self.change_theme(self.project / "staticfiles")
|
||||
self.assertEqual(list((self.project / "staticfiles").iterdir()), [])
|
||||
self.change_theme(None)
|
||||
self.assertEqual(self.theme_link(reverse("appsettings")), "/static/css/themes/flatly.min.css")
|
||||
|
|
|
|||
|
|
@ -1,33 +1,17 @@
|
|||
"""The themes in dev/scss/wvc-themes compile with the pinned libsass, and the
|
||||
shipped wvc-main.min.css is the default theme compiled from these sources."""
|
||||
"""static/css/themes holds every theme in dev/scss/wvc-themes, compiled from
|
||||
these sources with the pinned libsass (manage.py build_themes)."""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import sass
|
||||
from django.conf import settings
|
||||
from django.test import SimpleTestCase
|
||||
|
||||
SCSS = Path(settings.BASE_DIR, "dev", "scss")
|
||||
|
||||
|
||||
def compile_theme(theme):
|
||||
# the imports the settings view compiles
|
||||
return sass.compile(
|
||||
string=f"@import '{SCSS}/wvc-themes/{theme}/variables';\n"
|
||||
f"@import '{SCSS}/bootstrap-overrides.scss';\n"
|
||||
f"@import '{SCSS}/wvc-themes/{theme}/bootswatch';",
|
||||
output_style="compressed",
|
||||
)
|
||||
from appsettings.management.commands.build_themes import SCSS, compile_theme
|
||||
from appsettings.views import THEMES_DIR
|
||||
|
||||
|
||||
class ThemeTests(SimpleTestCase):
|
||||
def test_every_theme_compiles(self):
|
||||
def test_the_shipped_themes_are_compiled_from_these_sources(self):
|
||||
themes = sorted(p.name for p in (SCSS / "wvc-themes").iterdir() if p.is_dir())
|
||||
self.assertIn("zephyr", themes)
|
||||
self.assertEqual(sorted(p.name for p in THEMES_DIR.iterdir()), [f"{theme}.min.css" for theme in themes])
|
||||
for theme in themes:
|
||||
with self.subTest(theme=theme):
|
||||
self.assertIn(".btn", compile_theme(theme))
|
||||
|
||||
def test_the_shipped_css_is_zephyr_from_these_sources(self):
|
||||
shipped = Path(settings.BASE_DIR, "static", "css", "wvc-main.min.css").read_text()
|
||||
self.assertEqual(shipped, compile_theme("zephyr"))
|
||||
self.assertEqual((THEMES_DIR / f"{theme}.min.css").read_text(), compile_theme(theme), "run manage.py build_themes")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue