Skip to content
Snippets Groups Projects
Verified Commit dd24bf1d authored by Jonathan Weth's avatar Jonathan Weth :keyboard:
Browse files

Remove django-pwa and provide meta/manifest through own views and templates

parent 2280f3b7
No related branches found
No related tags found
1 merge request!641Resolve "Replace django-pwa by own views/templates"
Pipeline #14942 passed
...@@ -6,6 +6,19 @@ All notable changes to this project will be documented in this file. ...@@ -6,6 +6,19 @@ All notable changes to this project will be documented in this file.
The format is based on `Keep a Changelog`_, The format is based on `Keep a Changelog`_,
and this project adheres to `Semantic Versioning`_. and this project adheres to `Semantic Versioning`_.
Unreleased
----------
Changed
~~~~~~~
* Use own templates and views for PWA meta and manifest.
Removed
~~~~~~~
* Drop django-pwa completely.
`2.0b0`_ - 2021-05-21 `2.0b0`_ - 2021-05-21
--------------------- ---------------------
......
...@@ -5,13 +5,7 @@ from django.utils.translation import gettext_lazy as _ ...@@ -5,13 +5,7 @@ from django.utils.translation import gettext_lazy as _
from dynaconf import LazySettings from dynaconf import LazySettings
from .util.core_helpers import ( from .util.core_helpers import get_app_packages, merge_app_settings, monkey_patch
get_app_packages,
lazy_get_favicons,
lazy_preference,
merge_app_settings,
monkey_patch,
)
monkey_patch() monkey_patch()
...@@ -130,7 +124,6 @@ INSTALLED_APPS = [ ...@@ -130,7 +124,6 @@ INSTALLED_APPS = [
"impersonate", "impersonate",
"two_factor", "two_factor",
"material", "material",
"pwa",
"ckeditor", "ckeditor",
"ckeditor_uploader", "ckeditor_uploader",
"django_js_reverse", "django_js_reverse",
...@@ -652,29 +645,14 @@ DEFAULT_FAVICON_PATHS = { ...@@ -652,29 +645,14 @@ DEFAULT_FAVICON_PATHS = {
"pwa_icon": os.path.join(STATIC_ROOT, "img/aleksis-icon.png"), "pwa_icon": os.path.join(STATIC_ROOT, "img/aleksis-icon.png"),
"favicon": os.path.join(STATIC_ROOT, "img/aleksis-icon.png"), "favicon": os.path.join(STATIC_ROOT, "img/aleksis-icon.png"),
} }
PWA_APP_NAME = lazy_preference("general", "title") PWA_ICONS_CONFIG = {
PWA_APP_DESCRIPTION = lazy_preference("general", "description") "android": [192, 512],
PWA_APP_THEME_COLOR = lazy_preference("theme", "primary") "apple": [76, 114, 152, 180],
PWA_APP_BACKGROUND_COLOR = "#ffffff" "apple_splash": [192],
PWA_APP_DISPLAY = "standalone" "microsoft": [144],
PWA_APP_ORIENTATION = "any" }
PWA_APP_ICONS = lazy_get_favicons(
"pwa_icon", default=DEFAULT_FAVICON_PATHS["pwa_icon"], config={"android": [192, 512]}
)
PWA_APP_ICONS_APPLE = lazy_get_favicons(
"pwa_icon", default=DEFAULT_FAVICON_PATHS["pwa_icon"], config={"apple": [76, 114, 152, 180]}
)
PWA_APP_SPLASH_SCREEN = lazy_get_favicons(
"pwa_icon",
default=DEFAULT_FAVICON_PATHS["pwa_icon"],
config={"apple": [192]},
add_attrs={
"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") SERVICE_WORKER_PATH = os.path.join(STATIC_ROOT, "js", "serviceworker.js")
SITE_ID = 1 SITE_ID = 1
......
...@@ -112,6 +112,18 @@ $(document).ready(function () { ...@@ -112,6 +112,18 @@ $(document).ready(function () {
var el = $(e.target).parent(); var el = $(e.target).parent();
el.addClass("closed").removeClass("opened"); el.addClass("closed").removeClass("opened");
}); });
// Initialize the service worker
if ('serviceWorker' in navigator) {
console.debug("Start registration of service worker.");
navigator.serviceWorker.register('/serviceworker.js', {
scope: '/'
}).then(function() {
console.debug("Service worker has been registered.");
}).catch(function() {
console.debug("Service worker registration has failed.")
});
}
}); });
// Show notice if serviceworker broadcasts that the current page comes from its cache // Show notice if serviceworker broadcasts that the current page comes from its cache
......
{# -*- engine:django -*- #} {# -*- engine:django -*- #}
{% load i18n menu_generator static sass_tags any_js pwa rules %} {% load i18n menu_generator static sass_tags any_js rules %}
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
......
{% load pwa favtags %} {% load favtags %}
<meta charset="utf-8"/> <meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/> <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
...@@ -6,5 +6,31 @@ ...@@ -6,5 +6,31 @@
<meta name="description" content="{{ request.site.preferences.general__description }}"/> <meta name="description" content="{{ request.site.preferences.general__description }}"/>
<meta name="generator" content="AlekSIS School Information System"/> <meta name="generator" content="AlekSIS School Information System"/>
<meta name="theme-color" content="red">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-title" content="{{ request.site.preferences.general__title }}">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="msapplication-navbutton-color" content="{{ request.site.preferences.theme__primary }}">
<meta name="msapplication-TileColor" content="{{ request.site.preferences.theme__primary }}">
<meta name="msapplication-TileImage" content="{{ PWA_ICONS.microsoft.144.faviconImage.url }}">
<meta name="application-name" content="{{ request.site.preferences.general__title }}">
<meta name="msapplication-starturl" content="/">
<meta name="msapplication-tap-highlight" content="no">
<meta name="browsermode" content="application">
<link href="/manifest.json" rel="manifest">
{% place_favicon %} {% place_favicon %}
{% progressive_web_app_meta %}
{% for icon in PWA_ICONS.apple.values %}
<link rel="apple-touch-icon" href="{{ icon.faviconImage.url }}" sizes="{{ icon.size }}x{{ icon.size }}">
{% endfor %}
{% with icon=PWA_ICONS.apple_splash.192 %}
<link href="{{ icon.faviconImage.url }}" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image"/>
{% endwith %}
...@@ -18,8 +18,10 @@ from . import views ...@@ -18,8 +18,10 @@ from . import views
urlpatterns = [ urlpatterns = [
path("", include("django_prometheus.urls")), path("", include("django_prometheus.urls")),
path("", include("pwa.urls"), name="pwa"),
path(settings.MEDIA_URL.removeprefix("/"), include("titofisto.urls")), path(settings.MEDIA_URL.removeprefix("/"), include("titofisto.urls")),
path("manifest.json", views.ManifestView.as_view(), name="manifest"),
path("serviceworker.js", views.ServiceWorkerView.as_view(), name="service_worker"),
path("offline/", views.OfflineView.as_view(), name="offline"),
path("about/", views.about, name="about_aleksis"), path("about/", views.about, name="about_aleksis"),
path("accounts/logout/", auth_views.LogoutView.as_view(), name="logout"), path("accounts/logout/", auth_views.LogoutView.as_view(), name="logout"),
path( path(
......
...@@ -158,30 +158,12 @@ def get_or_create_favicon(title: str, default: str, is_favicon: bool = False) -> ...@@ -158,30 +158,12 @@ def get_or_create_favicon(title: str, default: str, is_favicon: bool = False) ->
return favicon return favicon
def lazy_get_favicons( def get_pwa_icons():
title: str, from django.conf import settings # noqa
config: dict[str, list[int]],
default: str,
add_attrs: Optional[dict[str, Any]] = None,
) -> Callable[[], list[dict[str, str]]]:
"""Lazily load a dictionary for PWA settings from favicon generation rules."""
if add_attrs is None:
add_attrs = {}
def _get_favicons() -> list[dict[str, str]]:
favicon = get_or_create_favicon(title, default)
favicon_imgs = favicon.get_favicons(config_override=config)
return [
{
"src": favicon_img.faviconImage.url,
"sizes": [f"{favicon_img.size}x{favicon_img.size}"],
}
| add_attrs
for favicon_img in favicon_imgs
]
return lazy(_get_favicons, list)() favicon = get_or_create_favicon("pwa_icon", settings.DEFAULT_FAVICON_PATHS["pwa_icon"])
favicon_imgs = favicon.get_favicons(config_override=settings.PWA_ICONS_CONFIG)
return favicon_imgs
def is_impersonate(request: HttpRequest) -> bool: def is_impersonate(request: HttpRequest) -> bool:
...@@ -220,6 +202,12 @@ def custom_information_processor(request: HttpRequest) -> dict: ...@@ -220,6 +202,12 @@ def custom_information_processor(request: HttpRequest) -> dict:
"""Provide custom information in all templates.""" """Provide custom information in all templates."""
from ..models import CustomMenu from ..models import CustomMenu
pwa_icons = get_pwa_icons()
regrouped_pwa_icons = {}
for pwa_icon in pwa_icons:
regrouped_pwa_icons.setdefault(pwa_icon.rel, {})
regrouped_pwa_icons[pwa_icon.rel][pwa_icon.size] = pwa_icon
return { return {
"FOOTER_MENU": CustomMenu.get_default("footer"), "FOOTER_MENU": CustomMenu.get_default("footer"),
"ALTERNATIVE_LOGIN_VIEWS_LIST": [ "ALTERNATIVE_LOGIN_VIEWS_LIST": [
...@@ -231,6 +219,7 @@ def custom_information_processor(request: HttpRequest) -> dict: ...@@ -231,6 +219,7 @@ def custom_information_processor(request: HttpRequest) -> dict:
a for a in settings.ALTERNATIVE_LOGIN_VIEWS if a[0] in settings.AUTHENTICATION_BACKENDS a for a in settings.ALTERNATIVE_LOGIN_VIEWS if a[0] in settings.AUTHENTICATION_BACKENDS
], ],
"ADMINS": settings.ADMINS, "ADMINS": settings.ADMINS,
"PWA_ICONS": regrouped_pwa_icons,
} }
......
...@@ -13,10 +13,13 @@ from django.http import ( ...@@ -13,10 +13,13 @@ from django.http import (
HttpResponse, HttpResponse,
HttpResponseNotFound, HttpResponseNotFound,
HttpResponseRedirect, HttpResponseRedirect,
JsonResponse,
) )
from django.http.response import FileResponse
from django.shortcuts import get_object_or_404, redirect, render from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse, reverse_lazy from django.urls import reverse, reverse_lazy
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.utils.translation import get_language
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.views.decorators.cache import never_cache from django.views.decorators.cache import never_cache
from django.views.generic.base import TemplateView, View from django.views.generic.base import TemplateView, View
...@@ -96,6 +99,7 @@ from .util.apps import AppConfig ...@@ -96,6 +99,7 @@ from .util.apps import AppConfig
from .util.celery_progress import render_progress_page from .util.celery_progress import render_progress_page
from .util.core_helpers import ( from .util.core_helpers import (
get_allowed_object_ids, get_allowed_object_ids,
get_pwa_icons,
get_site_preferences, get_site_preferences,
has_person, has_person,
objectgetter_optional, objectgetter_optional,
...@@ -115,6 +119,56 @@ class RenderPDFView(TemplateView): ...@@ -115,6 +119,56 @@ class RenderPDFView(TemplateView):
return render_pdf(request, self.template_name, context) return render_pdf(request, self.template_name, context)
class ServiceWorkerView(View):
"""Render serviceworker.js under root URL.
This can't be done by static files,
because the PWA has a scope and
only accepts service worker files from the root URL.
"""
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
return FileResponse(open(settings.SERVICE_WORKER_PATH))
class ManifestView(View):
"""Build manifest.json for PWA."""
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
prefs = get_site_preferences()
pwa_imgs = get_pwa_icons()
icons = [
{
"src": favicon_img.faviconImage.url,
"sizes": f"{favicon_img.size}x{favicon_img.size}",
}
for favicon_img in pwa_imgs
]
manifest = {
"name": prefs["general__title"],
"short_name": prefs["general__title"],
"description": prefs["general__description"],
"start_url": "/",
"scope": "/",
"lang": get_language(),
"display": "standalone",
"orientation": "any",
"status_bar": "default",
"background_color": "#ffffff",
"theme_color": prefs["theme__primary"],
"icons": icons,
}
return JsonResponse(manifest)
class OfflineView(TemplateView):
"""Show an error page if there is no internet connection."""
template_name = "offline.html"
@permission_required("core.view_dashboard_rule") @permission_required("core.view_dashboard_rule")
def index(request: HttpRequest) -> HttpResponse: def index(request: HttpRequest) -> HttpResponse:
"""View for dashboard.""" """View for dashboard."""
......
This diff is collapsed.
...@@ -67,7 +67,6 @@ django_select2 = "^7.1" ...@@ -67,7 +67,6 @@ django_select2 = "^7.1"
django-two-factor-auth = { version = "^1.12.1", extras = [ "yubikey", "phonenumbers", "call", "sms" ] } django-two-factor-auth = { version = "^1.12.1", extras = [ "yubikey", "phonenumbers", "call", "sms" ] }
django-yarnpkg = "^6.0" django-yarnpkg = "^6.0"
django-material = "^1.6.0" django-material = "^1.6.0"
django-pwa = "^1.0.8"
django-dynamic-preferences = "^1.9" django-dynamic-preferences = "^1.9"
django_widget_tweaks = "^1.4.5" django_widget_tweaks = "^1.4.5"
django-filter = "^2.2.0" django-filter = "^2.2.0"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment