From c23521bcf4d8f83322663e1589f84ec26fb74aaa Mon Sep 17 00:00:00 2001 From: catborise Date: Mon, 12 Oct 2026 08:14:00 +0300 Subject: [PATCH] fix(appsettings): a theme change reaches the CSS nginx serves nginx serves STATIC_ROOT (staticfiles/) since collectstatic moved there, but the theme view wrote only static/css/wvc-main.min.css, so a new theme showed up only after the next collectstatic. The view now also writes the collected copy when collectstatic has run; the source copy stays so a later collectstatic keeps the theme. --- appsettings/test_theme_name.py | 45 +++++++++++++++++++++++++++++++++- appsettings/views.py | 4 +++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/appsettings/test_theme_name.py b/appsettings/test_theme_name.py index bf64a16f..1865df30 100644 --- a/appsettings/test_theme_name.py +++ b/appsettings/test_theme_name.py @@ -2,11 +2,15 @@ SASS_DIR/wvc-themes: it is written into @import paths and the compiled CSS.""" import os +import shutil import tempfile +from pathlib import Path from appsettings.models import AppSettings +from django.conf import settings from django.contrib.auth.models import User -from django.test import TestCase +from django.contrib.messages import get_messages +from django.test import TestCase, override_settings from django.urls import reverse @@ -54,3 +58,42 @@ class SassDirTests(TestCase): AppSettings.objects.filter(key="SASS_DIR").update(value=outside.name) 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) diff --git a/appsettings/views.py b/appsettings/views.py index 7e8d26ed..59e10306 100644 --- a/appsettings/views.py +++ b/appsettings/views.py @@ -93,6 +93,10 @@ def appsettings(request): ) with open("static/css/" + main_css, "w") as css: css.write(css_compressed) + # nginx serves the collected copy; collectstatic later takes it from static/ + served = Path(settings.STATIC_ROOT or "", "css") + if settings.STATIC_ROOT and served.is_dir(): + (served / main_css).write_text(css_compressed) bootstrap_theme.value = theme bootstrap_theme.save()