From f97dc7e1210f5290afa90a1ee6bb521c4d648c48 Mon Sep 17 00:00:00 2001 From: Valentin Gagarin Date: Wed, 12 Feb 2025 23:59:51 +0100 Subject: [PATCH] fix settings and add dummy view This introduces customisation to `settings.py` that - allow controlling the relevant parameters from our systemd wrapper (more brittle and non-obvious than it should be, see TODOs) - correctly configure SASS processing and static file compression (not as easy as it sounds) --- panel/src/panel/settings.py | 58 +++++++++++++++++++++++++--- panel/src/panel/static/style.sass | 5 +++ panel/src/panel/templates/base.html | 29 ++++++++++++++ panel/src/panel/templates/index.html | 7 ++++ panel/src/panel/urls.py | 2 + panel/src/panel/views.py | 4 ++ 6 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 panel/src/panel/static/style.sass create mode 100644 panel/src/panel/templates/base.html create mode 100644 panel/src/panel/templates/index.html create mode 100644 panel/src/panel/views.py diff --git a/panel/src/panel/settings.py b/panel/src/panel/settings.py index d5074c1..e4869c4 100644 --- a/panel/src/panel/settings.py +++ b/panel/src/panel/settings.py @@ -10,6 +10,12 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/4.2/ref/settings/ """ +import sys +import os +import importlib.util +import dj_database_url + +from os import environ as env from pathlib import Path # Build paths inside the project like this: BASE_DIR / 'subdir'. @@ -19,8 +25,22 @@ BASE_DIR = Path(__file__).resolve().parent.parent # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ +def get_secret(name: str, encoding: str = "utf-8") -> str: + credentials_dir = env.get("CREDENTIALS_DIRECTORY") + + if credentials_dir is None: + raise RuntimeError("No credentials directory available.") + + try: + with open(f"{credentials_dir}/{name}", encoding=encoding) as f: + secret = f.read().removesuffix("\n") + except FileNotFoundError: + raise RuntimeError(f"No secret named {name} found in {credentials_dir}.") + + return secret + # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'django-insecure-9*i_k2o@x-c7w%o!*@b88t%n)eh=c2nj2f2m*-=$gwfn#zoso7' +SECRET_KEY = get_secret("SECRET_KEY") # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True @@ -31,12 +51,14 @@ ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [ + "panel", 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'compressor', ] MIDDLEWARE = [ @@ -72,12 +94,10 @@ WSGI_APPLICATION = 'panel.wsgi.application' # Database # https://docs.djangoproject.com/en/4.2/ref/settings/#databases +# https://github.com/jazzband/dj-database-url DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': BASE_DIR / 'db.sqlite3', - } + 'default': dj_database_url.config(), } @@ -117,7 +137,35 @@ USE_TZ = True STATIC_URL = 'static/' +STATIC_ROOT = os.path.join(BASE_DIR, "static/") + +STATICFILES_FINDERS = [ + "django.contrib.staticfiles.finders.FileSystemFinder", + "django.contrib.staticfiles.finders.AppDirectoriesFinder", + "compressor.finders.CompressorFinder", +] + +STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage' + +COMPRESS_PRECOMPILERS = [ + ("text/x-sass", "django_libsass.SassCompiler"), +] + # Default primary key field type # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +# Customization via user settings +# This must be at the end, as it must be able to override the above +# TODO: we may want to do this with a flat environment instead, and get all values from `os.environ.get()`. +# this would make it more obvious which moving parts there are, if that environment is specified for development/staging/production in a visible place. +user_settings_file = env.get("USER_SETTINGS_FILE", None) +if user_settings_file is not None: + spec = importlib.util.spec_from_file_location("user_settings", user_settings_file) + if spec is None or spec.loader is None: + raise RuntimeError("User settings specification failed!") + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + sys.modules["user_settings"] = module + from user_settings import * # noqa: F403 # pyright: ignore [reportMissingImports] diff --git a/panel/src/panel/static/style.sass b/panel/src/panel/static/style.sass new file mode 100644 index 0000000..53e52a3 --- /dev/null +++ b/panel/src/panel/static/style.sass @@ -0,0 +1,5 @@ +body + padding: 0 + margin: 0 + font-family: sans-serif + box-sizing: border-box diff --git a/panel/src/panel/templates/base.html b/panel/src/panel/templates/base.html new file mode 100644 index 0000000..f761fa0 --- /dev/null +++ b/panel/src/panel/templates/base.html @@ -0,0 +1,29 @@ + + + + {% block title %}Fediversity Panel{% endblock %} + + + + + {% load compress %} + {% compress css %} + + {% endcompress %} + + {% block extra_head %}{% endblock extra_head %} + + + + {% block navigation %} + + {% endblock navigation %} + + {% block layout %} +
+ {% block content %}{% endblock content %} +
+ {% endblock layout %} + + diff --git a/panel/src/panel/templates/index.html b/panel/src/panel/templates/index.html new file mode 100644 index 0000000..aadc25d --- /dev/null +++ b/panel/src/panel/templates/index.html @@ -0,0 +1,7 @@ +{% extends "base.html" %} + +{% block content %} +

Fediversity Panel

+ +

Hello world!

+{% endblock %} diff --git a/panel/src/panel/urls.py b/panel/src/panel/urls.py index 70ca35c..d4f47e8 100644 --- a/panel/src/panel/urls.py +++ b/panel/src/panel/urls.py @@ -16,7 +16,9 @@ Including another URLconf """ from django.contrib import admin from django.urls import path +from panel import views urlpatterns = [ path('admin/', admin.site.urls), + path('', views.Index.as_view(), name='index'), ] diff --git a/panel/src/panel/views.py b/panel/src/panel/views.py new file mode 100644 index 0000000..a7d73ff --- /dev/null +++ b/panel/src/panel/views.py @@ -0,0 +1,4 @@ +from django.views.generic import TemplateView + +class Index(TemplateView): + template_name = 'index.html'