diff --git a/README.md b/README.md index 8e9fc8c9..e13abd6e 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ See `.tool-versions` file for used django and node version You have to set up at least the following environment variables: ```bash -export IT_APP_ENVIRONMENT=development +export IT_APP_ENVIRONMENT=local ``` See `.env_secrets/local_daniel.env` for more possible environment variables. diff --git a/caprover_create_app.py b/caprover_create_app.py index 549b5b23..00688bf5 100644 --- a/caprover_create_app.py +++ b/caprover_create_app.py @@ -72,8 +72,10 @@ def main(app_name, image_name, environment_file): image_name=image_name, container_http_port=7555, environment_variables={ - # 'DJANGO_SETTINGS_MODULE': 'config.settings.base', - "IT_APP_ENVIRONMENT": env.str("IT_APP_ENVIRONMENT", "caprover_feature"), + "IT_APP_ENVIRONMENT": env.str("IT_APP_ENVIRONMENT", "dev-feature"), + "IT_DEFAULT_ADMIN_PASSWORD": env.str( + "IT_DEFAULT_ADMIN_PASSWORD", "ACEEs0DCmNaPxdoNV8vhccuCTRl9b" + ), "POSTGRES_HOST": f"srv-captain--{app_name}-postgres", "POSTGRES_PORT": 5432, "POSTGRES_DB": db_name, @@ -88,6 +90,7 @@ def main(app_name, image_name, environment_file): "IT_DJANGO_DEBUG": "false", "IT_SERVE_VUE": "false", "IT_ALLOW_LOCAL_LOGIN": "true", + "IT_DJANGO_LOGGING_CONF": "IT_DJANGO_LOGGING_CONF_JSON_FILE", }, ) diff --git a/caprover_deploy.sh b/caprover_deploy.sh index ffdfc2ce..2cb0c455 100755 --- a/caprover_deploy.sh +++ b/caprover_deploy.sh @@ -25,33 +25,22 @@ function generate_default_app_name() { # take app name as first argument or use the default generated app name APP_NAME=${1:-$(generate_default_app_name)} -VITE_SENTRY_ENV="development" +# VITE_* variables need to be present at build time +VITE_APP_ENVIRONMENT="dev-$APP_NAME" -if [[ "$APP_NAME" == "myvbv" ]]; then - VITE_LOGOUT_REDIRECT="https://edumgr.b2clogin.com/edumgr.onmicrosoft.com/b2c_1_signupandsignin/oauth2/v2.0/logout/?post_logout_redirect_uri=https://myvbv.iterativ.ch/" - VITE_SENTRY_ENV="production" -elif [[ "$APP_NAME" == "myvbv-stage" ]]; then - VITE_LOGOUT_REDIRECT="https://vbvtst.b2clogin.com/vbvtst.onmicrosoft.com/b2c_1_signupandsignin/oauth2/v2.0/logout/?post_logout_redirect_uri=https://myvbv-stage.iterativ.ch/" - VITE_SENTRY_ENV="stage" -elif [[ "$APP_NAME" == "vbv-lernwelt" ]]; then - VITE_LOGOUT_REDIRECT="https://vbvdev.b2clogin.com/vbvdev.onmicrosoft.com/b2c_1_signupandsignin/oauth2/v2.0/logout/?post_logout_redirect_uri=https://vbv-lernwelt.control.iterativ.ch" - VITE_SENTRY_ENV="development" -elif [[ "$APP_NAME" == "prod-azure" ]]; then - VITE_LOGOUT_REDIRECT="https://edumgr.b2clogin.com/edumgr.onmicrosoft.com/b2c_1_signupandsignin/oauth2/v2.0/logout/?post_logout_redirect_uri=https://my.vbv-afa.ch/" - VITE_SENTRY_ENV="production" +if [[ "$APP_NAME" == "myvbv-stage" ]]; then + VITE_OAUTH_API_BASE_URL="https://vbvtst.b2clogin.com/vbvtst.onmicrosoft.com/b2c_1_signupandsignin/oauth2/v2.0/" + VITE_APP_ENVIRONMENT="stage-caprover" +elif [[ "$APP_NAME" == prod* ]]; then + VITE_OAUTH_API_BASE_URL="https://edumgr.b2clogin.com/edumgr.onmicrosoft.com/b2c_1_signupandsignin/oauth2/v2.0/" + VITE_APP_ENVIRONMENT=$APP_NAME fi echo "Deploy to $APP_NAME" -echo "VITE_SENTRY_ENV: $VITE_SENTRY_ENV" -echo "VITE_LOGOUT_REDIRECT: $VITE_LOGOUT_REDIRECT" - -export VITE_SENTRY_ENV=$VITE_SENTRY_ENV -export VITE_LOGOUT_REDIRECT=$VITE_LOGOUT_REDIRECT - # create client for django npm run build -python server/manage.py collectstatic --no-input +IT_APP_ENVIRONMENT=local python server/manage.py collectstatic --no-input if [[ "$APP_NAME" == "prod-azure" ]]; then # build and push azure docker container diff --git a/client/index.html b/client/index.html index 9a334c7e..f0aa933d 100644 --- a/client/index.html +++ b/client/index.html @@ -7,7 +7,7 @@ diff --git a/client/public/favicon.ico b/client/public/favicon.ico index df36fcfb..447bfa57 100644 Binary files a/client/public/favicon.ico and b/client/public/favicon.ico differ diff --git a/client/src/components/AppFooter.vue b/client/src/components/AppFooter.vue index eb0b6b4f..dc50187c 100644 --- a/client/src/components/AppFooter.vue +++ b/client/src/components/AppFooter.vue @@ -8,7 +8,9 @@ import * as log from "loglevel"; log.debug("AppFooter created"); const userStore = useUserStore(); -const hideVersion = import.meta.env.VITE_SENTRY_ENV === "production"; +const hideVersion = (import.meta.env.VITE_APP_ENVIRONMENT || "local").startsWith( + "prod" +); async function changeLocale(language: AvailableLanguages) { userStore.setUserLanguages(language); diff --git a/client/src/main.ts b/client/src/main.ts index df15ebee..bb082423 100644 --- a/client/src/main.ts +++ b/client/src/main.ts @@ -14,13 +14,12 @@ declare module "pinia" { } } -if ( - window.location.href.indexOf("localhost") >= 0 || - window.location.href.indexOf("127.0.0.1") >= 0 -) { - log.setLevel("trace"); -} else { +const appEnv = import.meta.env.VITE_APP_ENVIRONMENT || "local"; + +if (appEnv.startsWith("prod")) { log.setLevel("warn"); +} else { + log.setLevel("trace"); } const i18n = setupI18n(); @@ -28,12 +27,10 @@ const app = createApp(App); Sentry.init({ app, - environment: import.meta.env.VITE_SENTRY_ENV || "development", + environment: appEnv, dsn: "https://2df6096a4fd94bd6b4802124d10e4b8d@o8544.ingest.sentry.io/4504157846372352", tracesSampleRate: 0.0, - enabled: - import.meta.env.VITE_SENTRY_ENV == "production" || - import.meta.env.VITE_SENTRY_ENV == "stage", + enabled: appEnv.startsWith("prod") || appEnv.startsWith("stage"), }); // todo: define lang setup diff --git a/client/src/router/guards.ts b/client/src/router/guards.ts index 59c4cf7c..f7090336 100644 --- a/client/src/router/guards.ts +++ b/client/src/router/guards.ts @@ -15,8 +15,8 @@ export const updateLoggedIn: NavigationGuard = async () => { export const redirectToLoginIfRequired: NavigationGuard = (to) => { const userStore = useUserStore(); if (loginRequired(to) && !userStore.loggedIn) { - const sentryEnv = import.meta.env.VITE_SENTRY_ENV; - const ssoLogin = sentryEnv === "production" || sentryEnv === "staging"; + const appEnv = import.meta.env.VITE_APP_ENVIRONMENT || "local"; + const ssoLogin = appEnv.startsWith("prod") || appEnv.startsWith("stage"); return ssoLogin ? `/login?next=${to.fullPath}` : `/login-local?next=${to.fullPath}`; } }; diff --git a/client/src/stores/user.ts b/client/src/stores/user.ts index e2403c9b..ba89c256 100644 --- a/client/src/stores/user.ts +++ b/client/src/stores/user.ts @@ -5,7 +5,15 @@ import { loadLocaleMessages, setI18nLanguage } from "@/i18n"; import dayjs from "dayjs"; import { defineStore } from "pinia"; -const logoutRedirectUrl = import.meta.env.VITE_LOGOUT_REDIRECT || "/"; +let logoutRedirectUrl = import.meta.env.VITE_LOGOUT_REDIRECT || "/"; + +// TODO: check if user logged in with SSO or login-local +if (import.meta.env.VITE_OAUTH_API_BASE_URL) { + logoutRedirectUrl = `${ + import.meta.env.VITE_OAUTH_API_BASE_URL + }logout/?post_logout_redirect_uri=${window.location.origin}`; +} + // typed state https://stackoverflow.com/questions/71012513/when-using-pinia-and-typescript-how-do-you-use-an-action-to-set-the-state export type AvailableLanguages = "de" | "fr" | "it"; diff --git a/compose/django/docker_start.sh b/compose/django/docker_start.sh index e888148f..b7a592d8 100644 --- a/compose/django/docker_start.sh +++ b/compose/django/docker_start.sh @@ -4,11 +4,9 @@ set -o errexit set -o pipefail set -o nounset -python /app/manage.py collectstatic --no-input --no-post-process +# python /app/manage.py collectstatic --no-input --no-post-process # TODO remove after stabilisation python /app/manage.py reset_schema /usr/local/bin/gunicorn config.asgi --bind 0.0.0.0:7555 --chdir=/app -k uvicorn.workers.UvicornWorker - - diff --git a/env/bitbucket/prepare_for_deployment.sh b/env/bitbucket/prepare_for_deployment.sh index c2f7435c..2359750c 100755 --- a/env/bitbucket/prepare_for_deployment.sh +++ b/env/bitbucket/prepare_for_deployment.sh @@ -12,9 +12,6 @@ export PATH="$PWD/vbvvenv/bin:$PATH" docker login --username=iterativ --password=$DOCKER_PASSWORD_TOKEN -# only used for `python manage.py collectstatic` so value doesn't matter -export IT_APP_ENVIRONMENT=development - pip install -r $BITBUCKET_CLONE_DIR/server/requirements/requirements-dev.txt npm install -g caprover diff --git a/env/docker_local.env b/env/docker_local.env deleted file mode 100644 index 409e30f8..00000000 --- a/env/docker_local.env +++ /dev/null @@ -1,13 +0,0 @@ -# PostgreSQL -# ------------------------------------------------------------------------------ -POSTGRES_HOST=postgres -POSTGRES_PORT=5432 -POSTGRES_DB=vbv_lernwelt -POSTGRES_USER=postgres -POSTGRES_PASSWORD=hNqfCdG6bwCLcnfboDtNM1L2Hiwp8GuKp1DJ6t2rcKl15Vls2QbByoIZ6IQlciKM - -# General -# ------------------------------------------------------------------------------ -IT_DJANGO_LOCAL_DOCKER=True -IPYTHONDIR=/app/.ipython -IT_APP_ENVIRONMENT=local diff --git a/env_secrets/caprover_dev.env b/env_secrets/caprover_dev.env index 4551800d..c0dd90f9 100644 Binary files a/env_secrets/caprover_dev.env and b/env_secrets/caprover_dev.env differ diff --git a/env_secrets/caprover_prod.env b/env_secrets/caprover_prod.env index 32320d96..cbf2d43f 100644 Binary files a/env_secrets/caprover_prod.env and b/env_secrets/caprover_prod.env differ diff --git a/env_secrets/caprover_stage.env b/env_secrets/caprover_stage.env index d0b38980..0fee939d 100644 Binary files a/env_secrets/caprover_stage.env and b/env_secrets/caprover_stage.env differ diff --git a/env_secrets/local_chrigu.env b/env_secrets/local_chrigu.env index 324ec6b9..5269f91e 100644 Binary files a/env_secrets/local_chrigu.env and b/env_secrets/local_chrigu.env differ diff --git a/env_secrets/local_daniel.env b/env_secrets/local_daniel.env index 1664c3b5..9b641f2e 100644 Binary files a/env_secrets/local_daniel.env and b/env_secrets/local_daniel.env differ diff --git a/env_secrets/local_elia.env b/env_secrets/local_elia.env index 16a4c5a0..920f089e 100644 Binary files a/env_secrets/local_elia.env and b/env_secrets/local_elia.env differ diff --git a/env_secrets/local_lorenz.env b/env_secrets/local_lorenz.env index 764a8653..22665c98 100644 Binary files a/env_secrets/local_lorenz.env and b/env_secrets/local_lorenz.env differ diff --git a/env_secrets/pg_backup_local.env b/env_secrets/pg_backup_local.env deleted file mode 100644 index ca8e7f15..00000000 Binary files a/env_secrets/pg_backup_local.env and /dev/null differ diff --git a/env_secrets/prod-azure.json b/env_secrets/prod-azure.json new file mode 100644 index 00000000..660fb8f8 Binary files /dev/null and b/env_secrets/prod-azure.json differ diff --git a/env_secrets/production.env b/env_secrets/production.env deleted file mode 100644 index 7169a777..00000000 Binary files a/env_secrets/production.env and /dev/null differ diff --git a/env_secrets/production_azure.json b/env_secrets/production_azure.json deleted file mode 100644 index 1314d1dd..00000000 Binary files a/env_secrets/production_azure.json and /dev/null differ diff --git a/example.env b/example.env index 06329196..cebd3ce6 100644 --- a/example.env +++ b/example.env @@ -1 +1 @@ -export IT_APP_ENVIRONMENT='development' +export IT_APP_ENVIRONMENT=local diff --git a/git-crypt-encrypted-files.txt b/git-crypt-encrypted-files.txt index 0825e8e7..565a8b73 100644 --- a/git-crypt-encrypted-files.txt +++ b/git-crypt-encrypted-files.txt @@ -5,6 +5,4 @@ encrypted: env_secrets/local_daniel.env encrypted: env_secrets/local_elia.env encrypted: env_secrets/local_lorenz.env - encrypted: env_secrets/pg_backup_local.env - encrypted: env_secrets/production.env - encrypted: env_secrets/production_azure.json + encrypted: env_secrets/prod-azure.json diff --git a/prepare_server_cypress.sh b/prepare_server_cypress.sh index b08106f5..0bc71716 100755 --- a/prepare_server_cypress.sh +++ b/prepare_server_cypress.sh @@ -3,7 +3,7 @@ # set location to script directory cd "${0%/*}" -export IT_APP_ENVIRONMENT=development +export IT_APP_ENVIRONMENT=local export DJANGO_SETTINGS_MODULE=config.settings.test_cypress export DJANGO_PORT=8001 export PGDATABASE=vbv_lernwelt_cypress diff --git a/scripts/count_queries.py b/scripts/count_queries.py index 48167c3b..905f001e 100644 --- a/scripts/count_queries.py +++ b/scripts/count_queries.py @@ -7,7 +7,7 @@ import django sys.path.append("../server") -os.environ.setdefault("IT_APP_ENVIRONMENT", "development") +os.environ.setdefault("IT_APP_ENVIRONMENT", "local") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.base") django.setup() @@ -16,12 +16,16 @@ from wagtail.models import Page def main(): from django.conf import settings + settings.DEBUG = True from django.db import connection from django.db import reset_queries + reset_queries() - page = Page.objects.get(slug='versicherungsvermittlerin', locale__language_code='de-CH') + page = Page.objects.get( + slug="versicherungsvermittlerin", locale__language_code="de-CH" + ) serializer = page.specific.get_serializer_class()(page.specific) print(serializer.data) @@ -29,5 +33,5 @@ def main(): print(len(connection.queries)) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/server/config/settings/base.py b/server/config/settings/base.py index 06b57573..8330a516 100644 --- a/server/config/settings/base.py +++ b/server/config/settings/base.py @@ -14,13 +14,18 @@ APPS_DIR = SERVER_ROOT_DIR / "vbv_lernwelt" env = Env() env.read_env() -# set to "development" for local development +# set to "local" for local development APP_ENVIRONMENT = env("IT_APP_ENVIRONMENT") # GENERAL # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#debug -DEBUG = env.bool("IT_DJANGO_DEBUG", True if APP_ENVIRONMENT == "development" else False) +DEBUG = env.bool("IT_DJANGO_DEBUG", True if APP_ENVIRONMENT == "local" else False) + +# check that IT_DEFAULT_ADMIN_PASSWORD is set +if APP_ENVIRONMENT != "local": + # fails if not set + env.str("IT_DEFAULT_ADMIN_PASSWORD") # Local time zone. Choices are # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name @@ -498,7 +503,7 @@ SPECTACULAR_SETTINGS = { # Your stuff... # ------------------------------------------------------------------------------ -if DEBUG: +if APP_ENVIRONMENT == "local": SECRET_KEY = env( "IT_DJANGO_SECRET_KEY", default="J9FiYN31FuY7lHrmx9Mpai3GGpTVCxakEclOfCLretDe7bTf2DtTsgazJ0aIMtbq", @@ -554,14 +559,14 @@ OAUTH = { default="https://sso.test.b.lernetz.host/auth/realms/vbv/protocol/openid-connect/", ), "local_redirect_uri": env( - "IT_OAUTH_LOCAL_DIRECT_URI", default="http://localhost:8000/sso/callback/" + "IT_OAUTH_LOCAL_REDIRECT_URI", default="http://localhost:8000/sso/callback/" ), "server_metadata_url": env( "IT_OAUTH_SERVER_METADATA_URL", default="https://sso.test.b.lernetz.host/auth/realms/vbv/.well-known/openid-configuration", ), "client_kwargs": { - "scope": env("IT_OAUTH_SCOPE", default=""), + "scope": env("IT_OAUTH_SCOPE", default="openid email"), "token_endpoint_auth_method": "client_secret_post", "token_placement": "body", }, @@ -614,7 +619,30 @@ if FILE_UPLOAD_STORAGE == "s3": AWS_PRESIGNED_EXPIRY = env.int("AWS_PRESIGNED_EXPIRY", default=300) # seconds -if APP_ENVIRONMENT == "development": +WHITENOISE_SKIP_COMPRESS_EXTENSIONS = ( + "jpg", + "jpeg", + "png", + "gif", + "webp", + "zip", + "gz", + "tgz", + "bz2", + "tbz", + "xz", + "br", + "swf", + "flv", + "woff", + "woff2", + # custom to improve speed + "pdf", + "svg", +) +STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage" + +if APP_ENVIRONMENT == "local": # http://whitenoise.evans.io/en/latest/django.html#using-whitenoise-in-development INSTALLED_APPS = ["whitenoise.runserver_nostatic"] + INSTALLED_APPS # noqa F405 @@ -647,10 +675,8 @@ if APP_ENVIRONMENT == "development": # ------------------------------------------------------------------------------ # https://django-extensions.readthedocs.io/en/latest/installation_instructions.html#configuration INSTALLED_APPS += ["django_extensions", "django_watchfiles"] # noqa F405 - -if APP_ENVIRONMENT in ["production", "caprover"] or APP_ENVIRONMENT.startswith( - "caprover" -): +else: + # not local # SECURITY # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#secure-proxy-ssl-header @@ -676,9 +702,6 @@ if APP_ENVIRONMENT in ["production", "caprover"] or APP_ENVIRONMENT.startswith( "DJANGO_SECURE_CONTENT_TYPE_NOSNIFF", default=True ) - # STATIC - # ------------------------ - STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage" # MEDIA # ------------------------------------------------------------------------------ @@ -697,11 +720,6 @@ if APP_ENVIRONMENT in ["production", "caprover"] or APP_ENVIRONMENT.startswith( default="[VBV Lernwelt]", ) - # ADMIN - # ------------------------------------------------------------------------------ - # Django Admin URL regex. - ADMIN_URL = env("IT_DJANGO_ADMIN_URL", "admin/") - # Anymail # ------------------------------------------------------------------------------ # https://anymail.readthedocs.io/en/stable/installation/#installing-anymail diff --git a/server/config/settings/test.py b/server/config/settings/test.py index 0485c979..a29a49ba 100644 --- a/server/config/settings/test.py +++ b/server/config/settings/test.py @@ -1,7 +1,7 @@ # pylint: disable=unused-wildcard-import,wildcard-import,wrong-import-position import os -os.environ["IT_APP_ENVIRONMENT"] = "development" +os.environ["IT_APP_ENVIRONMENT"] = "local" from .base import * # noqa @@ -14,6 +14,8 @@ PASSWORD_HASHERS = ["django.contrib.auth.hashers.MD5PasswordHasher"] # https://docs.djangoproject.com/en/dev/ref/settings/#email-backend EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend" +WHITENOISE_MANIFEST_STRICT = False + # Dummy data AWS_S3_ACCESS_KEY_ID = "SOMEKEY" AWS_S3_SECRET_ACCESS_KEY = "SOMEACCESSKEY" diff --git a/server/config/settings/test_cypress.py b/server/config/settings/test_cypress.py index 91d808b0..a82cbe93 100644 --- a/server/config/settings/test_cypress.py +++ b/server/config/settings/test_cypress.py @@ -1,7 +1,7 @@ # pylint: disable=unused-wildcard-import,wildcard-import,wrong-import-position import os -os.environ["IT_APP_ENVIRONMENT"] = "development" +os.environ["IT_APP_ENVIRONMENT"] = "local" from .base import * # noqa diff --git a/server/vbv_lernwelt/core/views.py b/server/vbv_lernwelt/core/views.py index 18a5e3a6..92bae1ae 100644 --- a/server/vbv_lernwelt/core/views.py +++ b/server/vbv_lernwelt/core/views.py @@ -34,9 +34,6 @@ def vue_home(request, *args): try: res = requests.get(f"{settings.IT_SERVE_VUE_URL}{request.get_full_path()}") content = res.text - content = content.replace( - "https://vbv-lernwelt.control.iterativ.ch/static/", "/static/" - ) headers = res.headers content_type = headers.get("content-type", "text/html") return HttpResponse(content, content_type=content_type) @@ -47,9 +44,6 @@ def vue_home(request, *args): # render index.html from `npm run build` content = loader.render_to_string("vue/index.html", context={}, request=request) - content = content.replace( - "https://vbv-lernwelt.control.iterativ.ch/static/", "/static/" - ) return HttpResponse(content) diff --git a/server/vbv_lernwelt/static/fonts/BuenosAires/stylesheet.css b/server/vbv_lernwelt/static/fonts/BuenosAires/stylesheet.css index c707794b..2581d283 100755 --- a/server/vbv_lernwelt/static/fonts/BuenosAires/stylesheet.css +++ b/server/vbv_lernwelt/static/fonts/BuenosAires/stylesheet.css @@ -16,19 +16,6 @@ font-display: swap; } -/*@font-face {*/ -/* font-family: 'Buenos Aires';*/ -/* src: url('BuenosAires-Regular.eot');*/ -/* src: local('Buenos Aires Regular'), local('BuenosAires-Regular'),*/ -/* url('BuenosAires-Regular.eot?#iefix') format('embedded-opentype'),*/ -/* url('BuenosAires-Regular.woff2') format('woff2'),*/ -/* url('BuenosAires-Regular.woff') format('woff'),*/ -/* url('BuenosAires-Regular.ttf') format('truetype');*/ -/* font-weight: normal;*/ -/* font-style: normal;*/ -/* font-display: swap;*/ -/*}*/ - @font-face { font-family: 'Buenos Aires'; src: local('Buenos Aires SemiBold'), local('BuenosAires-SemiBold'), @@ -82,17 +69,3 @@ font-style: normal; font-display: swap; } - -/*@font-face {*/ -/* font-family: 'Buenos Aires';*/ -/* src: url('BuenosAires-RegularItalic.eot');*/ -/* src: local('Buenos Aires Regular Italic'), local('BuenosAires-RegularItalic'),*/ -/* url('BuenosAires-RegularItalic.eot?#iefix') format('embedded-opentype'),*/ -/* url('BuenosAires-RegularItalic.woff2') format('woff2'),*/ -/* url('BuenosAires-RegularItalic.woff') format('woff'),*/ -/* url('BuenosAires-RegularItalic.ttf') format('truetype');*/ -/* font-weight: normal;*/ -/* font-style: italic;*/ -/* font-display: swap;*/ -/*}*/ - diff --git a/server/vbv_lernwelt/templates/base.html b/server/vbv_lernwelt/templates/base.html index ea9f3d72..137b819f 100644 --- a/server/vbv_lernwelt/templates/base.html +++ b/server/vbv_lernwelt/templates/base.html @@ -8,7 +8,7 @@ - + {% block css %}