From 18fe8aca9db3cc7c34cd046be10f3b8b8345bb42 Mon Sep 17 00:00:00 2001 From: Julian Leucker <leuckerj@gmail.com> Date: Sat, 2 May 2020 14:33:29 +0200 Subject: [PATCH] Optimise icon usage. Closes #184 --- aleksis/core/apps.py | 13 ++++++++-- aleksis/core/preferences.py | 28 +++++++++++++++++++-- aleksis/core/settings.py | 27 +++++++++++++------- aleksis/core/templates/core/base.html | 4 +-- aleksis/core/templates/core/base_print.html | 4 +-- aleksis/core/templates/core/meta.html | 6 ++--- aleksis/core/util/core_helpers.py | 20 ++++++++++++++- aleksis/core/views.py | 2 +- pyproject.toml | 1 + 9 files changed, 81 insertions(+), 24 deletions(-) diff --git a/aleksis/core/apps.py b/aleksis/core/apps.py index 3e2c5d5d0..492da4a3e 100644 --- a/aleksis/core/apps.py +++ b/aleksis/core/apps.py @@ -3,6 +3,7 @@ from typing import Any, List, Optional, Tuple import django.apps from django.contrib.auth.signals import user_logged_in from django.http import HttpRequest +from django.utils.translation import gettext_lazy as _ from dynamic_preferences.registries import preference_models @@ -51,8 +52,16 @@ class CoreConfig(AppConfig): **kwargs, ) -> None: if section == "theme": - # Clean compiled SCSS to invalidate it after theme changes; recreated on request - clean_scss() + if name in ("primary", "secondary"): + clean_scss() + elif name in ("favicon", "pwa_icon"): + from favicon.models import Favicon # noqa + + Favicon.on_site.update_or_create(title=name, + defaults={ + "isFavicon": name == "favicon", + "faviconImage": new_value, + }) def post_migrate( self, diff --git a/aleksis/core/preferences.py b/aleksis/core/preferences.py index cd4255fb5..a5538eb96 100644 --- a/aleksis/core/preferences.py +++ b/aleksis/core/preferences.py @@ -1,9 +1,9 @@ from django.conf import settings -from django.forms import EmailField, URLField +from django.forms import EmailField, URLField, ImageField from django.utils.translation import gettext_lazy as _ from colorfield.widgets import ColorWidget -from dynamic_preferences.types import BooleanPreference, ChoicePreference, StringPreference +from dynamic_preferences.types import BooleanPreference, ChoicePreference, StringPreference, FilePreference from dynamic_preferences.preferences import Section from dynamic_preferences.registries import global_preferences_registry @@ -56,6 +56,30 @@ class ColourSecondary(StringPreference): verbose_name = _("Secondary colour") +@site_preferences_registry.register +class Logo(FilePreference): + section = theme + field_class = ImageField + name = "logo" + verbose_name = _("Logo") + + +@site_preferences_registry.register +class Favicon(FilePreference): + section = theme + field_class = ImageField + name = "favicon" + verbose_name = _("Favicon") + + +@site_preferences_registry.register +class PWAIcon(FilePreference): + section = theme + field_class = ImageField + name = "pwa_icon" + verbose_name = _("PWA-Icon") + + @site_preferences_registry.register class MailOutName(StringPreference): section = mail diff --git a/aleksis/core/settings.py b/aleksis/core/settings.py index 9cd0fc2fd..58ff7e2d6 100644 --- a/aleksis/core/settings.py +++ b/aleksis/core/settings.py @@ -9,7 +9,7 @@ from django.utils.translation import gettext_lazy as _ from dynaconf import LazySettings from easy_thumbnails.conf import Settings as thumbnail_settings -from .util.core_helpers import get_app_packages, lazy_preference, merge_app_settings +from .util.core_helpers import get_app_packages, lazy_preference, merge_app_settings, lazy_get_favicon_url ENVVAR_PREFIX_FOR_DYNACONF = "ALEKSIS" DIRS_FOR_DYNACONF = ["/etc/aleksis"] @@ -93,6 +93,7 @@ INSTALLED_APPS = [ "django_js_reverse", "colorfield", "django_bleach", + "favicon", ] merge_app_settings("INSTALLED_APPS", INSTALLED_APPS, True) @@ -116,7 +117,7 @@ MIDDLEWARE = [ "django.middleware.common.CommonMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", - "debug_toolbar.middleware.DebugToolbarMiddleware", + # "debug_toolbar.middleware.DebugToolbarMiddleware", "django_otp.middleware.OTPMiddleware", "impersonate.middleware.ImpersonateMiddleware", "django.contrib.messages.middleware.MessageMiddleware", @@ -420,21 +421,29 @@ PWA_APP_BACKGROUND_COLOR = "#ffffff" PWA_APP_DISPLAY = "standalone" PWA_APP_ORIENTATION = "any" PWA_APP_ICONS = [ # three icons to upload dbsettings - {"src": STATIC_URL + "/icons/android_192.png", "sizes": "192x192"}, - {"src": STATIC_URL + "/icons/android_512.png", "sizes": "512x512"}, + {"src": lazy_get_favicon_url(title="pwa_icon", size=192, rel="android", + default=STATIC_URL + "icons/android_192.png"), "sizes": "192x192"}, + {"src": lazy_get_favicon_url(title="pwa_icon", size=512, rel="android", + default=STATIC_URL + "icons/android_512.png"), "sizes": "512x512"}, ] PWA_APP_ICONS_APPLE = [ - {"src": STATIC_URL + "/icons/apple_76.png", "sizes": "76x76"}, - {"src": STATIC_URL + "/icons/apple_114.png", "sizes": "114x114"}, - {"src": STATIC_URL + "/icons/apple_152.png", "sizes": "152x152"}, - {"src": STATIC_URL + "/icons/apple_180.png", "sizes": "180x180"}, + {"src": lazy_get_favicon_url(title="pwa_icon", size=192, rel="apple", + default=STATIC_URL + "icons/apple_76.png"), "sizes": "76x76"}, + {"src": lazy_get_favicon_url(title="pwa_icon", size=192, rel="apple", + default=STATIC_URL + "icons/apple_114.png"), "sizes": "114x114"}, + {"src": lazy_get_favicon_url(title="pwa_icon", size=192, rel="apple", + default=STATIC_URL + "icons/apple_152.png"), "sizes": "152x152"}, + {"src": lazy_get_favicon_url(title="pwa_icon", size=192, rel="apple", + default=STATIC_URL + "icons/apple_180.png"), "sizes": "180x180"}, ] PWA_APP_SPLASH_SCREEN = [ { - "src": STATIC_URL + "/icons/android_512.png", + "src": lazy_get_favicon_url(title="pwa_icon", size=192, rel="apple", default=STATIC_URL + "icons/apple_180.png"), "media": "(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2)", } ] + + PWA_SERVICE_WORKER_PATH = os.path.join(STATIC_ROOT, "js", "serviceworker.js") SITE_ID = 1 diff --git a/aleksis/core/templates/core/base.html b/aleksis/core/templates/core/base.html index f21d2efc8..b3fc8d66f 100644 --- a/aleksis/core/templates/core/base.html +++ b/aleksis/core/templates/core/base.html @@ -66,9 +66,7 @@ <ul id="slide-out" class="sidenav sidenav-fixed"> <li class="logo"> <a id="logo-container" href="/" class="brand-logo"> - <object type="image/svg+xml" data="{% static 'img/aleksis-icon.svg' %}" class="aleksis-logo-svg" id="sidenav-logo"> - <img src="{% static 'img/aleksis-icon.png' %}" alt="AlekSIS icon" /> - </object> + <img src="{{ request.site.preferences.theme__logo.url }}" alt="{{ request.site.preferences.general__title }} – Logo"> </a> </li> {% has_perm 'core.search' user as search %} diff --git a/aleksis/core/templates/core/base_print.html b/aleksis/core/templates/core/base_print.html index abd42a1c7..f9b9d8450 100644 --- a/aleksis/core/templates/core/base_print.html +++ b/aleksis/core/templates/core/base_print.html @@ -1,4 +1,4 @@ -{% load static i18n any_js sass_tags cropping %} +{% load static i18n any_js sass_tags %} <!DOCTYPE html> <html> @@ -40,7 +40,7 @@ <header> <div id="print-header" class="row"> <div class="col s6 logo"> - <img src="{% cropped_thumbnail SCHOOL 'logo_cropping' max_size="85x85" %}" alt="Logo" id="print-logo"/> + <img src="{{ request.site.preferences.theme__logo.url }}" alt="Logo" id="print-logo"/> </div> <div class="col s6 right-align"> <h5>{% block page_title %}{% endblock %}</h5> diff --git a/aleksis/core/templates/core/meta.html b/aleksis/core/templates/core/meta.html index 6a6087224..7b188462e 100644 --- a/aleksis/core/templates/core/meta.html +++ b/aleksis/core/templates/core/meta.html @@ -1,4 +1,4 @@ -{% load i18n static pwa %} +{% load i18n static pwa favtags %} {# Basic meta #} <meta charset="utf-8"> @@ -7,9 +7,7 @@ <meta name="description" content="{{ request.site.preferences.general__description }}"> {# Favicons #} -<link href="{% static "icons/favicon_16.png" %}" rel="icon" type="image/png" sizes="16x16"> -<link href="{% static "icons/favicon_32.png" %}" rel="icon" type="image/png" sizes="32x32"> -<link href="{% static "icons/favicon_48.png" %}" rel="icon" type="image/png" sizes="48x48"> +{% place_favicon %} {# PWA meta #} {% progressive_web_app_meta %} diff --git a/aleksis/core/util/core_helpers.py b/aleksis/core/util/core_helpers.py index f39b58f6f..c9c28deaf 100644 --- a/aleksis/core/util/core_helpers.py +++ b/aleksis/core/util/core_helpers.py @@ -4,7 +4,9 @@ from operator import itemgetter import os import pkgutil from importlib import import_module -from typing import Any, Callable, Sequence, Union, List, Optional + +from typing import Any, Callable, List, Optional, Sequence, Union + from uuid import uuid4 from django.conf import settings @@ -112,6 +114,22 @@ def lazy_preference(section: str, name: str) -> Callable[[str, str], Any]: return lazy(_get_preference, str)(section, name) +def lazy_get_favicon_url(title: str, size: int, rel: str, default: Optional[str] = None) -> Callable[[str, str], Any]: + """ Lazily get the URL to a favicon image """ + + def _get_favicon_url(size: int, rel: str) -> Any: + from favicon.models import Favicon # noqa + + try: + favicon = Favicon.on_site.get(title=title) + except Favicon.DoesNotExist: + return default + else: + return favicon.get_favicon(size, rel).faviconImage.url + + return lazy(_get_favicon_url, str)(size, rel) + + def is_impersonate(request: HttpRequest) -> bool: """ Check whether the user was impersonated by an admin """ diff --git a/aleksis/core/views.py b/aleksis/core/views.py index 2cdd5284e..bc82720fb 100644 --- a/aleksis/core/views.py +++ b/aleksis/core/views.py @@ -433,7 +433,7 @@ def preferences(request: HttpRequest, registry_name: str = "person", pk: Optiona form_class = preference_form_builder(form_class, instance=instance, section=section) if request.method == "POST": - form = form_class(request.POST) + form = form_class(request.POST, request.FILES or None) if form.is_valid(): form.update_preferences() messages.success(request, _("The preferences have been saved successfully.")) diff --git a/pyproject.toml b/pyproject.toml index 2bb92bfbb..b503eee1d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -76,6 +76,7 @@ django-dbbackup = "^3.3.0" spdx-license-list = "^0.4.0" license-expression = "^1.2" django-reversion = "^3.0.7" +django-favicon-plus-reloaded = "^1.0.1" [tool.poetry.extras] ldap = ["django-auth-ldap"] -- GitLab