From 1f7f33e446d346b7c7c1911de4153f1945bc891c Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Sat, 29 Nov 2025 13:50:50 +0100 Subject: [PATCH] chore(jdav_web/*): reformat using ruff (#20) --- jdav_web/jdav_web/__init__.py | 2 +- jdav_web/jdav_web/celery.py | 11 +- jdav_web/jdav_web/middleware.py | 4 +- jdav_web/jdav_web/settings/__init__.py | 39 +-- jdav_web/jdav_web/settings/components/base.py | 212 ++++++++-------- .../jdav_web/settings/components/cache.py | 25 +- .../jdav_web/settings/components/database.py | 17 +- .../jdav_web/settings/components/emails.py | 20 +- jdav_web/jdav_web/settings/components/jet.py | 166 +++++++----- .../jdav_web/settings/components/locale.py | 4 +- .../jdav_web/settings/components/logging.py | 14 +- .../jdav_web/settings/components/oauth.py | 4 +- .../jdav_web/settings/components/texts.py | 237 +++++++++++------- jdav_web/jdav_web/settings/local.py | 116 +++++---- jdav_web/jdav_web/tests.py | 28 ++- jdav_web/jdav_web/urls.py | 46 ++-- jdav_web/jdav_web/views.py | 26 +- 17 files changed, 565 insertions(+), 406 deletions(-) diff --git a/jdav_web/jdav_web/__init__.py b/jdav_web/jdav_web/__init__.py index fb989c4..53f4ccb 100644 --- a/jdav_web/jdav_web/__init__.py +++ b/jdav_web/jdav_web/__init__.py @@ -1,3 +1,3 @@ from .celery import app as celery_app -__all__ = ('celery_app',) +__all__ = ("celery_app",) diff --git a/jdav_web/jdav_web/celery.py b/jdav_web/jdav_web/celery.py index 04cc37c..5b522da 100644 --- a/jdav_web/jdav_web/celery.py +++ b/jdav_web/jdav_web/celery.py @@ -1,14 +1,13 @@ import os -from celery import Celery -from django.conf import settings +from celery import Celery # set the default Django settings module for the 'celery' program. -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'jdav_web.settings') +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "jdav_web.settings") app = Celery() -app.config_from_object('django.conf:settings') +app.config_from_object("django.conf:settings") app.autodiscover_tasks() -if __name__ == '__main__': - app.start() # pragma: no cover +if __name__ == "__main__": + app.start() # pragma: no cover diff --git a/jdav_web/jdav_web/middleware.py b/jdav_web/jdav_web/middleware.py index c480fe0..818cca6 100644 --- a/jdav_web/jdav_web/middleware.py +++ b/jdav_web/jdav_web/middleware.py @@ -2,6 +2,6 @@ class ForceLangMiddleware: def __init__(self, get_response): self.get_response = get_response - def __call__(self,request): - request.META['HTTP_ACCEPT_LANGUAGE'] = "de" + def __call__(self, request): + request.META["HTTP_ACCEPT_LANGUAGE"] = "de" return self.get_response(request) diff --git a/jdav_web/jdav_web/settings/__init__.py b/jdav_web/jdav_web/settings/__init__.py index 060c16e..ef7989f 100644 --- a/jdav_web/jdav_web/settings/__init__.py +++ b/jdav_web/jdav_web/settings/__init__.py @@ -10,25 +10,26 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/1.10/ref/settings/ """ -from split_settings.tools import optional, include import os + import tomli +from split_settings.tools import include -CONFIG_DIR_PATH = os.environ.get('KOMPASS_CONFIG_DIR_PATH', '') -SETTINGS_FILE = os.environ.get('KOMPASS_SETTINGS_FILE', 'settings.toml') -TEXTS_FILE = os.environ.get('KOMPASS_TEXTS_FILE', 'texts.toml') +CONFIG_DIR_PATH = os.environ.get("KOMPASS_CONFIG_DIR_PATH", "") +SETTINGS_FILE = os.environ.get("KOMPASS_SETTINGS_FILE", "settings.toml") +TEXTS_FILE = os.environ.get("KOMPASS_TEXTS_FILE", "texts.toml") -with open(os.path.join(CONFIG_DIR_PATH, SETTINGS_FILE), 'rb') as f: +with open(os.path.join(CONFIG_DIR_PATH, SETTINGS_FILE), "rb") as f: config = tomli.load(f) if os.path.exists(os.path.join(CONFIG_DIR_PATH, TEXTS_FILE)): - with open(os.path.join(CONFIG_DIR_PATH, TEXTS_FILE), 'rb') as f: + with open(os.path.join(CONFIG_DIR_PATH, TEXTS_FILE), "rb") as f: texts = tomli.load(f) else: - texts = {} # pragma: no cover + texts = {} # pragma: no cover -def get_var(*keys, default='', dictionary=config): +def get_var(*keys, default="", dictionary=config): """ Get a variable from given config dictionary. The passed keys are used for nested retrieval from the dictionary. @@ -42,7 +43,7 @@ def get_var(*keys, default='', dictionary=config): return cfg -def get_text(*keys, default=''): +def get_text(*keys, default=""): """ Get a text from the `texts.toml`. """ @@ -50,16 +51,16 @@ def get_text(*keys, default=''): base_settings = [ - 'local.py', - 'components/base.py', - 'components/database.py', - 'components/cache.py', - 'components/jet.py', - 'components/emails.py', - 'components/texts.py', - 'components/locale.py', - 'components/logging.py', - 'components/oauth.py', + "local.py", + "components/base.py", + "components/database.py", + "components/cache.py", + "components/jet.py", + "components/emails.py", + "components/texts.py", + "components/locale.py", + "components/logging.py", + "components/oauth.py", ] include(*base_settings) diff --git a/jdav_web/jdav_web/settings/components/base.py b/jdav_web/jdav_web/settings/components/base.py index f3b5d89..b7e8f1a 100644 --- a/jdav_web/jdav_web/settings/components/base.py +++ b/jdav_web/jdav_web/settings/components/base.py @@ -1,28 +1,31 @@ -deployed = get_var('django', 'deployed', default=False) +# ruff: noqa F821 + +deployed = get_var("django", "deployed", default=False) # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = get_var('django', 'secret_key', default='secret') +SECRET_KEY = get_var("django", "secret_key", default="secret") # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = get_var('django', 'debug', default=True) +DEBUG = get_var("django", "debug", default=True) -ALLOWED_HOSTS = get_var('django', 'allowed_hosts', default=["*"]) +ALLOWED_HOSTS = get_var("django", "allowed_hosts", default=["*"]) # hostname and base url -HOST = get_var('django', 'host', default='localhost:8000') -PROTOCOL = get_var('django', 'protocol', default='https') -BASE_URL = get_var('django', 'base_url', default=HOST) +HOST = get_var("django", "host", default="localhost:8000") +PROTOCOL = get_var("django", "protocol", default="https") +BASE_URL = get_var("django", "base_url", default=HOST) # Define media paths e.g. for image storage -MEDIA_URL = '/media/' -MEDIA_ROOT = get_var('django', 'media_root', - default=os.path.join((os.path.join(BASE_DIR, os.pardir)), "media")) +MEDIA_URL = "/media/" +MEDIA_ROOT = get_var( + "django", "media_root", default=os.path.join((os.path.join(BASE_DIR, os.pardir)), "media") +) # default primary key auto field type -DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' +DEFAULT_AUTO_FIELD = "django.db.models.AutoField" # prevent large files from being unreadable by the server # see @@ -36,71 +39,70 @@ USE_X_FORWARDED_HOST = True # Application definition INSTALLED_APPS = [ - 'logindata.apps.LoginDataConfig', - 'contrib.apps.ContribConfig', - 'startpage.apps.StartpageConfig', - 'material.apps.MaterialConfig', - 'members.apps.MembersConfig', - 'mailer.apps.MailerConfig', - 'finance.apps.FinanceConfig', - 'ludwigsburgalpin.apps.LudwigsburgalpinConfig', + "logindata.apps.LoginDataConfig", + "contrib.apps.ContribConfig", + "startpage.apps.StartpageConfig", + "material.apps.MaterialConfig", + "members.apps.MembersConfig", + "mailer.apps.MailerConfig", + "finance.apps.FinanceConfig", + "ludwigsburgalpin.apps.LudwigsburgalpinConfig", #'easy_select2', - 'markdownify.apps.MarkdownifyConfig', - 'markdownx', - 'djcelery_email', - 'nested_admin', - 'django_celery_beat', - 'rules', - 'jet', - 'oauth2_provider', - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', + "markdownify.apps.MarkdownifyConfig", + "markdownx", + "djcelery_email", + "nested_admin", + "django_celery_beat", + "rules", + "jet", + "oauth2_provider", + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", ] MIDDLEWARE = [ - 'django.middleware.cache.UpdateCacheMiddleware', - 'jdav_web.middleware.ForceLangMiddleware', - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.locale.LocaleMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', - 'django.middleware.cache.FetchFromCacheMiddleware', + "django.middleware.cache.UpdateCacheMiddleware", + "jdav_web.middleware.ForceLangMiddleware", + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.locale.LocaleMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", + "django.middleware.cache.FetchFromCacheMiddleware", ] -X_FRAME_OPTIONS = 'SAMEORIGIN' +X_FRAME_OPTIONS = "SAMEORIGIN" -ROOT_URLCONF = 'jdav_web.urls' +ROOT_URLCONF = "jdav_web.urls" TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [os.path.join(CONFIG_DIR_PATH, 'templates'), - os.path.join(BASE_DIR, 'templates')], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [os.path.join(CONFIG_DIR_PATH, "templates"), os.path.join(BASE_DIR, "templates")], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", ], }, }, ] -WSGI_APPLICATION = 'jdav_web.wsgi.application' +WSGI_APPLICATION = "jdav_web.wsgi.application" AUTHENTICATION_BACKENDS = ( - 'django.contrib.auth.backends.ModelBackend', - 'rules.permissions.ObjectPermissionBackend', + "django.contrib.auth.backends.ModelBackend", + "rules.permissions.ObjectPermissionBackend", ) # Password validation @@ -108,23 +110,23 @@ AUTHENTICATION_BACKENDS = ( AUTH_PASSWORD_VALIDATORS = [ { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", }, ] # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.10/howto/static-files/ -STATIC_URL = '/static/' +STATIC_URL = "/static/" STATICFILES_DIRS = [ os.path.join(CONFIG_DIR_PATH, "static"), os.path.join(BASE_DIR, "static"), @@ -132,70 +134,76 @@ STATICFILES_DIRS = [ # static root where all the static files are collected to # use python3 manage.py collectstatic to collect static files in the STATIC_ROOT # this is needed for deployment -STATIC_ROOT = get_var('django', 'static_root', default='/var/www/jdav_web/static') -DEFAULT_STATIC_PATH = get_var('django', 'default_static_path', default='/app/jdav_web/static') +STATIC_ROOT = get_var("django", "static_root", default="/var/www/jdav_web/static") +DEFAULT_STATIC_PATH = get_var("django", "default_static_path", default="/app/jdav_web/static") # Locale files (translations) -LOCALE_PATHS = (os.path.join(BASE_DIR, 'locale'),) +LOCALE_PATHS = (os.path.join(BASE_DIR, "locale"),) # Celery and Redis setup -BROKER_URL = get_var('django', 'broker_url', default='redis://localhost:6379/0') +BROKER_URL = get_var("django", "broker_url", default="redis://localhost:6379/0") # password hash algorithms used PASSWORD_HASHERS = [ - 'django.contrib.auth.hashers.BCryptPasswordHasher', - 'django.contrib.auth.hashers.PBKDF2PasswordHasher', - 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', - 'django.contrib.auth.hashers.Argon2PasswordHasher', - 'django.contrib.auth.hashers.ScryptPasswordHasher', + "django.contrib.auth.hashers.BCryptPasswordHasher", + "django.contrib.auth.hashers.PBKDF2PasswordHasher", + "django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher", + "django.contrib.auth.hashers.Argon2PasswordHasher", + "django.contrib.auth.hashers.ScryptPasswordHasher", ] MARKDOWNIFY = { - 'default': { + "default": { "WHITELIST_TAGS": [ - 'img', - 'abbr', - 'acronym', - 'a', - 'b', - 'blockquote', - 'em', - 'i', - 'li', - 'ol', - 'p', - 'strong', - 'ul', - 'br', - 'code', - 'span', - 'div', 'class', - 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' + "img", + "abbr", + "acronym", + "a", + "b", + "blockquote", + "em", + "i", + "li", + "ol", + "p", + "strong", + "ul", + "br", + "code", + "span", + "div", + "class", + "pre", + "h1", + "h2", + "h3", + "h4", + "h5", + "h6", ], "WHITELIST_ATTRS": [ - 'src', - 'href', - 'style', - 'alt', - 'class', + "src", + "href", + "style", + "alt", + "class", ], "LINKIFY_TEXT": { "PARSE_URLS": True, - # Next key/value-pairs only have effect if "PARSE_URLS" is True "PARSE_EMAIL": True, "CALLBACKS": [], "SKIP_TAGS": [], - } + }, } } # allowed characters in names appearing in urls on the website -STARTPAGE_URL_NAME_PATTERN = "[\w\-: *]" +STARTPAGE_URL_NAME_PATTERN = r"[\w\-: *]" # admins to contact on error messages -ADMINS = get_var('section', 'admins', default=[]) +ADMINS = get_var("section", "admins", default=[]) -LOGIN_URL = '/de/kompass/login/' +LOGIN_URL = "/de/kompass/login/" diff --git a/jdav_web/jdav_web/settings/components/cache.py b/jdav_web/jdav_web/settings/components/cache.py index 512a2fc..55ff0a4 100644 --- a/jdav_web/jdav_web/settings/components/cache.py +++ b/jdav_web/jdav_web/settings/components/cache.py @@ -1,17 +1,18 @@ +# ruff: noqa F821 + CACHES = { - 'default': { - 'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache', - 'LOCATION': get_var('django', 'memcached_url', default='127.0.0.1:11211'), - 'OPTIONS': { - 'no_delay': True, - 'ignore_exc': True, - 'max_pool_size': 4, - 'use_pooling': True, - } + "default": { + "BACKEND": "django.core.cache.backends.memcached.PyMemcacheCache", + "LOCATION": get_var("django", "memcached_url", default="127.0.0.1:11211"), + "OPTIONS": { + "no_delay": True, + "ignore_exc": True, + "max_pool_size": 4, + "use_pooling": True, + }, } } -CACHE_MIDDLEWARE_ALIAS = 'default' +CACHE_MIDDLEWARE_ALIAS = "default" CACHE_MIDDLEWARE_SECONDS = 1 -CACHE_MIDDLEWARE_KEY_PREFIX = '' - +CACHE_MIDDLEWARE_KEY_PREFIX = "" diff --git a/jdav_web/jdav_web/settings/components/database.py b/jdav_web/jdav_web/settings/components/database.py index 6ff11b3..11171af 100644 --- a/jdav_web/jdav_web/settings/components/database.py +++ b/jdav_web/jdav_web/settings/components/database.py @@ -1,14 +1,15 @@ +# ruff: noqa F821 + # Database # https://docs.djangoproject.com/en/1.10/ref/settings/#databases DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.mysql', - 'NAME': get_var('database', 'database', default='jdav_db'), - 'USER': get_var('database', 'user', default='user'), - 'PASSWORD': get_var('database', 'password', default='secret'), - 'HOST': get_var('database', 'host', default='127.0.0.1'), - 'PORT': get_var('database', 'port', default=5432) + "default": { + "ENGINE": "django.db.backends.mysql", + "NAME": get_var("database", "database", default="jdav_db"), + "USER": get_var("database", "user", default="user"), + "PASSWORD": get_var("database", "password", default="secret"), + "HOST": get_var("database", "host", default="127.0.0.1"), + "PORT": get_var("database", "port", default=5432), } } - diff --git a/jdav_web/jdav_web/settings/components/emails.py b/jdav_web/jdav_web/settings/components/emails.py index c8a1c11..4f0f375 100644 --- a/jdav_web/jdav_web/settings/components/emails.py +++ b/jdav_web/jdav_web/settings/components/emails.py @@ -1,17 +1,19 @@ +# ruff: noqa F821 + # Email setup -EMAIL_HOST = get_var('mail', 'host', default='localhost') -EMAIL_PORT = get_var('mail', 'port', default=587 if deployed else 25) -EMAIL_HOST_USER = get_var('mail', 'user', default='user') -EMAIL_HOST_PASSWORD = get_var('mail', 'password', default='secret') -EMAIL_USE_TLS = get_var('mail', 'tls', default=True if deployed else False) -EMAIL_BACKEND = 'djcelery_email.backends.CeleryEmailBackend' +EMAIL_HOST = get_var("mail", "host", default="localhost") +EMAIL_PORT = get_var("mail", "port", default=587 if deployed else 25) +EMAIL_HOST_USER = get_var("mail", "user", default="user") +EMAIL_HOST_PASSWORD = get_var("mail", "password", default="secret") +EMAIL_USE_TLS = get_var("mail", "tls", default=True if deployed else False) +EMAIL_BACKEND = "djcelery_email.backends.CeleryEmailBackend" # Celery Email Setup CELERY_EMAIL_TASK_CONFIG = { - 'rate_limit' : '10/m' # * CELERY_EMAIL_CHUNK_SIZE (default: 10) + "rate_limit": "10/m" # * CELERY_EMAIL_CHUNK_SIZE (default: 10) } -DEFAULT_SENDING_MAIL = get_var('mail', 'default_sending_address', default='kompass@localhost') -DEFAULT_SENDING_NAME = get_var('mail', 'default_sending_name', default='Kompass') +DEFAULT_SENDING_MAIL = get_var("mail", "default_sending_address", default="kompass@localhost") +DEFAULT_SENDING_NAME = get_var("mail", "default_sending_name", default="Kompass") diff --git a/jdav_web/jdav_web/settings/components/jet.py b/jdav_web/jdav_web/settings/components/jet.py index 2473b73..60b25cd 100644 --- a/jdav_web/jdav_web/settings/components/jet.py +++ b/jdav_web/jdav_web/settings/components/jet.py @@ -1,64 +1,116 @@ +# ruff: noqa F821 + # JET options (admin interface) JET_SIDE_MENU_COMPACT = True -JET_DEFAULT_THEME = 'jdav-green' +JET_DEFAULT_THEME = "jdav-green" JET_CHANGE_FORM_SIBLING_LINKS = False JET_SIDE_MENU_ITEMS = [ - {'label': 'Teilnehmer*innenverwaltung', 'app_label': 'members', 'items': [ - {'name': 'member', 'label': 'Alle Teilnehmer*innen', 'permissions': ['members.view_member']}, - {'name': 'freizeit', 'permissions': ['members.view_freizeit']}, - {'name': 'group', 'permissions': ['members.view_group']}, - {'name': 'membernotelist', 'permissions': ['members.view_membernotelist']}, - {'name': 'klettertreff', 'permissions': ['members.view_klettertreff']}, - ]}, - {'label': 'Neue Mitglieder', 'app_label': 'members', 'permissions': ['members.view_memberunconfirmedproxy'], 'items': [ - {'name': 'memberunconfirmedproxy', 'permissions': ['members.view_memberunconfirmedproxy']}, - {'name': 'memberwaitinglist', 'permissions': ['members.view_memberwaitinglist']}, - ]}, - {'label': 'Ausbildung', 'app_label': 'members', 'permissions': ['members.view_membertraining'], 'items': [ - {'name': 'membertraining', 'permissions': ['members.view_membertraining']}, - {'name': 'trainingcategory', 'permissions': ['members.view_trainingcategory']}, - {'name': 'activitycategory', 'permissions': ['members.view_activitycategory']}, - ]}, - {'app_label': 'mailer', 'items': [ - {'name': 'message', 'permissions': ['mailer.view_message']}, - {'name': 'emailaddress', 'permissions': ['mailer.view_emailaddress']}, - ]}, - {'app_label': 'finance', 'items': [ - {'name': 'statement', 'permissions': ['finance.view_statement']}, - {'name': 'ledger', 'permissions': ['finance.view_ledger']}, - {'name': 'bill', 'permissions': ['finance.view_bill', 'finance.view_bill_admin']}, - {'name': 'transaction', 'permissions': ['finance.view_transaction']}, - ]}, - {'app_label': 'logindata', 'permissions': ['auth'], 'items': [ - {'name': 'authgroup', 'permissions': ['auth.group'] }, - {'name': 'logindatum', 'permissions': ['auth.user']}, - {'name': 'registrationpassword', 'permissions': ['auth.user']}, - ]}, - {'app_label': 'django_celery_beat', 'permissions': ['django_celery_beat'], 'items': [ - {'name': 'crontabschedule'}, - {'name': 'clockedschedule'}, - {'name': 'intervalschedule'}, - {'name': 'periodictask'}, - {'name': 'solarschedule'}, - ]}, - {'app_label': 'ludwigsburgalpin', 'permissions': ['ludwigsburgalpin'], 'items': [ - {'name': 'termin', 'permissions': ['ludwigsburgalpin.view_termin']}, - ]}, - {'app_label': 'material', 'permissions': ['material.view_materialpart'], 'items': [ - {'name': 'materialcategory', 'permissions': ['material.view_materialcategory']}, - {'name': 'materialpart', 'permissions': ['material.view_materialpart']}, - ]}, - {'app_label': 'startpage', 'permissions': ['startpage'], 'items': [ - {'name': 'section', 'permissions': ['startpage.view_section']}, - {'name': 'post', 'permissions': ['startpage.view_post']}, - {'name': 'link', 'permissions': ['startpage.view_link']}, - ]}, - {'label': 'Externe Links', 'items' : [ - { 'label': 'Nextcloud', 'url': CLOUD_LINK, 'url_blank': True }, - { 'label': 'DAV 360', 'url': DAV_360_LINK, 'url_blank': True }, - { 'label': 'Julei-Wiki', 'url': WIKI_LINK, 'url_blank': True }, - { 'label': 'Kompass Dokumentation', 'url': DOCS_LINK, 'url_blank': True }, - ]}, + { + "label": "Teilnehmer*innenverwaltung", + "app_label": "members", + "items": [ + { + "name": "member", + "label": "Alle Teilnehmer*innen", + "permissions": ["members.view_member"], + }, + {"name": "freizeit", "permissions": ["members.view_freizeit"]}, + {"name": "group", "permissions": ["members.view_group"]}, + {"name": "membernotelist", "permissions": ["members.view_membernotelist"]}, + {"name": "klettertreff", "permissions": ["members.view_klettertreff"]}, + ], + }, + { + "label": "Neue Mitglieder", + "app_label": "members", + "permissions": ["members.view_memberunconfirmedproxy"], + "items": [ + { + "name": "memberunconfirmedproxy", + "permissions": ["members.view_memberunconfirmedproxy"], + }, + {"name": "memberwaitinglist", "permissions": ["members.view_memberwaitinglist"]}, + ], + }, + { + "label": "Ausbildung", + "app_label": "members", + "permissions": ["members.view_membertraining"], + "items": [ + {"name": "membertraining", "permissions": ["members.view_membertraining"]}, + {"name": "trainingcategory", "permissions": ["members.view_trainingcategory"]}, + {"name": "activitycategory", "permissions": ["members.view_activitycategory"]}, + ], + }, + { + "app_label": "mailer", + "items": [ + {"name": "message", "permissions": ["mailer.view_message"]}, + {"name": "emailaddress", "permissions": ["mailer.view_emailaddress"]}, + ], + }, + { + "app_label": "finance", + "items": [ + {"name": "statement", "permissions": ["finance.view_statement"]}, + {"name": "ledger", "permissions": ["finance.view_ledger"]}, + {"name": "bill", "permissions": ["finance.view_bill", "finance.view_bill_admin"]}, + {"name": "transaction", "permissions": ["finance.view_transaction"]}, + ], + }, + { + "app_label": "logindata", + "permissions": ["auth"], + "items": [ + {"name": "authgroup", "permissions": ["auth.group"]}, + {"name": "logindatum", "permissions": ["auth.user"]}, + {"name": "registrationpassword", "permissions": ["auth.user"]}, + ], + }, + { + "app_label": "django_celery_beat", + "permissions": ["django_celery_beat"], + "items": [ + {"name": "crontabschedule"}, + {"name": "clockedschedule"}, + {"name": "intervalschedule"}, + {"name": "periodictask"}, + {"name": "solarschedule"}, + ], + }, + { + "app_label": "ludwigsburgalpin", + "permissions": ["ludwigsburgalpin"], + "items": [ + {"name": "termin", "permissions": ["ludwigsburgalpin.view_termin"]}, + ], + }, + { + "app_label": "material", + "permissions": ["material.view_materialpart"], + "items": [ + {"name": "materialcategory", "permissions": ["material.view_materialcategory"]}, + {"name": "materialpart", "permissions": ["material.view_materialpart"]}, + ], + }, + { + "app_label": "startpage", + "permissions": ["startpage"], + "items": [ + {"name": "section", "permissions": ["startpage.view_section"]}, + {"name": "post", "permissions": ["startpage.view_post"]}, + {"name": "link", "permissions": ["startpage.view_link"]}, + ], + }, + { + "label": "Externe Links", + "items": [ + {"label": "Nextcloud", "url": CLOUD_LINK, "url_blank": True}, + {"label": "DAV 360", "url": DAV_360_LINK, "url_blank": True}, + {"label": "Julei-Wiki", "url": WIKI_LINK, "url_blank": True}, + {"label": "Kompass Dokumentation", "url": DOCS_LINK, "url_blank": True}, + ], + }, ] diff --git a/jdav_web/jdav_web/settings/components/locale.py b/jdav_web/jdav_web/settings/components/locale.py index 4f69722..904fffe 100644 --- a/jdav_web/jdav_web/settings/components/locale.py +++ b/jdav_web/jdav_web/settings/components/locale.py @@ -1,9 +1,9 @@ # Internationalization # https://docs.djangoproject.com/en/1.10/topics/i18n/ -LANGUAGE_CODE = 'de' +LANGUAGE_CODE = "de" -TIME_ZONE = 'Europe/Berlin' +TIME_ZONE = "Europe/Berlin" USE_I18N = True USE_L10N = True diff --git a/jdav_web/jdav_web/settings/components/logging.py b/jdav_web/jdav_web/settings/components/logging.py index 464eb47..7ca57a8 100644 --- a/jdav_web/jdav_web/settings/components/logging.py +++ b/jdav_web/jdav_web/settings/components/logging.py @@ -1,10 +1,12 @@ -import os +# ruff: noqa F821 -DJANGO_LOG_LEVEL = get_var('logging', 'django_level', default='INFO') -ROOT_LOG_LEVEL = get_var('logging', 'level', default='INFO') -LOG_ERROR_TO_EMAIL = get_var('logging', 'email_admins', default=False) -LOG_EMAIL_BACKEND = EMAIL_BACKEND if LOG_ERROR_TO_EMAIL else "django.core.mail.backends.console.EmailBackend" -LOG_ERROR_INCLUDE_HTML = get_var('logging', 'error_report_include_html', default=False) +DJANGO_LOG_LEVEL = get_var("logging", "django_level", default="INFO") +ROOT_LOG_LEVEL = get_var("logging", "level", default="INFO") +LOG_ERROR_TO_EMAIL = get_var("logging", "email_admins", default=False) +LOG_EMAIL_BACKEND = ( + EMAIL_BACKEND if LOG_ERROR_TO_EMAIL else "django.core.mail.backends.console.EmailBackend" +) +LOG_ERROR_INCLUDE_HTML = get_var("logging", "error_report_include_html", default=False) LOGGING = { "version": 1, diff --git a/jdav_web/jdav_web/settings/components/oauth.py b/jdav_web/jdav_web/settings/components/oauth.py index 5e8b831..a3a3c1e 100644 --- a/jdav_web/jdav_web/settings/components/oauth.py +++ b/jdav_web/jdav_web/settings/components/oauth.py @@ -1,8 +1,10 @@ +# ruff: noqa F821 + OAUTH2_PROVIDER = { "OIDC_ENABLED": True, "PKCE_REQUIRED": False, "OAUTH2_VALIDATOR_CLASS": "logindata.oauth.CustomOAuth2Validator", - "OIDC_RSA_PRIVATE_KEY": get_var('oauth', 'oidc_rsa_private_key', default=''), + "OIDC_RSA_PRIVATE_KEY": get_var("oauth", "oidc_rsa_private_key", default=""), "SCOPES": { "openid": "OpenID Connect scope", "profile": "profile scope", diff --git a/jdav_web/jdav_web/settings/components/texts.py b/jdav_web/jdav_web/settings/components/texts.py index 43bc197..6f07c03 100644 --- a/jdav_web/jdav_web/settings/components/texts.py +++ b/jdav_web/jdav_web/settings/components/texts.py @@ -1,17 +1,24 @@ +# ruff: noqa F821 + # mail texts -CONFIRM_MAIL_TEXT = get_text('confirm_mail', default="""Hallo {name}, +CONFIRM_MAIL_TEXT = get_text( + "confirm_mail", + default="""Hallo {{name}}, -du hast bei der JDAV %(SEKTION)s eine E-Mail Adresse hinterlegt. Da bei uns alle Kommunikation -per Email funktioniert, brauchen wir eine Bestätigung {whattoconfirm}. Dazu klicke bitte einfach auf +du hast bei der JDAV {SEKTION} eine E-Mail Adresse hinterlegt. Da bei uns alle Kommunikation +per Email funktioniert, brauchen wir eine Bestätigung {{whattoconfirm}}. Dazu klicke bitte einfach auf folgenden Link: -{link} +{{link}} Viele Grüße -Deine JDAV %(SEKTION)s""" % { 'SEKTION': SEKTION }) +Deine JDAV {SEKTION}""".format(SEKTION=SEKTION), +) -NEW_UNCONFIRMED_REGISTRATION = get_text('new_unconfirmed_registration', default="""Hallo {name}, +NEW_UNCONFIRMED_REGISTRATION = get_text( + "new_unconfirmed_registration", + default="""Hallo {name}, für deine Gruppe {group} liegt eine neue unbestätigte Reservierung vor. Die Person hat bereits ihre E-Mailadressen bestätigt und ihr Anmeldeformular hochgeladen. Bitte prüfe die Registrierung eingehend und @@ -20,69 +27,84 @@ bestätige falls möglich. Zu der Registrierung kommst du hier: {link} Viele Grüße -Dein KOMPASS""") +Dein KOMPASS""", +) -GROUP_INVITATION_LEFT_WAITINGLIST = get_text('group_invitation_left_waitinglist', - default="""Hallo {name}, +GROUP_INVITATION_LEFT_WAITINGLIST = get_text( + "group_invitation_left_waitinglist", + default="""Hallo {name}, der*die kürzlich zu einer Schnupperstunde für die Gruppe {group} eingeladene Wartende {waiter} hat die Warteliste verlassen. Viele Grüße -Dein KOMPASS""") +Dein KOMPASS""", +) -GROUP_INVITATION_REJECTED = get_text('group_invitation_rejected', - default="""Hallo {name}, +GROUP_INVITATION_REJECTED = get_text( + "group_invitation_rejected", + default="""Hallo {name}, {waiter} hat die Einladung zu einer Schnupperstunde bei der Gruppe {group} abgelehnt, ist aber weiterhin auf der Warteliste. Viele Grüße -Dein KOMPASS""") +Dein KOMPASS""", +) -GROUP_INVITATION_CONFIRMED_TEXT = get_text('group_invitation_confirmed', - default="""Hallo {name}, +GROUP_INVITATION_CONFIRMED_TEXT = get_text( + "group_invitation_confirmed", + default="""Hallo {name}, {waiter} hat die Einladung zu einer Schnupperstunde bei der Gruppe {group} angenommen. Viele Grüße -Dein KOMPASS""") +Dein KOMPASS""", +) -TRIAL_GROUP_MEETING_CONFIRMED_TEXT = get_text('trial_group_meeting_confirmed', - default="""Hallo {name}, +TRIAL_GROUP_MEETING_CONFIRMED_TEXT = get_text( + "trial_group_meeting_confirmed", + default="""Hallo {{name}}, -deine Teilnahme an der Schnupperstunde der Gruppe {group} wurde erfolgreich bestätigt. -{timeinfo} +deine Teilnahme an der Schnupperstunde der Gruppe {{group}} wurde erfolgreich bestätigt. +{{timeinfo}} Für alle weiteren Absprachen, kontaktiere bitte die Jugendleiter*innen der Gruppe -unter {contact_email}. +unter {{contact_email}}. Viele Grüße -Deine JDAV %(SEKTION)s""" % { 'SEKTION': SEKTION }) +Deine JDAV {SEKTION}""".format(SEKTION=SEKTION), +) -GROUP_TIME_AVAILABLE_TEXT = get_text('group_time_available', - default="""Die Gruppenstunde findet jeden {weekday} von {start_time} bis {end_time} Uhr statt.""") +GROUP_TIME_AVAILABLE_TEXT = get_text( + "group_time_available", + default="""Die Gruppenstunde findet jeden {weekday} von {start_time} bis {end_time} Uhr statt.""", +) -GROUP_TIME_UNAVAILABLE_TEXT = get_text('group_time_unavailable', - default="""Bitte erfrage die Gruppenzeiten bei der Gruppenleitung ({contact_email}).""") +GROUP_TIME_UNAVAILABLE_TEXT = get_text( + "group_time_unavailable", + default="""Bitte erfrage die Gruppenzeiten bei der Gruppenleitung ({contact_email}).""", +) -INVITE_TEXT = get_text('invite', default="""Hallo {{name}}, +INVITE_TEXT = get_text( + "invite", + default="""Hallo {{{{name}}}}, -wir haben gute Neuigkeiten für dich. Es ist ein Platz in der Jugendgruppe {group_name} {group_link}freigeworden. -{group_time} +wir haben gute Neuigkeiten für dich. Es ist ein Platz in der Jugendgruppe {{group_name}} {{group_link}}freigeworden. +{{group_time}} Wenn du an der Schnupperstunde teilnehmen möchtest, bestätige deine Teilnahme bitte unter folgendem Link: -{{invitation_confirm_link}} +{{{{invitation_confirm_link}}}} -Für alle weiteren Absprachen, kontaktiere bitte die Gruppenleitung ({contact_email}). +Für alle weiteren Absprachen, kontaktiere bitte die Gruppenleitung ({{contact_email}}). Wenn du nach der Schnupperstunde beschließt der Gruppe beizutreten, benötigen wir noch ein paar Informationen und eine schriftliche Anmeldebestätigung von dir. Das kannst du alles über folgenden Link erledigen: -{{link}} +{{{{link}}}} Du siehst dort auch die Daten, die du bei deiner Eintragung auf die Warteliste angegeben hast. Bitte überprüfe, ob die Daten noch stimmen und ändere sie bei Bedarf ab. @@ -90,27 +112,35 @@ Du siehst dort auch die Daten, die du bei deiner Eintragung auf die Warteliste a Falls du zu dem obigen Termin keine Zeit hast oder dich ganz von der Warteliste abmelden möchtest, lehne bitte diese Einladung unter folgendem Link ab: -{{invitation_reject_link}} +{{{{invitation_reject_link}}}} -Bei Fragen, wende dich gerne an %(RESPONSIBLE_MAIL)s. +Bei Fragen, wende dich gerne an {RESPONSIBLE_MAIL}. Viele Grüße -Deine JDAV %(SEKTION)s""" % { 'SEKTION': SEKTION, 'RESPONSIBLE_MAIL': RESPONSIBLE_MAIL, - 'REGISTRATION_FORM_DOWNLOAD_LINK': REGISTRATION_FORM_DOWNLOAD_LINK }) +Deine JDAV {SEKTION}""".format( + SEKTION=SEKTION, + RESPONSIBLE_MAIL=RESPONSIBLE_MAIL, + ), +) -LEAVE_WAITINGLIST_TEXT = get_text('leave_waitinglist', default="""Hallo {name}, +LEAVE_WAITINGLIST_TEXT = get_text( + "leave_waitinglist", + default="""Hallo {{name}}, du hast dich erfolgreich von der Warteliste abgemeldet. Falls du zu einem späteren Zeitpunkt wieder der Warteliste beitreten möchtest, kannst du das über unsere Webseite machen. -Falls du dich nicht selbst abgemeldet hast, wende dich bitte umgehend an %(RESPONSIBLE_MAIL)s. +Falls du dich nicht selbst abgemeldet hast, wende dich bitte umgehend an {RESPONSIBLE_MAIL}. Viele Grüße -Deine JDAV %(SEKTION)s""" % { 'SEKTION': SEKTION, 'RESPONSIBLE_MAIL': RESPONSIBLE_MAIL }) +Deine JDAV {SEKTION}""".format(SEKTION=SEKTION, RESPONSIBLE_MAIL=RESPONSIBLE_MAIL), +) -WAIT_CONFIRMATION_TEXT = get_text('wait_confirmation', default="""Hallo {name}, +WAIT_CONFIRMATION_TEXT = get_text( + "wait_confirmation", + default="""Hallo {{name}}, leider können wir dir zur Zeit noch keinen Platz in einer Jugendgruppe anbieten. Da wir sehr viele Interessenten haben und wir möglichst vielen die Möglichkeit bieten möchten, an @@ -119,22 +149,25 @@ Warteliste ab, ob sie noch Interesse haben. Wenn du weiterhin auf der Warteliste bleiben möchtest, klicke auf den folgenden Link: -{link} +{{link}} Falls du kein Interesse mehr hast, kannst du unter folgendem Link die Warteliste verlassen: -{leave_link} +{{leave_link}} -Das ist Erinnerung Nummer {reminder} von {max_reminder_count}. Nach Erinnerung Nummer {max_reminder_count} wirst +Das ist Erinnerung Nummer {{reminder}} von {{max_reminder_count}}. Nach Erinnerung Nummer {{max_reminder_count}} wirst du automatisch entfernt. Viele Grüße -Deine JDAV %(SEKTION)s""" % { 'SEKTION': SEKTION }) +Deine JDAV {SEKTION}""".format(SEKTION=SEKTION), +) -JOIN_WAITINGLIST_CONFIRMATION_TEXT = get_text('join_waitinglist_confirmation', default="""Hallo {name}, +JOIN_WAITINGLIST_CONFIRMATION_TEXT = get_text( + "join_waitinglist_confirmation", + default="""Hallo {{name}}, -vielen Dank für dein Interesse an einem Platz in einer Jugendgruppe der JDAV %(SEKTION)s. Du hast dich erfolgreich +vielen Dank für dein Interesse an einem Platz in einer Jugendgruppe der JDAV {SEKTION}. Du hast dich erfolgreich für die Warteliste registriert. Leider ist die Nachfrage nach Jugendgruppenplätzen deutlich höher als unsere Kapazitäten. Daher kann es @@ -143,34 +176,43 @@ aktuell bleibt, werden wir dich in regelmäßigen Abständen per E-Mail bitten, zu bestätigen. Viele Grüße -Deine JDAV %(SEKTION)s""" % { 'SEKTION': SEKTION }) +Deine JDAV {SEKTION}""".format(SEKTION=SEKTION), +) -UNSUBSCRIBE_CONFIRMATION_TEXT = get_text('unsubscribe_confirmation', default="""Klicke auf den Link, um dich vom Newsletter der JDAV %(SEKTION)s abzumelden +UNSUBSCRIBE_CONFIRMATION_TEXT = get_text( + "unsubscribe_confirmation", + default="""Klicke auf den Link, um dich vom Newsletter der JDAV {SEKTION} abzumelden -{link}""" % { 'SEKTION': SEKTION }) +{{link}}""".format(SEKTION=SEKTION), +) -NOTIFY_MOST_ACTIVE_TEXT = get_text('notify_most_active', default="""Hallo {name}! +NOTIFY_MOST_ACTIVE_TEXT = get_text( + "notify_most_active", + default="""Hallo {{name}}! -Herzlichen Glückwunsch, du hast im letzten Jahr zu den {congratulate_max} aktivsten -Mitgliedern der JDAV %(SEKTION)s gehört! Um genau zu sein beträgt dein Aktivitäts Wert -des letzten Jahres {score} Punkte. Das entspricht {level} Kletterer:innen. Damit warst du -im letzten Jahr das {position}aktivste Mitglied der JDAV %(SEKTION)s. +Herzlichen Glückwunsch, du hast im letzten Jahr zu den {{congratulate_max}} aktivsten +Mitgliedern der JDAV {SEKTION} gehört! Um genau zu sein beträgt dein Aktivitäts Wert +des letzten Jahres {{score}} Punkte. Das entspricht {{level}} Kletterer:innen. Damit warst du +im letzten Jahr das {{position}}aktivste Mitglied der JDAV {SEKTION}. -Auf ein weiteres aktives Jahr in der JDAV %(SEKTION)s. +Auf ein weiteres aktives Jahr in der JDAV {SEKTION}. -Dein:e Jugendreferent:in""" % { 'SEKTION': SEKTION }) +Dein:e Jugendreferent:in""".format(SEKTION=SEKTION), +) -ECHO_TEXT = get_text('echo', default="""Hallo {name}, +ECHO_TEXT = get_text( + "echo", + default="""Hallo {{name}}, um unsere Daten auf dem aktuellen Stand zu halten und sicherzugehen, dass du weiterhin ein Teil unserer Jugendarbeit bleiben möchtest, brauchen wir eine kurze Bestätigung von dir. Dafür besuche einfach diesen Link: -{link} +{{link}} Dort kannst du deine Daten nach Eingabe eines Passworts überprüfen und ggf. ändern. Dein Passwort ist dein Geburtsdatum. Wäre dein Geburtsdatum zum Beispiel der 4. Januar 1942, @@ -180,76 +222,94 @@ Falls du nicht innerhalb von 30 Tagen deine Daten bestätigst, gehen wir davon a unserer Jugendarbeit sein möchtest. Dein Platz wird dann weitervergeben, deine Daten aus unserer Datenbank gelöscht und du erhälst in Zukunft keine Mails mehr von uns. -Bei Fragen, wende dich gerne an %(RESPONSIBLE_MAIL)s. +Bei Fragen, wende dich gerne an {RESPONSIBLE_MAIL}. Viele Grüße -Deine JDAV %(SEKTION)s""" % { 'SEKTION': SEKTION, 'RESPONSIBLE_MAIL': RESPONSIBLE_MAIL }) +Deine JDAV {SEKTION}""".format(SEKTION=SEKTION, RESPONSIBLE_MAIL=RESPONSIBLE_MAIL), +) -PREPEND_INCOMPLETE_REGISTRATION_TEXT = get_text('prepend_incomplete_registration', default="""WICHTIGE MITTEILUNG +PREPEND_INCOMPLETE_REGISTRATION_TEXT = get_text( + "prepend_incomplete_registration", + default="""WICHTIGE MITTEILUNG Deine Anmeldung ist aktuell nicht vollständig. Bitte fülle umgehend das Anmeldeformular aus und lasse es Deine*r Jugendleiter*in zukommen! Dieses kannst Du unter folgendem Link herunterladen: -%(REGISTRATION_FORM_DOWNLOAD_LINK)s +{REGISTRATION_FORM_DOWNLOAD_LINK} **************** -""" % { 'REGISTRATION_FORM_DOWNLOAD_LINK': REGISTRATION_FORM_DOWNLOAD_LINK }) +""".format(REGISTRATION_FORM_DOWNLOAD_LINK=REGISTRATION_FORM_DOWNLOAD_LINK), +) -MAIL_FOOTER = get_text('mail_footer', default=""" +MAIL_FOOTER = get_text( + "mail_footer", + default=""" **************** -Diese Email wurde über die Webseite der JDAV %(SEKTION)s +Diese Email wurde über die Webseite der JDAV {SEKTION} verschickt. Wenn Du in Zukunft keine Emails mehr erhalten möchtest, kannst Du hier den Newsletter deabonnieren: -{link}""" % { 'SEKTION': SEKTION }) +{{link}}""".format(SEKTION=SEKTION), +) -INVITE_AS_USER_TEXT = get_text('invite_as_user', default="""Hallo {name}, +INVITE_AS_USER_TEXT = get_text( + "invite_as_user", + default="""Hallo {{name}}, -du bist Jugendleiter*in in der Sektion %(SEKTION)s. Die Verwaltung unserer Jugendgruppen, +du bist Jugendleiter*in in der Sektion {SEKTION}. Die Verwaltung unserer Jugendgruppen, Ausfahrten und Finanzen erfolgt in unserer Online Plattform Kompass. Deine Stammdaten sind dort bereits hinterlegt. Damit du dich auch anmelden kannst, folge bitte dem folgenden Link und wähle ein Passwort. -{link} +{{link}} -Bei Fragen, wende dich gerne an %(RESPONSIBLE_MAIL)s. +Bei Fragen, wende dich gerne an {RESPONSIBLE_MAIL}. Viele Grüße -Deine JDAV %(SEKTION)s""" % { 'SEKTION': SEKTION, 'RESPONSIBLE_MAIL': RESPONSIBLE_MAIL }) +Deine JDAV {SEKTION}""".format(SEKTION=SEKTION, RESPONSIBLE_MAIL=RESPONSIBLE_MAIL), +) -UPLOAD_REGISTRATION_FORM_TEXT = get_text('upload_registration_form', default="""Hallo {name}, +UPLOAD_REGISTRATION_FORM_TEXT = get_text( + "upload_registration_form", + default="""Hallo {{name}}, -vielen Dank für deine Anmeldung in der JDAV %(SEKTION)s. Bevor es richtig losgehen kann, brauchen +vielen Dank für deine Anmeldung in der JDAV {SEKTION}. Bevor es richtig losgehen kann, brauchen wir noch die Bestätigung deiner Daten und die Zustimmung zu unseren Teilnahmebedingungen. Dafür kannst du das für dich vorausgefüllte Anmeldeformular unter folgendem Link herunterladen, durchlesen und, falls du zustimmst, das unterschriebene Formular wieder dort hochladen. -{link} +{{link}} Bist du noch nicht volljährig? Dann muss eine erziehungsberechtigte Person das Formular unterschreiben. -Bei Fragen, wende dich gerne an %(RESPONSIBLE_MAIL)s. +Bei Fragen, wende dich gerne an {RESPONSIBLE_MAIL}. Viele Grüße -Deine JDAV %(SEKTION)s""" % { 'SEKTION': SEKTION, 'RESPONSIBLE_MAIL': RESPONSIBLE_MAIL }) +Deine JDAV {SEKTION}""".format(SEKTION=SEKTION, RESPONSIBLE_MAIL=RESPONSIBLE_MAIL), +) -ADDRESS = get_text('address', default="""JDAV %(SEKTION)s -%(STREET)s -%(PLACE)s""" % { 'SEKTION': SEKTION, 'STREET': SEKTION_STREET, 'PLACE': SEKTION_TOWN }) +ADDRESS = get_text( + "address", + default="""JDAV {SEKTION} +{STREET} +{PLACE}""".format(SEKTION=SEKTION, STREET=SEKTION_STREET, PLACE=SEKTION_TOWN), +) -NOTIFY_EXCURSION_PARTICIPANT_LIST = get_text('notify_excursion_participant_list', default="""Hallo {name}, +NOTIFY_EXCURSION_PARTICIPANT_LIST = get_text( + "notify_excursion_participant_list", + default="""Hallo {name}, deine Ausfahrt {excursion} steht kurz bevor. Damit die Sektion dich im Notfall gut unterstützen kann, benötigt die Geschäftsstelle eine aktuelle Kriseninterventionsliste, das heißt eine Teilnehmendenliste der Ausfahrt. @@ -262,9 +322,12 @@ Das sind die aktuell in der Ausfahrt eingetragenen Teilnehmenden: Falls diese Liste nicht mehr aktuell ist, gehe bitte umgehend auf {excursion_link} und trage die Daten nach. Viele Grüße -Dein KOMPASS""") +Dein KOMPASS""", +) -SEND_EXCURSION_CRISIS_LIST = get_text('send_excursion_crisis_list', default="""Hallo zusammen, +SEND_EXCURSION_CRISIS_LIST = get_text( + "send_excursion_crisis_list", + default="""Hallo zusammen, vom {excursion_start} bis {excursion_end} findet die Ausfahrt {excursion} der Jugend statt. Die Ausfahrt wird geleitet von {leaders}. @@ -272,12 +335,16 @@ Ausfahrt wird geleitet von {leaders}. Im Anhang findet ihr die Kriseninterventionsliste. Viele Grüße -Euer KOMPASS""") +Euer KOMPASS""", +) -SEND_STATEMENT_SUMMARY = get_text('send_statement_summary', default="""Hallo zusammen, +SEND_STATEMENT_SUMMARY = get_text( + "send_statement_summary", + default="""Hallo zusammen, anbei findet ihr die Abrechnung inklusive Belege für {statement}. Die Überweisungen wurden wie beschrieben ausgeführt. Viele Grüße -Euer KOMPASS""") +Euer KOMPASS""", +) diff --git a/jdav_web/jdav_web/settings/local.py b/jdav_web/jdav_web/settings/local.py index f60cb8b..31d7750 100644 --- a/jdav_web/jdav_web/settings/local.py +++ b/jdav_web/jdav_web/settings/local.py @@ -1,86 +1,98 @@ +# ruff: noqa F821 + # contact data -SEKTION = get_var('section', 'name', default='Heyo') -SEKTION_STREET = get_var('section', 'street', default='Street') -SEKTION_TOWN = get_var('section', 'town', default='12345 Town') -SEKTION_TELEPHONE = get_var('section', 'telephone', default='0123456789') -SEKTION_TELEFAX = get_var('section', 'telefax', default=SEKTION_TELEPHONE) -SEKTION_CONTACT_MAIL = get_var('section', 'contact_mail', default='info@example.org') -SEKTION_BOARD_MAIL = get_var('section', 'board_mail', default=SEKTION_CONTACT_MAIL) -SEKTION_CRISIS_INTERVENTION_MAIL = get_var('section', 'crisis_intervention_mail', - default=SEKTION_BOARD_MAIL) -SEKTION_FINANCE_MAIL = get_var('section', 'finance_mail', default=SEKTION_CONTACT_MAIL) -SEKTION_IBAN = get_var('section', 'iban', default='Foo 123') -SEKTION_ACCOUNT_HOLDER = get_var('section', 'account_holder', - default='Foo') - -RESPONSIBLE_MAIL = get_var('section', 'responsible_mail', default='foo@example.org') -DIGITAL_MAIL = get_var('section', 'digital_mail', default='bar@example.org') +SEKTION = get_var("section", "name", default="Heyo") +SEKTION_STREET = get_var("section", "street", default="Street") +SEKTION_TOWN = get_var("section", "town", default="12345 Town") +SEKTION_TELEPHONE = get_var("section", "telephone", default="0123456789") +SEKTION_TELEFAX = get_var("section", "telefax", default=SEKTION_TELEPHONE) +SEKTION_CONTACT_MAIL = get_var("section", "contact_mail", default="info@example.org") +SEKTION_BOARD_MAIL = get_var("section", "board_mail", default=SEKTION_CONTACT_MAIL) +SEKTION_CRISIS_INTERVENTION_MAIL = get_var( + "section", "crisis_intervention_mail", default=SEKTION_BOARD_MAIL +) +SEKTION_FINANCE_MAIL = get_var("section", "finance_mail", default=SEKTION_CONTACT_MAIL) +SEKTION_IBAN = get_var("section", "iban", default="Foo 123") +SEKTION_ACCOUNT_HOLDER = get_var("section", "account_holder", default="Foo") + +RESPONSIBLE_MAIL = get_var("section", "responsible_mail", default="foo@example.org") +DIGITAL_MAIL = get_var("section", "digital_mail", default="bar@example.org") # LJP -V32_HEAD_ORGANISATION = get_var('LJP', 'v32_head_organisation', default='not configured') -LJP_CONTRIBUTION_PER_DAY = get_var('LJP', 'contribution_per_day', default=25) -LJP_TAX = get_var('LJP', 'tax', default=0) +V32_HEAD_ORGANISATION = get_var("LJP", "v32_head_organisation", default="not configured") +LJP_CONTRIBUTION_PER_DAY = get_var("LJP", "contribution_per_day", default=25) +LJP_TAX = get_var("LJP", "tax", default=0) # echo # used to generate the personalized echo password -ECHO_PASSWORD_BIRTHDATE_FORMAT = get_var('echo', 'password_birthdate_format', default='%d.%m.%Y') +ECHO_PASSWORD_BIRTHDATE_FORMAT = get_var("echo", "password_birthdate_format", default="%d.%m.%Y") # grace period in days after which echo keys expire -ECHO_GRACE_PERIOD = get_var('echo', 'grace_period', default=30) +ECHO_GRACE_PERIOD = get_var("echo", "grace_period", default=30) # Waiting list configuration parameters, all numbers are in days -GRACE_PERIOD_WAITING_CONFIRMATION = get_var('waitinglist', 'grace_period_confirmation', default=30) -WAITING_CONFIRMATION_FREQUENCY = get_var('waitinglist', 'confirmation_frequency', default=90) -CONFIRMATION_REMINDER_FREQUENCY = get_var('waitinglist', 'confirmation_reminder_frequency', default=30) -MAX_REMINDER_COUNT = get_var('waitinglist', 'max_reminder_count', default=3) +GRACE_PERIOD_WAITING_CONFIRMATION = get_var("waitinglist", "grace_period_confirmation", default=30) +WAITING_CONFIRMATION_FREQUENCY = get_var("waitinglist", "confirmation_frequency", default=90) +CONFIRMATION_REMINDER_FREQUENCY = get_var( + "waitinglist", "confirmation_reminder_frequency", default=30 +) +MAX_REMINDER_COUNT = get_var("waitinglist", "max_reminder_count", default=3) # misc # the maximal number of members that get sent congratulations for highest activity on aprils fools day -CONGRATULATE_MEMBERS_MAX = get_var('misc', 'congratulate_members_max', default=10) +CONGRATULATE_MEMBERS_MAX = get_var("misc", "congratulate_members_max", default=10) # expiry duration of a good conduct certificate in months -MAX_AGE_GOOD_CONDUCT_CERTIFICATE_MONTHS = get_var('misc', 'max_age_good_conduct_certificate_months', default=24) +MAX_AGE_GOOD_CONDUCT_CERTIFICATE_MONTHS = get_var( + "misc", "max_age_good_conduct_certificate_months", default=24 +) # accepted email domains for inviting users -ALLOWED_EMAIL_DOMAINS_FOR_INVITE_AS_USER = get_var('misc', 'allowed_email_domains_for_invite_as_user', - default=['example.org']) +ALLOWED_EMAIL_DOMAINS_FOR_INVITE_AS_USER = get_var( + "misc", "allowed_email_domains_for_invite_as_user", default=["example.org"] +) # send all mails from the assocation's contact mail or from personal association mails -SEND_FROM_ASSOCIATION_EMAIL = get_var('misc', 'send_from_association_email', default=False) +SEND_FROM_ASSOCIATION_EMAIL = get_var("misc", "send_from_association_email", default=False) # domain for association email and generated urls -DOMAIN = get_var('misc', 'domain', default='example.org') - -GROUP_CHECKLIST_N_WEEKS = get_var('misc', 'group_checklist_n_weeks', default=18) -GROUP_CHECKLIST_N_MEMBERS = get_var('misc', 'group_checklist_n_members', default=20) -GROUP_CHECKLIST_TEXT = get_var('misc', 'group_checklist_text', - default="""Anwesende Jugendleitende und Teilnehmende werden mit einem -Kreuz ($\\times$) markiert und die ausgefüllte Liste zum Anfang der Gruppenstunde an der Kasse -abgegeben. Zum Ende wird sie wieder abgeholt. Wenn die Punkte auf einer Karte fast aufgebraucht -sind, notiert die Kasse die verbliebenen Eintritte (3, 2, 1) unter dem Kreuz.""") +DOMAIN = get_var("misc", "domain", default="example.org") + +GROUP_CHECKLIST_N_WEEKS = get_var("misc", "group_checklist_n_weeks", default=18) +GROUP_CHECKLIST_N_MEMBERS = get_var("misc", "group_checklist_n_members", default=20) +GROUP_CHECKLIST_TEXT = get_var( + "misc", + "group_checklist_text", + default="""Anwesende Jugendleitende und Teilnehmende werden mit einem +Kreuz ($\\times$) markiert und die ausgefüllte Liste zum Anfang der Gruppenstunde an der Kasse +abgegeben. Zum Ende wird sie wieder abgeholt. Wenn die Punkte auf einer Karte fast aufgebraucht +sind, notiert die Kasse die verbliebenen Eintritte (3, 2, 1) unter dem Kreuz.""", +) # finance -ALLOWANCE_PER_DAY = get_var('finance', 'allowance_per_day', default=22) -MAX_NIGHT_COST = get_var('finance', 'max_night_cost', default=11) +ALLOWANCE_PER_DAY = get_var("finance", "allowance_per_day", default=22) +MAX_NIGHT_COST = get_var("finance", "max_night_cost", default=11) -EXCURSION_ORG_FEE = get_var('finance', 'org_fee', default=10) +EXCURSION_ORG_FEE = get_var("finance", "org_fee", default=10) # links -CLOUD_LINK = get_var('links', 'cloud', default='https://startpage.com') -DAV_360_LINK = get_var('links', 'dav_360', default='https://dav360.de') -WIKI_LINK = get_var('links', 'wiki', default='https://wikipedia.org') -DOCS_LINK = get_var('links', 'docs', default='https://github.com/chrisflav/kompass') -REGISTRATION_FORM_DOWNLOAD_LINK = get_var('links', 'registration_form', default='https://startpage.com') +CLOUD_LINK = get_var("links", "cloud", default="https://startpage.com") +DAV_360_LINK = get_var("links", "dav_360", default="https://dav360.de") +WIKI_LINK = get_var("links", "wiki", default="https://wikipedia.org") +DOCS_LINK = get_var("links", "docs", default="https://github.com/chrisflav/kompass") +REGISTRATION_FORM_DOWNLOAD_LINK = get_var( + "links", "registration_form", default="https://startpage.com" +) # startpage -STARTPAGE_REDIRECT_URL = get_var('startpage', 'redirect_url', default='') -ROOT_SECTION = get_var('startpage', 'root_section', default='about') -RECENT_SECTION = get_var('startpage', 'recent_section', default='recent') -REPORTS_SECTION = get_var('startpage', 'reports_section', default='reports') +STARTPAGE_REDIRECT_URL = get_var("startpage", "redirect_url", default="") +ROOT_SECTION = get_var("startpage", "root_section", default="about") +RECENT_SECTION = get_var("startpage", "recent_section", default="recent") +REPORTS_SECTION = get_var("startpage", "reports_section", default="reports") # testing -TEST_MAIL = get_var('testing', 'mail', default='test@localhost') +TEST_MAIL = get_var("testing", "mail", default="test@localhost") diff --git a/jdav_web/jdav_web/tests.py b/jdav_web/jdav_web/tests.py index 6714873..a752ab1 100644 --- a/jdav_web/jdav_web/tests.py +++ b/jdav_web/jdav_web/tests.py @@ -1,29 +1,35 @@ -from django.test import TestCase, RequestFactory, override_settings -from django.contrib.auth.models import User +from unittest.mock import Mock +from unittest.mock import patch + from django.contrib import admin -from unittest.mock import Mock, patch -from jdav_web.views import media_unprotected, custom_admin_view +from django.contrib.auth.models import User +from django.test import override_settings +from django.test import RequestFactory +from django.test import TestCase from startpage.models import Link +from jdav_web.views import custom_admin_view +from jdav_web.views import media_unprotected + class ViewsTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.user = User.objects.create_user('testuser', 'test@example.com', 'password') - Link.objects.create(title='Test Link', url='https://example.com') + self.user = User.objects.create_user("testuser", "test@example.com", "password") + Link.objects.create(title="Test Link", url="https://example.com") @override_settings(DEBUG=True) def test_media_unprotected_debug_true(self): - request = self.factory.get('/media/test.jpg') - with patch('jdav_web.views.serve') as mock_serve: + request = self.factory.get("/media/test.jpg") + with patch("jdav_web.views.serve") as mock_serve: mock_serve.return_value = Mock() - result = media_unprotected(request, 'test.jpg') + media_unprotected(request, "test.jpg") mock_serve.assert_called_once() def test_custom_admin_view(self): - request = self.factory.get('/admin/') + request = self.factory.get("/admin/") request.user = self.user - with patch.object(admin.site, 'get_app_list') as mock_get_app_list: + with patch.object(admin.site, "get_app_list") as mock_get_app_list: mock_get_app_list.return_value = [] response = custom_admin_view(request) self.assertEqual(response.status_code, 200) diff --git a/jdav_web/jdav_web/urls.py b/jdav_web/jdav_web/urls.py index 1b034c0..0343509 100644 --- a/jdav_web/jdav_web/urls.py +++ b/jdav_web/jdav_web/urls.py @@ -13,40 +13,44 @@ Including another URLconf 1. Import the include() function: from django.conf.urls import url, include 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) """ -from django.urls import path, re_path, include -from django.contrib import admin -from django.conf.urls.static import static + from django.conf.urls.i18n import i18n_patterns -from django.conf import settings +from django.contrib import admin +from django.urls import include +from django.urls import path +from django.urls import re_path from django.utils.translation import gettext_lazy as _ from django.views.generic.base import RedirectView from oauth2_provider import urls as oauth2_urls + from .views import media_access -admin.site.index_title = _('Startpage') -admin.site.site_header = 'Kompass' +admin.site.index_title = _("Startpage") +admin.site.site_header = "Kompass" urlpatterns = i18n_patterns( - re_path(r'^media/(?P.*)', media_access, name='media'), - re_path(r'^kompass/?', admin.site.urls, name='kompass'), - re_path(r'^jet/', include('jet.urls', 'jet')), # Django JET URLS - re_path(r'^admin/?', RedirectView.as_view(url='/kompass')), - re_path(r'^newsletter/', include('mailer.urls', namespace="mailer")), - re_path(r'^members/', include('members.urls', namespace="members")), - re_path(r'^login/', include('logindata.urls', namespace="logindata")), - re_path(r'^LBAlpin/Programm(/)?(20)?[0-9]{0,2}', include('ludwigsburgalpin.urls', - namespace="ludwigsburgalpin")), - re_path(r'^_nested_admin/', include('nested_admin.urls')), - path('o/', include(oauth2_urls)), - re_path(r'^', include('startpage.urls', namespace="startpage")), + re_path(r"^media/(?P.*)", media_access, name="media"), + re_path(r"^kompass/?", admin.site.urls, name="kompass"), + re_path(r"^jet/", include("jet.urls", "jet")), # Django JET URLS + re_path(r"^admin/?", RedirectView.as_view(url="/kompass")), + re_path(r"^newsletter/", include("mailer.urls", namespace="mailer")), + re_path(r"^members/", include("members.urls", namespace="members")), + re_path(r"^login/", include("logindata.urls", namespace="logindata")), + re_path( + r"^LBAlpin/Programm(/)?(20)?[0-9]{0,2}", + include("ludwigsburgalpin.urls", namespace="ludwigsburgalpin"), + ), + re_path(r"^_nested_admin/", include("nested_admin.urls")), + path("o/", include(oauth2_urls)), + re_path(r"^", include("startpage.urls", namespace="startpage")), ) urlpatterns += [ - re_path(r'^markdownx/', include('markdownx.urls')), + re_path(r"^markdownx/", include("markdownx.urls")), ] -handler404 = 'startpage.views.handler404' -handler500 = 'startpage.views.handler500' +handler404 = "startpage.views.handler404" +handler500 = "startpage.views.handler500" # TODO: django serving from MEDIA_URL should be disabled in production stage # see diff --git a/jdav_web/jdav_web/views.py b/jdav_web/jdav_web/views.py index c692dbe..6eeec60 100644 --- a/jdav_web/jdav_web/views.py +++ b/jdav_web/jdav_web/views.py @@ -1,11 +1,12 @@ -from django.http import HttpResponse -from django.views.static import serve +import re + from django.conf import settings -from django.contrib.admin.views.decorators import staff_member_required from django.contrib import admin +from django.contrib.admin.views.decorators import staff_member_required +from django.http import HttpResponse from django.shortcuts import render +from django.views.static import serve from startpage.models import Link -import re def media_unprotected(request, path): @@ -15,8 +16,8 @@ def media_unprotected(request, path): # otherwise create a redirect to the internal nginx endpoint at /protected response = HttpResponse() # Content-type will be detected by nginx - del response['Content-Type'] - response['X-Accel-Redirect'] = '/protected/' + path + del response["Content-Type"] + response["X-Accel-Redirect"] = "/protected/" + path return response @@ -26,7 +27,7 @@ def media_protected(request, path): def media_access(request, path): - if re.match('^(people|images)/', path): + if re.match("^(people|images)/", path): return media_unprotected(request, path) else: return media_protected(request, path) @@ -38,11 +39,12 @@ def custom_admin_view(request): """ app_list = admin.site.get_app_list(request) context = { - 'app_list': app_list, - 'site_header': admin.site.site_header, - 'site_title': admin.site.site_title, - 'external_links': Link.objects.all() + "app_list": app_list, + "site_header": admin.site.site_header, + "site_title": admin.site.site_title, + "external_links": Link.objects.all(), } - return render(request, 'admin/index.html', context) + return render(request, "admin/index.html", context) + admin.site.index = custom_admin_view