forked from beba/foerderbarometer
Compare commits
43 Commits
4aeb330fa4
...
d1ae90b6a1
| Author | SHA1 | Date |
|---|---|---|
|
|
d1ae90b6a1 | |
|
|
d933f5a32b | |
|
|
6698d6a6f3 | |
|
|
0b9fb801bd | |
|
|
0efaa6910d | |
|
|
32f8a8f50f | |
|
|
f4698c3894 | |
|
|
0839439671 | |
|
|
295f41ff75 | |
|
|
c295f7182b | |
|
|
945550b8f6 | |
|
|
e44e0eb31c | |
|
|
52315d4378 | |
|
|
17f763ba66 | |
|
|
6306567ebd | |
|
|
165ad050ad | |
|
|
5696072604 | |
|
|
4c458c16d7 | |
|
|
60a5538033 | |
|
|
d40c53bc80 | |
|
|
e28d68516a | |
|
|
88e2c959d0 | |
|
|
61dcce3505 | |
|
|
858e8519bd | |
|
|
fe50d9b465 | |
|
|
edd0eb2205 | |
|
|
1495621ef0 | |
|
|
d3f18b0b93 | |
|
|
f0c8ca71bb | |
|
|
b5a0fbde98 | |
|
|
eaddabbcdd | |
|
|
0afabe9325 | |
|
|
d5e6a7c343 | |
|
|
eb44094639 | |
|
|
e5cea49673 | |
|
|
233151968b | |
|
|
fe8985504e | |
|
|
80d1d17ff6 | |
|
|
02ee0097a8 | |
|
|
70c88440aa | |
|
|
fa8d0ab898 | |
|
|
b9fe0c9a1f | |
|
|
e0538bbc9a |
|
|
@ -0,0 +1,23 @@
|
|||
[run]
|
||||
branch = on
|
||||
source = input
|
||||
omit =
|
||||
# ignore the tests itself
|
||||
*/test*.py
|
||||
*/tests/*.py
|
||||
|
||||
# ignore wsgi & asgi
|
||||
*/?sgi.py
|
||||
|
||||
[report]
|
||||
include =
|
||||
input/*
|
||||
exclude_lines =
|
||||
pragma: no cover
|
||||
raise NotImplementedError
|
||||
omit =
|
||||
# they are excluded in run, so
|
||||
# doesn't need to be reported
|
||||
*/test*.py
|
||||
*/tests/*.py
|
||||
*/?sgi.py
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
ENVIRONMENT = develop
|
||||
DEBUG = yes
|
||||
SECRET_KEY = not-a-secret-key
|
||||
DATABASE_ENGINE = sqlite3
|
||||
EMAIL_BACKEND = console
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
ENVIRONMENT = production
|
||||
DEBUG = no
|
||||
SECRET_KEY = <enter a secret key>
|
||||
HOST = https://foerderung.wikimedia.de
|
||||
DATABASE_ENGINE = mysql
|
||||
DATABASE_PASSWORD = <enter a database password>
|
||||
EMAIL_BACKEND = smtp
|
||||
EMAIL_HOST_USER = <enter an email host user>
|
||||
EMAIL_HOST_PASSWORD = <enter an email host password>
|
||||
OAUTH_ENABLED = yes
|
||||
OAUTH_CLIENT_NAME = <enter a client name>
|
||||
OAUTH_CLIENT_ID = <enter a client id>
|
||||
OAUTH_CLIENT_SECRET = <enter a client secret>
|
||||
|
|
@ -1,9 +1,6 @@
|
|||
# secret passwords and so
|
||||
/secrets.json
|
||||
/staticfiles
|
||||
# /foerderbarometer/settings.py
|
||||
# /foerderbarometer/*settings*
|
||||
/input/settings.py
|
||||
/nohup.out
|
||||
/logfile
|
||||
*~
|
||||
|
|
@ -93,6 +90,10 @@ target/
|
|||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# IDEA
|
||||
/*.iml
|
||||
/.idea
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
|
|
@ -139,3 +140,6 @@ dmypy.json
|
|||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# MacOS
|
||||
.DS_Store
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
stages:
|
||||
- test
|
||||
|
||||
test:
|
||||
stage: test
|
||||
image: python:3.11-bookworm
|
||||
variables:
|
||||
DJANGO_SETTINGS_MODULE: foerderbarometer.settings
|
||||
ENVIRONMENT: test
|
||||
SECRET_KEY: this-is-not-a-secret-key
|
||||
DATABASE_ENGINE: mysql
|
||||
DATABASE_HOST: mariadb
|
||||
DATABASE_USER: root
|
||||
DATABASE_PASSWORD: fdb
|
||||
OAUTH_ENABLED: no
|
||||
services:
|
||||
- name: mariadb:10.6
|
||||
variables:
|
||||
MARIADB_ROOT_PASSWORD: fdb
|
||||
tags:
|
||||
- docker
|
||||
coverage: /(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/
|
||||
before_script:
|
||||
- pip install -r requirements.txt coverage
|
||||
script:
|
||||
- coverage run manage.py test --noinput
|
||||
after_script:
|
||||
- coverage report
|
||||
51
README.md
51
README.md
|
|
@ -2,9 +2,13 @@
|
|||
|
||||
purpose: gather data from intern(WMDE) and extern(volunteers) forms to create a database ('förderdatenbank') and send emails with links for a questionary.
|
||||
|
||||
## installation and development setup
|
||||
## manual development setup
|
||||
|
||||
ln -sr foerderbarometer/settings_development.py foerderbarometer/settings.py
|
||||
cp .env.develop.example .env
|
||||
|
||||
By default a SQLite database is used for development.
|
||||
To use a MariaDB change `DATABASE_ENGINE` in .env to `mysql` and amend `DATABASE_*` variables according to your setup.
|
||||
For further information see the production setup below.
|
||||
|
||||
build the database with
|
||||
|
||||
|
|
@ -24,6 +28,25 @@ access via
|
|||
http://localhost:8000/intern/ (login required)
|
||||
http://localhost:8000/admin/ (login reqiured)
|
||||
|
||||
## docker compose development setup
|
||||
|
||||
The project comes with a `docker-compose.yml` file to run the project in a containerized environment.
|
||||
|
||||
cp .env.develop.example .env
|
||||
docker compose up
|
||||
|
||||
The setup will use a containerized MariaDB database.
|
||||
|
||||
Create your superuser account with
|
||||
|
||||
docker compose exec django python3 manage.py createsuperuser
|
||||
|
||||
You can access the application via
|
||||
|
||||
http://localhost:8000/
|
||||
http://localhost:8000/intern/ (login required)
|
||||
http://localhost:8000/admin/ (login required)
|
||||
|
||||
## additional admin functionality
|
||||
|
||||
The admin page is the standard admin page delivered by django but with two additional functionalities:
|
||||
|
|
@ -65,16 +88,26 @@ run some tests with
|
|||
|
||||
## production setup
|
||||
|
||||
ln -sr foerderbarometer/settings_production.py foerderbarometer/settings.py
|
||||
cp .env.production.example .env
|
||||
|
||||
edit /secrets.json to contain something similar to
|
||||
edit .env and fill in the missing secrets
|
||||
|
||||
{
|
||||
"DATABASE_PASSWORD": "THIS IS TOP SECRET!",
|
||||
"SECRET_KEY": "THIS IS ANOTHER SECRET!"
|
||||
}
|
||||
SECRET_KEY
|
||||
DATABASE_PASSWORD
|
||||
EMAIL_HOST_USER
|
||||
EMAIL_HOST_PASSWORD
|
||||
OAUTH_CLIENT_NAME
|
||||
OAUTH_CLIENT_ID
|
||||
OAUTH_CLIENT_SECRET
|
||||
|
||||
edit foerderbarometer/settings_production.py according to your database setup (tested with MariaDB 10.0.36)
|
||||
amend database variables to .env according to your database setup (tested with MariaDB 10.0.36), e.g.
|
||||
|
||||
DATABASE_NAME
|
||||
DATABASE_USER
|
||||
DATABASE_HOST
|
||||
DATABASE_PORT
|
||||
|
||||
for a full set of all possible env vars have a look at foerderbarometer/settings.py
|
||||
|
||||
run the following commands:
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
services:
|
||||
django:
|
||||
image: python:3-alpine
|
||||
working_dir: /app
|
||||
volumes:
|
||||
- .:/app
|
||||
environment:
|
||||
PYTHONUNBUFFERED: 1
|
||||
DATABASE_ENGINE: mysql
|
||||
DATABASE_HOST: mariadb
|
||||
DATABASE_USER: fdb
|
||||
DATABASE_PASSWORD: fdb
|
||||
ports:
|
||||
- 8000:8000
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
apk update
|
||||
apk add gcc
|
||||
apk add mariadb-dev
|
||||
apk add musl-dev
|
||||
pip install -Ur requirements.txt
|
||||
python manage.py migrate
|
||||
python manage.py runserver 0.0.0.0:8000
|
||||
|
||||
mariadb:
|
||||
image: mariadb
|
||||
environment:
|
||||
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: yes
|
||||
MARIADB_DATABASE: fdb
|
||||
MARIADB_USER: fdb
|
||||
MARIADB_PASSWORD: fdb
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
import os
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from input.utils.settings import env, password_validators
|
||||
|
||||
BASE_DIR = Path(__file__).parents[1]
|
||||
|
||||
load_dotenv(BASE_DIR / '.env')
|
||||
|
||||
DEBUG = env('DEBUG', False)
|
||||
|
||||
SECRET_KEY = env('SECRET_KEY')
|
||||
|
||||
ALLOWED_HOSTS = ['*']
|
||||
|
||||
HOST = env('HOST', 'http://localhost:8000')
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'input.apps.InputConfig',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'formtools',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'whitenoise.middleware.WhiteNoiseMiddleware',
|
||||
'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',
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'foerderbarometer.urls'
|
||||
|
||||
DJANGO_TEMPLATES = {
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [],
|
||||
'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',
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
TEMPLATES = [DJANGO_TEMPLATES]
|
||||
|
||||
WSGI_APPLICATION = 'foerderbarometer.wsgi.application'
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
|
||||
|
||||
DATABASE_ENGINE = env('DATABASE_ENGINE', 'mysql')
|
||||
|
||||
DATABASE_SQLITE = {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': BASE_DIR / 'db.sqlite3',
|
||||
}
|
||||
|
||||
DATABASE_MYSQL = {
|
||||
'ENGINE': 'django.db.backends.mysql',
|
||||
'NAME': env('DATABASE_NAME', 'fdb'),
|
||||
'USER': env('DATABASE_USER', 'fdb'),
|
||||
'PASSWORD': env('DATABASE_PASSWORD'),
|
||||
'HOST': env('DATABASE_HOST', 'localhost'),
|
||||
'PORT': env('DATABASE_PORT', 3306),
|
||||
'OPTIONS': {
|
||||
'charset' : 'utf8',
|
||||
'use_unicode' : True,
|
||||
'init_command': 'SET '
|
||||
'storage_engine=INNODB,'
|
||||
'character_set_connection=utf8,'
|
||||
'collation_connection=utf8_bin'
|
||||
},
|
||||
'TEST_CHARSET': 'utf8',
|
||||
'TEST_COLLATION': 'utf8_general_ci',
|
||||
}
|
||||
|
||||
if DATABASE_ENGINE == 'mysql':
|
||||
DATABASE_DEFAULT = DATABASE_MYSQL
|
||||
else:
|
||||
DATABASE_DEFAULT = DATABASE_SQLITE
|
||||
|
||||
DATABASES = {
|
||||
'default': DATABASE_DEFAULT,
|
||||
}
|
||||
|
||||
EMAIL_BACKEND = env('EMAIL_BACKEND', 'console')
|
||||
|
||||
if EMAIL_BACKEND == 'smtp':
|
||||
EMAIL_HOST = env('EMAIL_HOST', 'email.wikimedia.de')
|
||||
EMAIL_PORT = env('EMAIL_PORT', 587)
|
||||
EMAIL_USE_TLS = env('EMAIL_USE_TLS', True)
|
||||
EMAIL_HOST_USER = env('EMAIL_HOST_USER')
|
||||
EMAIL_HOST_PASSWORD = env('EMAIL_HOST_PASSWORD')
|
||||
|
||||
EMAIL_BACKEND = f'django.core.mail.backends.{EMAIL_BACKEND}.EmailBackend'
|
||||
EMAIL_URL_PREFIX = env('EMAIL_URL_PREFIX', HOST)
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = password_validators(
|
||||
'UserAttributeSimilarityValidator',
|
||||
'MinimumLengthValidator',
|
||||
'CommonPasswordValidator',
|
||||
'NumericPasswordValidator',
|
||||
)
|
||||
|
||||
USE_I18N = True
|
||||
USE_L10N = True
|
||||
LANGUAGE_CODE = env('LANGUAGE_CODE', 'en-us')
|
||||
|
||||
USE_TZ = True
|
||||
TIME_ZONE = env('TIME_ZONE', 'UTC')
|
||||
|
||||
STATIC_ROOT = BASE_DIR / 'staticfiles'
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
FORM_RENDERER = 'input.forms.TableFormRenderer'
|
||||
|
||||
if OAUTH_ENABLED := env('OAUTH_ENABLED', not DEBUG):
|
||||
MIDDLEWARE += ['input.middleware.oauth.OAuthMiddleware']
|
||||
|
||||
OAUTH_CLIENT_NAME = env('OAUTH_CLIENT_NAME')
|
||||
|
||||
OAUTH_CLIENT = {
|
||||
'client_id': env('OAUTH_CLIENT_ID'),
|
||||
'client_secret': env('OAUTH_CLIENT_SECRET'),
|
||||
'access_token_url': 'https://meta.wikimedia.org/w/rest.php/oauth2/access_token',
|
||||
'authorize_url': 'https://meta.wikimedia.org/w/rest.php/oauth2/authorize',
|
||||
'api_base_url': 'https://meta.wikimedia.org/w/rest.php/oauth2/resource',
|
||||
'redirect_uri': env('OAUTH_REDIRECT_URI', f'{HOST}/oauth/callback'),
|
||||
'client_kwargs': {
|
||||
'scope': 'basic',
|
||||
'token_placement': 'header'
|
||||
},
|
||||
'userinfo_endpoint': 'resource/profile',
|
||||
}
|
||||
|
||||
OAUTH_URL_WHITELISTS = ['/admin']
|
||||
|
||||
OAUTH_COOKIE_SESSION_ID = 'sso_session_id'
|
||||
|
||||
IF_EMAIL = env('IF_EMAIL', 'community@wikimedia.de')
|
||||
|
||||
SURVEY_EMAIL = env('SURVEY_EMAIL', 'sandro.halank@wikimedia.de')
|
||||
SURVEY_PREFIX = env('SURVEY_PREFIX', 'https://wikimedia.sslsurvey.de/Foerderbarometer/?')
|
||||
|
||||
DATAPROTECTION = 'https://www.wikimedia.de/datenschutz/#datenerfassung'
|
||||
FOERDERRICHTLINIEN = 'https://de.wikipedia.org/wiki/Wikipedia:Wikimedia_Deutschland/Richtlinie_zur_Förderung_der_Communitys'
|
||||
|
||||
NUTZUNGSBEDINGUNGEN = 'static/input/nutzungsbedingungen.html'
|
||||
NUTZUNGSBEDINGUNGEN_EMAIL_SERVICE = 'static/input/nutzungsbedingungen-mail.pdf'
|
||||
NUTZUNGSBEDINGUNGEN_MAILINGLISTEN = 'static/input/nutzungsbedingungen-mailinglisten.pdf'
|
||||
NUTZUNGSBEDINGUNGEN_LITERATURSTIPENDIUM = 'static/input/nutzungsbedingungen-literaturstipendium.pdf'
|
||||
NUTZUNGSBEDINGUNGEN_OTRS = 'static/input/2025_Nutzungsvereinbarung_OTRS.docx.pdf'
|
||||
NUTZUNGSBEDINGUNGEN_VISITENKARTEN = 'static/input/nutzungsbedingungen-visitenkarten.pdf'
|
||||
|
|
@ -1,203 +0,0 @@
|
|||
"""
|
||||
Django settings for foerderbarometer project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 3.1.1.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/3.1/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/3.1/ref/settings/
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
||||
# prefix for urls in mails
|
||||
URLPREFIX = 'https://fdb-devel.wikimedia.de'
|
||||
|
||||
|
||||
# mails in development go to stdout
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
||||
|
||||
CSRF_TRUSTED_ORIGINS = ['https://fdb-devel.wikimedia.de']
|
||||
|
||||
# EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||
|
||||
EMAIL_HOST = 'xemail.wikimedia.de'
|
||||
EMAIL_PORT = '587'
|
||||
EMAIL_USE_TLS = True
|
||||
#EMAIL_HOST_USER = get_secret('EMAIL_HOST_USER')
|
||||
#EMAIL_HOST_PASSWORD = get_secret('EMAIL_HOST_PASSWORD')
|
||||
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
# get secrets
|
||||
with open(os.path.join(BASE_DIR, 'secrets.json')) as secrets_file:
|
||||
secrets = json.load(secrets_file)
|
||||
|
||||
def get_secret(setting, secrets=secrets):
|
||||
"""Get secret setting or fail with ImproperlyConfigured"""
|
||||
try:
|
||||
return secrets[setting]
|
||||
except KeyError:
|
||||
raise ImproperlyConfigured("Set the {} setting".format(setting))
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = get_secret('SECRET_KEY')
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
STATIC_ROOT = BASE_DIR / 'staticfiles'
|
||||
|
||||
ALLOWED_HOSTS = ['*']
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'input.apps.InputConfig',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'formtools',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'whitenoise.middleware.WhiteNoiseMiddleware',
|
||||
'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',
|
||||
'input.middleware.oauth.OAuthMiddleware'
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'foerderbarometer.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [],
|
||||
'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 = 'foerderbarometer.wsgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.mysql',
|
||||
'NAME': 'fdbdevel',
|
||||
'USER': 'fdbdevel',
|
||||
'PASSWORD': get_secret('DATABASE_PASSWORD'),
|
||||
'HOST': '10.0.6.224', # Or an IP Address that your database is hosted on
|
||||
# 'PORT': '3306',
|
||||
#optional:
|
||||
'OPTIONS': {
|
||||
'charset' : 'utf8',
|
||||
'use_unicode' : True,
|
||||
'init_command': 'SET '
|
||||
'storage_engine=INNODB,'
|
||||
'character_set_connection=utf8,'
|
||||
'collation_connection=utf8_bin'
|
||||
#'sql_mode=STRICT_TRANS_TABLES,' # see note below
|
||||
#'SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED',
|
||||
},
|
||||
'TEST_CHARSET': 'utf8',
|
||||
'TEST_COLLATION': 'utf8_general_ci',
|
||||
}
|
||||
}
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/3.1/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/3.1/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
# needed since django 3.2
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
|
||||
|
||||
|
||||
# OAuth Settings
|
||||
OAUTH_URL_WHITELISTS = ['/admin']
|
||||
|
||||
OAUTH_CLIENT_NAME = '<name-of-the-configured-wikimedia-app>'
|
||||
OAUTH_CLIENT_NAME = get_secret('OAUTH_CLIENT_NAME')
|
||||
|
||||
|
||||
OAUTH_CLIENT = {
|
||||
'client_id': get_secret('OAUTH_CLIENT_ID'),
|
||||
'client_secret': get_secret('OAUTH_CLIENT_SECRET'),
|
||||
'access_token_url': 'https://meta.wikimedia.org/w/rest.php/oauth2/access_token',
|
||||
'authorize_url': 'https://meta.wikimedia.org/w/rest.php/oauth2/authorize',
|
||||
'api_base_url': 'https://meta.wikimedia.org/w/rest.php/oauth2/resource',
|
||||
'redirect_uri': 'https://fdb-devel.wikimedia.de/oauth/callback',
|
||||
'client_kwargs': {
|
||||
'scope': 'basic',
|
||||
'token_placement': 'header'
|
||||
},
|
||||
'userinfo_endpoint': 'resource/profile',
|
||||
}
|
||||
|
||||
OAUTH_COOKIE_SESSION_ID = 'sso_session_id'
|
||||
|
|
@ -1,151 +0,0 @@
|
|||
"""
|
||||
Django settings for foerderbarometer project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 3.1.1.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/3.1/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/3.1/ref/settings/
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
||||
# prefix for urls in mails
|
||||
URLPREFIX = 'http://localhost:8000'
|
||||
|
||||
# mails in development go to stdout
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
# get secrets
|
||||
with open(os.path.join(BASE_DIR, 'secrets.json')) as secrets_file:
|
||||
secrets = json.load(secrets_file)
|
||||
|
||||
def get_secret(setting, secrets=secrets):
|
||||
"""Get secret setting or fail with ImproperlyConfigured"""
|
||||
try:
|
||||
return secrets[setting]
|
||||
except KeyError:
|
||||
raise ImproperlyConfigured("Set the {} setting".format(setting))
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = '*&7p9#_n$@^%0z49s+7jpy@+j1rw_hqh05knyd6y2*!0)r&b6h'
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
STATIC_ROOT = BASE_DIR / 'staticfiles'
|
||||
|
||||
ALLOWED_HOSTS = ['*']
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'input.apps.InputConfig',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'formtools',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'whitenoise.middleware.WhiteNoiseMiddleware',
|
||||
'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',
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'foerderbarometer.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [],
|
||||
'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 = 'foerderbarometer.wsgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': BASE_DIR / 'db.sqlite3',
|
||||
'PASSWORD': get_secret('DATABASE_PASSWORD')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/3.1/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/3.1/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
# needed since django 3.2
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
|
||||
|
|
@ -1,158 +0,0 @@
|
|||
"""
|
||||
Django settings for foerderbarometer project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 3.1.1.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/3.1/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/3.1/ref/settings/
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
||||
# prefix for urls in mails
|
||||
URLPREFIX = 'http://localhost:8000'
|
||||
|
||||
# mails in development go to stdout
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||
|
||||
EMAIL_HOST = 'email.wikimedia.de'
|
||||
EMAIL_PORT = '587'
|
||||
EMAIL_USE_TLS = True
|
||||
EMAIL_HOST_USER = '636ea784dd6ec43'
|
||||
EMAIL_HOST_PASSWORD = 'wsgqp4ZaVRZZEpRJ'
|
||||
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
# get secrets
|
||||
with open(os.path.join(BASE_DIR, 'secrets.json')) as secrets_file:
|
||||
secrets = json.load(secrets_file)
|
||||
|
||||
def get_secret(setting, secrets=secrets):
|
||||
"""Get secret setting or fail with ImproperlyConfigured"""
|
||||
try:
|
||||
return secrets[setting]
|
||||
except KeyError:
|
||||
raise ImproperlyConfigured("Set the {} setting".format(setting))
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = '*&7p9#_n$@^%0z49s+7jpy@+j1rw_hqh05knyd6y2*!0)r&b6h'
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
STATIC_ROOT = BASE_DIR / 'staticfiles'
|
||||
|
||||
ALLOWED_HOSTS = ['*']
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'input.apps.InputConfig',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'formtools',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'whitenoise.middleware.WhiteNoiseMiddleware',
|
||||
'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',
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'foerderbarometer.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [],
|
||||
'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 = 'foerderbarometer.wsgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': BASE_DIR / 'db.sqlite3',
|
||||
'PASSWORD': get_secret('DATABASE_PASSWORD')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/3.1/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/3.1/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
# needed since django 3.2
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
|
||||
|
|
@ -1,175 +0,0 @@
|
|||
"""
|
||||
Django settings for foerderbarometer project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 3.1.1.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/3.1/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/3.1/ref/settings/
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
||||
# prefix for urls in mails
|
||||
URLPREFIX = 'http://localhost:8000'
|
||||
|
||||
# mails in development go to stdout
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
# get secrets
|
||||
with open(os.path.join(BASE_DIR, 'secrets.json')) as secrets_file:
|
||||
secrets = json.load(secrets_file)
|
||||
|
||||
def get_secret(setting, secrets=secrets):
|
||||
"""Get secret setting or fail with ImproperlyConfigured"""
|
||||
try:
|
||||
return secrets[setting]
|
||||
except KeyError:
|
||||
raise ImproperlyConfigured("Set the {} setting".format(setting))
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = '*&7p9#_n$@^%0z49s+7jpy@+j1rw_hqh05knyd6y2*!0)r&b6h'
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
STATIC_ROOT = BASE_DIR / 'staticfiles'
|
||||
|
||||
ALLOWED_HOSTS = ['*']
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'input.apps.InputConfig',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'formtools',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'whitenoise.middleware.WhiteNoiseMiddleware',
|
||||
'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',
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'foerderbarometer.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [],
|
||||
'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 = 'foerderbarometer.wsgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases
|
||||
#
|
||||
# DATABASES = {
|
||||
# 'default': {
|
||||
# 'ENGINE': 'django.db.backends.sqlite3',
|
||||
# 'NAME': BASE_DIR / 'db.sqlite3',
|
||||
# 'PASSWORD': get_secret('DATABASE_PASSWORD')
|
||||
# }
|
||||
# }
|
||||
#
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.mysql',
|
||||
'NAME': 'fdb',
|
||||
'USER': 'fdb',
|
||||
'PASSWORD': get_secret('DATABASE_PASSWORD'),
|
||||
'HOST': 'localhost', # Or an IP Address that your database is hosted on
|
||||
# 'PORT': '3306',
|
||||
#optional:
|
||||
'OPTIONS': {
|
||||
'charset' : 'utf8',
|
||||
'use_unicode' : True,
|
||||
'init_command': 'SET '
|
||||
'storage_engine=INNODB,'
|
||||
'character_set_connection=utf8,'
|
||||
'collation_connection=utf8_bin'
|
||||
#'sql_mode=STRICT_TRANS_TABLES,' # see note below
|
||||
#'SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED',
|
||||
},
|
||||
'TEST_CHARSET': 'utf8',
|
||||
'TEST_COLLATION': 'utf8_general_ci',
|
||||
}
|
||||
}
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/3.1/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/3.1/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
# needed since django 3.2
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
|
||||
|
|
@ -1,171 +0,0 @@
|
|||
"""
|
||||
Django settings for foerderbarometer project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 3.1.1.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/3.1/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/3.1/ref/settings/
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
||||
# mails in development go to stdout
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||
|
||||
EMAIL_HOST = 'email.wikimedia.de'
|
||||
EMAIL_PORT = '587'
|
||||
EMAIL_USE_TLS = True
|
||||
EMAIL_HOST_USER = '636ea784dd6ec43'
|
||||
EMAIL_HOST_PASSWORD = 'wsgqp4ZaVRZZEpRJ'
|
||||
|
||||
# prefix for urls in mails
|
||||
URLPREFIX = 'http://foerderung.wikimedia.de'
|
||||
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
# get secrets
|
||||
with open(os.path.join(BASE_DIR, 'secrets.json')) as secrets_file:
|
||||
secrets = json.load(secrets_file)
|
||||
|
||||
def get_secret(setting, secrets=secrets):
|
||||
"""Get secret setting or fail with ImproperlyConfigured"""
|
||||
try:
|
||||
return secrets[setting]
|
||||
except KeyError:
|
||||
raise ImproperlyConfigured("Set the {} setting".format(setting))
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = get_secret('SECRET_KEY')
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = False
|
||||
|
||||
STATIC_ROOT = BASE_DIR / 'staticfiles'
|
||||
|
||||
ALLOWED_HOSTS = ['*']
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'input.apps.InputConfig',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'formtools',
|
||||
]
|
||||
|
||||
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'whitenoise.middleware.WhiteNoiseMiddleware',
|
||||
'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',
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'foerderbarometer.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [],
|
||||
'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 = 'foerderbarometer.wsgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.mysql',
|
||||
'NAME': 'fdbdevel',
|
||||
'USER': 'fdbdevel',
|
||||
'PASSWORD': get_secret('DATABASE_PASSWORD'),
|
||||
'HOST': '10.0.6.7', # Or an IP Address that your database is hosted on
|
||||
# 'PORT': '3306',
|
||||
#optional:
|
||||
'OPTIONS': {
|
||||
'charset' : 'utf8',
|
||||
'use_unicode' : True,
|
||||
'init_command': 'SET '
|
||||
'storage_engine=INNODB,'
|
||||
'character_set_connection=utf8,'
|
||||
'collation_connection=utf8_bin'
|
||||
#'sql_mode=STRICT_TRANS_TABLES,' # see note below
|
||||
#'SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED',
|
||||
},
|
||||
'TEST_CHARSET': 'utf8',
|
||||
'TEST_COLLATION': 'utf8_general_ci',
|
||||
}
|
||||
}
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/3.1/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/3.1/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
|
@ -3,8 +3,20 @@ import csv
|
|||
from django.contrib import admin
|
||||
from django.http import HttpResponse
|
||||
|
||||
from .models import Account, Project, HonoraryCertificate, Library, IFG, Travel,\
|
||||
Email, BusinessCard, List, Literature
|
||||
from .models import (
|
||||
Account,
|
||||
Project,
|
||||
HonoraryCertificate,
|
||||
Library,
|
||||
ELiterature,
|
||||
Software,
|
||||
IFG,
|
||||
Travel,
|
||||
Email,
|
||||
BusinessCard,
|
||||
List,
|
||||
Literature,
|
||||
)
|
||||
|
||||
|
||||
def export_as_csv(self, request, queryset):
|
||||
|
|
@ -45,7 +57,7 @@ class ProjectAdmin(admin.ModelAdmin):
|
|||
class BusinessCardAdmin(admin.ModelAdmin):
|
||||
save_as = True
|
||||
search_fields = ('realname', 'service_id', 'granted', 'granted_date', 'project')
|
||||
list_display = ('realname', 'service_id', 'granted', 'granted_date', 'project')
|
||||
list_display = ('realname', 'service_id', 'granted', 'granted_date', 'project', 'terms_accepted')
|
||||
list_display_links = ('realname', 'service_id')
|
||||
# action = ['export_as_csv']
|
||||
date_hierarchy = 'granted_date'
|
||||
|
|
@ -57,7 +69,7 @@ class BusinessCardAdmin(admin.ModelAdmin):
|
|||
class LiteratureAdmin(admin.ModelAdmin):
|
||||
save_as = True
|
||||
search_fields = ('realname', 'service_id', 'granted', 'granted_date')
|
||||
list_display = ('realname', 'service_id', 'granted', 'granted_date')
|
||||
list_display = ('realname', 'service_id', 'granted', 'granted_date', 'terms_accepted')
|
||||
list_display_links = ('realname', 'service_id')
|
||||
date_hierarchy = 'granted_date'
|
||||
readonly_fields = ['service_id']
|
||||
|
|
@ -78,7 +90,8 @@ class HonoraryCertificateAdmin(admin.ModelAdmin):
|
|||
class Media:
|
||||
js = ('dropdown/js/otrs_link.js',)
|
||||
|
||||
@admin.register(Library)
|
||||
|
||||
@admin.register(Library, ELiterature, Software)
|
||||
class LibraryAdmin(admin.ModelAdmin):
|
||||
save_as = True
|
||||
search_fields = ('realname', 'service_id', 'granted', 'granted_date')
|
||||
|
|
@ -86,6 +99,21 @@ class LibraryAdmin(admin.ModelAdmin):
|
|||
list_display_links = ('realname', 'service_id')
|
||||
date_hierarchy = 'granted_date'
|
||||
readonly_fields = ['service_id']
|
||||
exclude = ['type']
|
||||
|
||||
def get_queryset(self, request):
|
||||
return super().get_queryset(request).filter(type=self.model.TYPE)
|
||||
|
||||
def formfield_for_dbfield(self, db_field, request, **kwargs):
|
||||
if db_field.name == 'library':
|
||||
kwargs['label'] = self.model.LIBRARY_LABEL
|
||||
kwargs['help_text'] = self.model.LIBRARY_HELP_TEXT
|
||||
|
||||
elif db_field.name == 'duration':
|
||||
kwargs['help_text'] = self.model.DURATION_HELP_TEXT
|
||||
|
||||
return super().formfield_for_dbfield(db_field, request, **kwargs)
|
||||
|
||||
|
||||
@admin.register(IFG)
|
||||
class IFGAdmin(admin.ModelAdmin):
|
||||
|
|
@ -103,9 +131,8 @@ class TravelAdmin(admin.ModelAdmin):
|
|||
list_display = ('realname', 'service_id', 'granted', 'granted_date', 'project_end', 'project', 'project_end_quartal')
|
||||
list_display_links = ('realname', 'project')
|
||||
date_hierarchy = 'project_end'
|
||||
readonly_fields = ('project_end_quartal', 'project_end')
|
||||
autocomplete_fields = ['project']
|
||||
readonly_fields = ['service_id']
|
||||
readonly_fields = ['service_id', 'project_end', 'project_end_quartal']
|
||||
|
||||
class Media:
|
||||
js = ('dropdown/js/otrs_link.js',)
|
||||
|
|
@ -115,7 +142,7 @@ class TravelAdmin(admin.ModelAdmin):
|
|||
class EmailAdmin(admin.ModelAdmin):
|
||||
save_as = True
|
||||
search_fields = ('realname', 'service_id', 'granted', 'granted_date')
|
||||
list_display = ('realname', 'service_id', 'granted', 'granted_date')
|
||||
list_display = ('realname', 'service_id', 'granted', 'granted_date', 'terms_accepted')
|
||||
list_display_links = ('realname', 'service_id')
|
||||
date_hierarchy = 'granted_date'
|
||||
radio_fields = {'adult': admin.VERTICAL}
|
||||
|
|
@ -128,7 +155,7 @@ class EmailAdmin(admin.ModelAdmin):
|
|||
class ListAdmin(admin.ModelAdmin):
|
||||
save_as = True
|
||||
search_fields = ('realname', 'service_id', 'granted', 'granted_date')
|
||||
list_display = ('realname', 'service_id', 'granted', 'granted_date')
|
||||
list_display = ('realname', 'service_id', 'granted', 'granted_date', 'terms_accepted')
|
||||
list_display_links = ('realname', 'service_id')
|
||||
date_hierarchy = 'granted_date'
|
||||
readonly_fields = ['service_id']
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
"""
|
||||
ASGI config for oauth_demo project.
|
||||
|
||||
It exposes the ASGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.asgi import get_asgi_application
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'oauth_demo.settings')
|
||||
|
||||
application = get_asgi_application()
|
||||
|
|
@ -1,15 +1,30 @@
|
|||
from django.db import models
|
||||
from django.forms import ModelForm, DateField, ChoiceField, RadioSelect, BooleanField
|
||||
from django.conf import settings
|
||||
from django.forms import ModelForm, ChoiceField, RadioSelect, BooleanField
|
||||
from django.contrib.admin.widgets import AdminDateWidget
|
||||
from django.forms.renderers import DjangoTemplates
|
||||
from django.utils.html import format_html
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
from .models import Project, Volunteer, ConcreteVolunteer, Extern, ConcreteExtern, IFG, Library, TYPE_CHOICES,\
|
||||
HonoraryCertificate, Travel, Email, Literature, List,\
|
||||
BusinessCard
|
||||
from .settings import DATAPROTECTION, FOERDERRICHTLINIEN, NUTZUNGSBEDINGUNGEN
|
||||
from .models import (
|
||||
TYPE_CHOICES,
|
||||
Project,
|
||||
ConcreteVolunteer,
|
||||
ConcreteExtern,
|
||||
IFG,
|
||||
Library,
|
||||
ELiterature,
|
||||
Software,
|
||||
HonoraryCertificate,
|
||||
Travel,
|
||||
Email,
|
||||
Literature,
|
||||
List,
|
||||
BusinessCard,
|
||||
)
|
||||
|
||||
from . import settings
|
||||
|
||||
class TableFormRenderer(DjangoTemplates):
|
||||
form_template_name = 'django/forms/table.html'
|
||||
|
||||
|
||||
class FdbForm(ModelForm):
|
||||
|
|
@ -39,7 +54,7 @@ class ExternForm(FdbForm):
|
|||
|
||||
check = BooleanField(required=True,
|
||||
label=format_html("Ich stimme den <a href='{}' target='_blank' rel='noopener'>Datenschutzbestimmungen</a> und der<br> <a href='{}' target='_blank' rel='noopener'>Richtlinie zur Förderung der Communitys</a> zu",
|
||||
DATAPROTECTION, FOERDERRICHTLINIEN))
|
||||
settings.DATAPROTECTION, settings.FOERDERRICHTLINIEN))
|
||||
|
||||
class Meta:
|
||||
model = ConcreteExtern
|
||||
|
|
@ -59,8 +74,8 @@ class InternForm(FdbForm):
|
|||
exclude = ('granted', 'granted_date', 'survey_mail_send', 'survey_mail_date', 'mail_state')
|
||||
|
||||
|
||||
HOTEL_CHOICES = {'TRUE': format_html('Hotelzimmer benötigt'),
|
||||
'FALSE': format_html('Kein Hotelzimmer benötigt')
|
||||
HOTEL_CHOICES = {'TRUE': mark_safe('Hotelzimmer benötigt'),
|
||||
'FALSE': mark_safe('Kein Hotelzimmer benötigt')
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -91,6 +106,7 @@ class TravelForm(FdbForm):
|
|||
'all': ('css/dateFieldNoNowShortcutInTravels.css',)
|
||||
}
|
||||
|
||||
|
||||
class LibraryForm(FdbForm):
|
||||
|
||||
class Meta:
|
||||
|
|
@ -98,6 +114,26 @@ class LibraryForm(FdbForm):
|
|||
fields = ['cost', 'library', 'duration', 'notes', 'survey_mail_send']
|
||||
exclude = ['intern_notes', 'survey_mail_send', 'mail_state']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.fields['library'].label = self._meta.model.LIBRARY_LABEL
|
||||
self.fields['library'].help_text = self._meta.model.LIBRARY_HELP_TEXT
|
||||
self.fields['duration'].help_text = self._meta.model.DURATION_HELP_TEXT
|
||||
|
||||
|
||||
class ELiteratureForm(LibraryForm):
|
||||
|
||||
class Meta(LibraryForm.Meta):
|
||||
model = ELiterature
|
||||
|
||||
|
||||
class SoftwareForm(LibraryForm):
|
||||
|
||||
class Meta(LibraryForm.Meta):
|
||||
model = Software
|
||||
|
||||
|
||||
class HonoraryCertificateForm(FdbForm):
|
||||
|
||||
class Meta:
|
||||
|
|
@ -116,26 +152,20 @@ class IFGForm(FdbForm):
|
|||
|
||||
|
||||
class CheckForm(FdbForm):
|
||||
termstoaccept = NUTZUNGSBEDINGUNGEN
|
||||
termstoaccept = settings.NUTZUNGSBEDINGUNGEN
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['check'] = BooleanField(
|
||||
required=True,
|
||||
label=format_html(
|
||||
|
||||
# Check if the model field 'terms_accepted' is present
|
||||
if 'terms_accepted' in self.fields:
|
||||
# Make the field required (HTML5 validation)
|
||||
self.fields['terms_accepted'].required = True
|
||||
# Set custom label with link to terms
|
||||
self.fields['terms_accepted'].label = format_html(
|
||||
"Ich stimme den <a href='{}'>Nutzungsbedingungen</a> zu",
|
||||
self.termstoaccept
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
||||
"""Baseclass for all classes which need a check for Nutzungsbedingungen"""
|
||||
# def __init__(self, *args, **kwargs):
|
||||
# check = BooleanField(required=True,
|
||||
# label=format_html("Ich stimme den <a href='{}'>Nutzungsbedingungen</a> zu",
|
||||
# termstoaccept))
|
||||
# NUTZUNGSBEDINGUNGEN))
|
||||
|
||||
|
||||
class LiteratureForm(CheckForm):
|
||||
|
|
@ -146,13 +176,13 @@ class LiteratureForm(CheckForm):
|
|||
self.fields['selfbuy_give_data'].required = True
|
||||
class Meta:
|
||||
model = Literature
|
||||
fields = ['cost', 'info', 'source', 'notes', 'selfbuy', 'selfbuy_data', 'selfbuy_give_data']
|
||||
fields = ['cost', 'info', 'source', 'notes', 'selfbuy', 'selfbuy_data', 'selfbuy_give_data', 'terms_accepted']
|
||||
exclude = ['intern_notes', 'survey_mail_send', 'mail_state']
|
||||
class Media:
|
||||
js = ('dropdown/js/literature.js',)
|
||||
|
||||
ADULT_CHOICES = {'TRUE': format_html('Ich bin volljährig.'),
|
||||
'FALSE': format_html('Ich bin noch nicht volljährig.')
|
||||
ADULT_CHOICES = {'TRUE': mark_safe('Ich bin volljährig.'),
|
||||
'FALSE': mark_safe('Ich bin noch nicht volljährig.')
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -173,7 +203,7 @@ class EmailForm(CheckForm):
|
|||
# TODO: add some javascript to show/hide other-field
|
||||
class Meta:
|
||||
model = Email
|
||||
fields = ['domain', 'address', 'other', 'adult']
|
||||
fields = ['domain', 'address', 'other', 'adult', 'terms_accepted']
|
||||
exclude = ['intern_notes', 'survey_mail_send', 'mail_state']
|
||||
class Media:
|
||||
js = ('dropdown/js/mail.js',)
|
||||
|
|
@ -191,7 +221,7 @@ class BusinessCardForm(CheckForm):
|
|||
class Meta:
|
||||
model = BusinessCard
|
||||
exclude = ['intern_notes', 'survey_mail_send', 'mail_state']
|
||||
fields = ['project', 'data', 'variant', 'url_of_pic', 'send_data_to_print', 'sent_to']
|
||||
fields = ['project', 'data', 'variant', 'url_of_pic', 'send_data_to_print', 'sent_to', 'terms_accepted']
|
||||
class Media:
|
||||
js = ('dropdown/js/businessCard.js',)
|
||||
|
||||
|
|
@ -200,6 +230,5 @@ class ListForm(CheckForm):
|
|||
termstoaccept = settings.NUTZUNGSBEDINGUNGEN_MAILINGLISTEN
|
||||
class Meta:
|
||||
model = List
|
||||
fields = ['domain', 'address']
|
||||
fields = ['domain', 'address', 'terms_accepted']
|
||||
exclude = ['intern_notes', 'survey_mail_send','mail_state']
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,16 @@
|
|||
from datetime import date, timedelta
|
||||
import sys
|
||||
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.template.loader import get_template
|
||||
from django.core.mail import send_mail, BadHeaderError, EmailMessage
|
||||
from django.core.mail import BadHeaderError
|
||||
from django.core.mail import EmailMultiAlternatives
|
||||
from django.conf import settings
|
||||
|
||||
from input.models import Project, Library, HonoraryCertificate, Travel, Email,\
|
||||
BusinessCard, List, IFG, Literature
|
||||
from input.settings import IF_EMAIL, SURVEYPREFIX, SURVEY_EMAIL
|
||||
|
||||
class Command(BaseCommand):
|
||||
''' mails will be send here:
|
||||
''' mails will be sent here:
|
||||
|
||||
- two weeks after confirmation of support for volunteer (/extern) send link
|
||||
with surveylink
|
||||
|
|
@ -34,14 +32,14 @@ class Command(BaseCommand):
|
|||
'type': type,
|
||||
'name': name,
|
||||
'pid': pid,
|
||||
'SURVEYPREFIX': SURVEYPREFIX, }
|
||||
'SURVEY_PREFIX': settings.SURVEY_PREFIX, }
|
||||
txt_mail_template = get_template('input/survey_mail.txt')
|
||||
html_mail_template = get_template('input/survey_mail.html')
|
||||
try:
|
||||
subject, from_email, to = 'Dein Feedback zur Förderung durch Wikimedia Deutschland', IF_EMAIL, email
|
||||
subject, from_email, to = 'Dein Feedback zur Förderung durch Wikimedia Deutschland', settings.IF_EMAIL, email
|
||||
text_content = txt_mail_template.render(context)
|
||||
html_content = html_mail_template.render(context)
|
||||
msg = EmailMultiAlternatives(subject, text_content, from_email, [to], bcc=[SURVEY_EMAIL])
|
||||
msg = EmailMultiAlternatives(subject, text_content, from_email, [to], bcc=[settings.SURVEY_EMAIL])
|
||||
msg.attach_alternative(html_content, "text/html")
|
||||
msg.send()
|
||||
#print('survey mail would have been send')
|
||||
|
|
@ -53,7 +51,7 @@ class Command(BaseCommand):
|
|||
# bcc=[SURVEY_EMAIL])
|
||||
#survey_mail.send(fail_silently=False)
|
||||
except BadHeaderError:
|
||||
return HttpResponse('Invalid header found.')
|
||||
return HttpResponse('Invalid header found.') # FIXME HttpResponse???
|
||||
|
||||
print(f'send surveylinkemail to {email}...')
|
||||
|
||||
|
|
@ -77,10 +75,10 @@ class Command(BaseCommand):
|
|||
|
||||
for project in old:
|
||||
context = {'project': project}
|
||||
context['URLPREFIX'] = settings.URLPREFIX
|
||||
context['URL_PREFIX'] = settings.EMAIL_URL_PREFIX
|
||||
|
||||
try:
|
||||
subject, from_email, to = 'Projektende erreicht', IF_EMAIL, IF_EMAIL
|
||||
subject, from_email, to = 'Projektende erreicht', settings.IF_EMAIL, settings.IF_EMAIL
|
||||
text_content = txt_mail_template.render(context)
|
||||
html_content = html_mail_template.render(context)
|
||||
msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
|
||||
|
|
@ -120,11 +118,11 @@ class Command(BaseCommand):
|
|||
|
||||
for project in approved_end:
|
||||
context = {'project': project}
|
||||
context['URLPREFIX'] = settings.URLPREFIX
|
||||
context['URL_PREFIX'] = settings.EMAIL_URL_PREFIX
|
||||
|
||||
|
||||
try:
|
||||
subject, from_email, to = 'Projektende erreicht', IF_EMAIL, project.email
|
||||
subject, from_email, to = 'Projektende erreicht', settings.IF_EMAIL, project.email
|
||||
text_content = txt_mail_template.render(context)
|
||||
html_content = html_mail_template.render(context)
|
||||
msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
|
||||
|
|
@ -132,7 +130,7 @@ class Command(BaseCommand):
|
|||
msg.send()
|
||||
#print('if and of project approved mail would have been sent')
|
||||
|
||||
inform_subject, inform_from_email, inform_to = 'Projektorganisator*in wurde informiert', IF_EMAIL, IF_EMAIL
|
||||
inform_subject, inform_from_email, inform_to = 'Projektorganisator*in wurde informiert', settings.IF_EMAIL, settings.IF_EMAIL
|
||||
inform_text_content = txt_informMail_template.render(context)
|
||||
inform_html_content = html_informMail_template.render(context)
|
||||
inform_msg = EmailMultiAlternatives(inform_subject, inform_text_content, inform_from_email, [inform_to])
|
||||
|
|
@ -178,9 +176,9 @@ class Command(BaseCommand):
|
|||
|
||||
for project in approved_notHappened:
|
||||
context = {'project': project}
|
||||
context['URLPREFIX'] = settings.URLPREFIX
|
||||
context['URL_PREFIX'] = settings.EMAIL_URL_PREFIX
|
||||
try:
|
||||
subject, from_email, to = 'Projektende erreicht', IF_EMAIL, project.email
|
||||
subject, from_email, to = 'Projektende erreicht', settings.IF_EMAIL, project.email
|
||||
text_content = txt_mail_template.render(context)
|
||||
html_content = html_mail_template.render(context)
|
||||
msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
|
||||
|
|
@ -195,7 +193,7 @@ class Command(BaseCommand):
|
|||
# [project.email],
|
||||
# fail_silently=False)
|
||||
|
||||
inform_subject, inform_from_email, inform_to = 'Projektorganisator*in wurde informiert', IF_EMAIL, IF_EMAIL
|
||||
inform_subject, inform_from_email, inform_to = 'Projektorganisator*in wurde informiert', settings.IF_EMAIL, settings.IF_EMAIL
|
||||
inform_text_content = txt_informMail_template.render(context)
|
||||
inform_html_content = html_informMail_template.render(context)
|
||||
inform_msg = EmailMultiAlternatives(inform_subject, inform_text_content, inform_from_email, [inform_to])
|
||||
|
|
@ -297,16 +295,15 @@ class Command(BaseCommand):
|
|||
'''send survey link 2 weeks after mailadresss, mailinglist or businesscards are granted'''
|
||||
lastdate = date.today() - timedelta(days=14)
|
||||
|
||||
typefield = ('MAIL','VIS','LIST')
|
||||
count = 0
|
||||
for c in ('Email', 'BusinessCard', 'List'):
|
||||
# get class via string
|
||||
supported = getattr(sys.modules[__name__], c).objects.filter(granted=True)\
|
||||
models = Email, BusinessCard, List
|
||||
types = 'MAIL', 'VIS', 'LIST'
|
||||
|
||||
for model, typ in zip(models, types):
|
||||
supported = model.objects.filter(granted=True)\
|
||||
.filter(granted_date__lt = lastdate)\
|
||||
.exclude(survey_mail_send=True)\
|
||||
.exclude(mail_state = 'END')
|
||||
self.surveymails_to_object(supported, type=typefield[count])
|
||||
count += 1
|
||||
self.surveymails_to_object(supported, type=typ)
|
||||
|
||||
|
||||
def handle(self, *args, **options):
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
import datetime
|
||||
|
||||
from django.core.management import call_command
|
||||
from django.test import TestCase
|
||||
from django.utils.timezone import localdate
|
||||
|
||||
from input.models import Project, Account, Email, Library, HonoraryCertificate
|
||||
|
||||
|
||||
class ManagementCommandTestCase(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.account = Account.objects.create(code='test')
|
||||
|
||||
def test_sendmails(self):
|
||||
today = localdate(None)
|
||||
start = today - datetime.timedelta(days=2)
|
||||
end = today - datetime.timedelta(days=1)
|
||||
granted = today - datetime.timedelta(days=15)
|
||||
|
||||
def create_project(name, **kwargs):
|
||||
kwargs.setdefault('account', self.account)
|
||||
kwargs.setdefault('start', start)
|
||||
kwargs.setdefault('end', end)
|
||||
|
||||
return Project.objects.create(name=name, **kwargs)
|
||||
|
||||
create_project('Test end_of_projects_reached')
|
||||
create_project('Test end_of_projects_approved', status='END', mail_state='INF')
|
||||
create_project('Test notHappened_of_projects_approved', status='NOT', mail_state='INF')
|
||||
|
||||
Email.objects.create(
|
||||
domain='SOURCE',
|
||||
address='cosmocode',
|
||||
adult='TRUE',
|
||||
granted=True,
|
||||
granted_date=granted,
|
||||
)
|
||||
|
||||
Library.objects.create(
|
||||
type='BIB',
|
||||
library='Test',
|
||||
duration='1 Jahr',
|
||||
cost=100,
|
||||
granted=True,
|
||||
granted_date=granted,
|
||||
)
|
||||
|
||||
HonoraryCertificate.objects.create(
|
||||
request_url='https://example.com',
|
||||
granted=True,
|
||||
granted_date=granted,
|
||||
project=create_project('Test surveymails_to_hon'),
|
||||
)
|
||||
|
||||
call_command('sendmails')
|
||||
|
|
@ -1,11 +1,14 @@
|
|||
from authlib.integrations.base_client import OAuthError
|
||||
from authlib.integrations.django_client import OAuth
|
||||
from authlib.oauth2.rfc6749 import OAuth2Token
|
||||
|
||||
from django.shortcuts import redirect
|
||||
from django.utils.deprecation import MiddlewareMixin
|
||||
from foerderbarometer import settings
|
||||
from input import views
|
||||
from input import models
|
||||
from django.conf import settings
|
||||
|
||||
from input.models import Extern
|
||||
from input.views import ExternView
|
||||
|
||||
|
||||
class OAuthMiddleware(MiddlewareMixin):
|
||||
|
||||
|
|
@ -14,7 +17,7 @@ class OAuthMiddleware(MiddlewareMixin):
|
|||
self.oauth = OAuth()
|
||||
|
||||
def process_request(self, request):
|
||||
# added this if clause to get the landing page before oauth
|
||||
# added this if-clause to get the landing page before oauth
|
||||
if request.path == '/':
|
||||
return self.get_response(request)
|
||||
if settings.OAUTH_URL_WHITELISTS is not None:
|
||||
|
|
@ -37,12 +40,12 @@ class OAuthMiddleware(MiddlewareMixin):
|
|||
self.clear_session(request)
|
||||
request.session['token'] = sso_client.authorize_access_token(request)
|
||||
# print('blub', request.session['token'])
|
||||
models.Extern.username = self.get_current_user(sso_client, request)['username']
|
||||
Extern.username = self.get_current_user(sso_client, request)['username']
|
||||
if self.get_current_user(sso_client, request) is not None:
|
||||
redirect_uri = request.session.pop('redirect_uri', None)
|
||||
if redirect_uri is not None:
|
||||
return redirect(redirect_uri)
|
||||
return redirect(views.ExternView)
|
||||
return redirect(ExternView)
|
||||
|
||||
if request.session.get('token', None) is not None:
|
||||
current_user = self.get_current_user(sso_client, request)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,113 @@
|
|||
# Generated by Django 5.2.5 on 2025-08-20 09:13
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('input', '0096_auto_20230106_1338'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='businesscard',
|
||||
name='realname',
|
||||
field=models.CharField(default='', help_text='Bitte gib deinen Vornamen und deinen Nachnamen ein.', max_length=200, null=True, verbose_name='Realname'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='businesscard',
|
||||
name='username',
|
||||
field=models.CharField(help_text='Wikimedia Benutzer_innenname', max_length=200, null=True, verbose_name='Benutzer_innenname'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='concreteextern',
|
||||
name='realname',
|
||||
field=models.CharField(default='', help_text='Bitte gib deinen Vornamen und deinen Nachnamen ein.', max_length=200, null=True, verbose_name='Realname'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='concreteextern',
|
||||
name='username',
|
||||
field=models.CharField(help_text='Wikimedia Benutzer_innenname', max_length=200, null=True, verbose_name='Benutzer_innenname'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='concretevolunteer',
|
||||
name='realname',
|
||||
field=models.CharField(default='', help_text='Bitte gib deinen Vornamen und deinen Nachnamen ein.', max_length=200, null=True, verbose_name='Realname'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='email',
|
||||
name='realname',
|
||||
field=models.CharField(default='', help_text='Bitte gib deinen Vornamen und deinen Nachnamen ein.', max_length=200, null=True, verbose_name='Realname'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='email',
|
||||
name='username',
|
||||
field=models.CharField(help_text='Wikimedia Benutzer_innenname', max_length=200, null=True, verbose_name='Benutzer_innenname'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='honorarycertificate',
|
||||
name='realname',
|
||||
field=models.CharField(default='', help_text='Bitte gib deinen Vornamen und deinen Nachnamen ein.', max_length=200, null=True, verbose_name='Realname'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='ifg',
|
||||
name='realname',
|
||||
field=models.CharField(default='', help_text='Bitte gib deinen Vornamen und deinen Nachnamen ein.', max_length=200, null=True, verbose_name='Realname'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='ifg',
|
||||
name='username',
|
||||
field=models.CharField(help_text='Wikimedia Benutzer_innenname', max_length=200, null=True, verbose_name='Benutzer_innenname'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='library',
|
||||
name='realname',
|
||||
field=models.CharField(default='', help_text='Bitte gib deinen Vornamen und deinen Nachnamen ein.', max_length=200, null=True, verbose_name='Realname'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='library',
|
||||
name='type',
|
||||
field=models.CharField(choices=[('BIB', '<a href="https://de.wikipedia.org/wiki/Wikipedia:Förderung/Zugang_zu_Fachliteratur#Bibliotheksstipendium" target="_blank" rel="noopener">Bibliotheksstipendium</a>'), ('ELIT', '<a href="https://de.wikipedia.org/wiki/Wikipedia:Förderung/Zugang_zu_Fachliteratur#eLiteraturstipendium" target="_blank" rel="noopener">eLiteraturstipendium</a>'), ('MAIL', '<a href="https://de.wikipedia.org/wiki/Wikipedia:Förderung/E-Mail-Adressen_und_Visitenkarten#E-Mail-Adressen" target="_blank" rel="noopener">E-Mail-Adresse</a>'), ('IFG', '<a href="https://de.wikipedia.org/wiki/Wikipedia:Förderung/Gebührenerstattungen_für_Behördenanfragen" target="_blank" rel="noopener">Kostenübernahme IFG-Anfrage</a>'), ('LIT', '<a href="https://de.wikipedia.org/wiki/Wikipedia:Förderung/Zugang_zu_Fachliteratur#Literaturstipendium" target="_blank" rel="noopener">Literaturstipendium</a>'), ('LIST', '<a href="https://de.wikipedia.org/wiki/Wikipedia:Förderung/E-Mail-Adressen_und_Visitenkarten#Mailinglisten" target="_blank" rel="noopener">Mailingliste</a>'), ('TRAV', '<a href="https://de.wikipedia.org/wiki/Wikipedia:Förderung/Reisekostenerstattungen" target="_blank" rel="noopener">Reisekosten</a>'), ('SOFT', '<a href="https://de.wikipedia.org/wiki/Wikipedia:Förderung/Software-Stipendien" target="_blank" rel="noopener">Softwarestipendium</a>'), ('VIS', '<a href="https://de.wikipedia.org/wiki/Wikipedia:Förderung/E-Mail-Adressen_und_Visitenkarten#Visitenkarten" target="_blank" rel="noopener">Visitenkarten</a>')], default='BIB', max_length=4),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='library',
|
||||
name='username',
|
||||
field=models.CharField(help_text='Wikimedia Benutzer_innenname', max_length=200, null=True, verbose_name='Benutzer_innenname'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='list',
|
||||
name='realname',
|
||||
field=models.CharField(default='', help_text='Bitte gib deinen Vornamen und deinen Nachnamen ein.', max_length=200, null=True, verbose_name='Realname'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='list',
|
||||
name='username',
|
||||
field=models.CharField(help_text='Wikimedia Benutzer_innenname', max_length=200, null=True, verbose_name='Benutzer_innenname'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='literature',
|
||||
name='realname',
|
||||
field=models.CharField(default='', help_text='Bitte gib deinen Vornamen und deinen Nachnamen ein.', max_length=200, null=True, verbose_name='Realname'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='literature',
|
||||
name='username',
|
||||
field=models.CharField(help_text='Wikimedia Benutzer_innenname', max_length=200, null=True, verbose_name='Benutzer_innenname'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='project',
|
||||
name='realname',
|
||||
field=models.CharField(default='', help_text='Bitte gib deinen Vornamen und deinen Nachnamen ein.', max_length=200, null=True, verbose_name='Realname'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='travel',
|
||||
name='realname',
|
||||
field=models.CharField(default='', help_text='Bitte gib deinen Vornamen und deinen Nachnamen ein.', max_length=200, null=True, verbose_name='Realname'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='travel',
|
||||
name='username',
|
||||
field=models.CharField(help_text='Wikimedia Benutzer_innenname', max_length=200, null=True, verbose_name='Benutzer_innenname'),
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
# Generated by Django 5.2.5 on 2025-08-20 10:01
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('input', '0097_alter_realname_and_username'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ELiterature',
|
||||
fields=[
|
||||
],
|
||||
options={
|
||||
'proxy': True,
|
||||
'indexes': [],
|
||||
'constraints': [],
|
||||
},
|
||||
bases=('input.library',),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Software',
|
||||
fields=[
|
||||
],
|
||||
options={
|
||||
'proxy': True,
|
||||
'indexes': [],
|
||||
'constraints': [],
|
||||
},
|
||||
bases=('input.library',),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='library',
|
||||
name='type',
|
||||
field=models.CharField(choices=[('BIB', '<a href="https://de.wikipedia.org/wiki/Wikipedia:Förderung/Zugang_zu_Fachliteratur#Bibliotheksstipendium" target="_blank" rel="noopener">Bibliotheksstipendium</a>'), ('ELIT', '<a href="https://de.wikipedia.org/wiki/Wikipedia:Förderung/Zugang_zu_Fachliteratur#eLiteraturstipendium" target="_blank" rel="noopener">eLiteraturstipendium</a>'), ('SOFT', '<a href="https://de.wikipedia.org/wiki/Wikipedia:Förderung/Software-Stipendien" target="_blank" rel="noopener">Softwarestipendium</a>')], default='BIB', max_length=4),
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
# Generated by Django 5.2.5 on 2025-08-26 11:28
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('input', '0098_add_eliterature_and_software_proxies'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='businesscard',
|
||||
name='terms_accepted',
|
||||
field=models.BooleanField(default=False, verbose_name='Nutzungsbedingungen zugestimmt'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='email',
|
||||
name='terms_accepted',
|
||||
field=models.BooleanField(default=False, verbose_name='Nutzungsbedingungen zugestimmt'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='list',
|
||||
name='terms_accepted',
|
||||
field=models.BooleanField(default=False, verbose_name='Nutzungsbedingungen zugestimmt'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='literature',
|
||||
name='terms_accepted',
|
||||
field=models.BooleanField(default=False, verbose_name='Nutzungsbedingungen zugestimmt'),
|
||||
),
|
||||
]
|
||||
157
input/models.py
157
input/models.py
|
|
@ -2,20 +2,28 @@ from datetime import date
|
|||
|
||||
from django.db import models
|
||||
from django.utils.html import format_html
|
||||
|
||||
from .settings import ACCOUNTS
|
||||
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
EMAIL_STATES = {'NONE': 'noch keine Mail versendet',
|
||||
'INF': 'die Benachrichtigung zur Projektabschlussmail wurde versendet',
|
||||
'CLOSE': 'die Projektabschlussmail wurde versendet',
|
||||
'END': 'alle automatischen Mails, auch surveyMail, wurden versendet'}
|
||||
|
||||
|
||||
class TermsConsentMixin(models.Model):
|
||||
"""Abstract mixin to add a terms_accepted field for documenting user consent."""
|
||||
|
||||
terms_accepted = models.BooleanField(default=False, verbose_name="Nutzungsbedingungen zugestimmt")
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
||||
class Volunteer(models.Model):
|
||||
realname = models.CharField(max_length=200, null=True, verbose_name="Realname",
|
||||
help_text="Bitte gib deinen Vornamen und deinen Nachnamen ein.", default='')
|
||||
email = models.EmailField(max_length=200, null=True, verbose_name='E-Mail-Adresse',
|
||||
help_text=format_html('Bitte gib deine E-Mail-Adresse ein, damit dich<br>Wikimedia Deutschland bei Rückfragen oder für<br>die Zusage kontaktieren kann.'))
|
||||
help_text=mark_safe('Bitte gib deine E-Mail-Adresse ein, damit dich<br>Wikimedia Deutschland bei Rückfragen oder für<br>die Zusage kontaktieren kann.'))
|
||||
|
||||
# the following Fields are not supposed to be edited by users
|
||||
|
||||
|
|
@ -42,7 +50,7 @@ class Extern(Volunteer):
|
|||
''' abstract basis class for all data entered by extern volunteers '''
|
||||
|
||||
username = models.CharField(max_length=200, null=True, verbose_name='Benutzer_innenname',
|
||||
help_text=format_html("Wikimedia Benutzer_innenname"))
|
||||
help_text=mark_safe("Wikimedia Benutzer_innenname"))
|
||||
|
||||
# the following Fields are not supposed to be edited by users
|
||||
service_id = models.CharField(max_length=15, null=True, blank=True)
|
||||
|
|
@ -154,16 +162,8 @@ class Project(Volunteer):
|
|||
# self.pid = str(self.account.code) + str(self.pk).zfill(3)
|
||||
print (("Hallo Leute! Ich save jetzt mal MIT PID DANN!!!",self.pid))
|
||||
|
||||
|
||||
# generation of field quartals
|
||||
if self.end.month in [1, 2, 3]:
|
||||
self.end_quartal = 'Q1'
|
||||
if self.end.month in [4, 5, 6]:
|
||||
self.end_quartal = 'Q2'
|
||||
if self.end.month in [7, 8, 9]:
|
||||
self.end_quartal = 'Q3'
|
||||
if self.end.month in [10, 11, 12]:
|
||||
self.end_quartal = 'Q4'
|
||||
if self.end:
|
||||
self.end_quartal = f'Q{self.end.month // 4 + 1}'
|
||||
|
||||
super().save()
|
||||
|
||||
|
|
@ -198,8 +198,8 @@ TRANSPORT_CHOICES = {'BAHN': 'Bahn',
|
|||
PAYEDBY_CHOICES = {'WMDE': 'WMDE',
|
||||
'REQU': 'Antragstellender Mensch'}
|
||||
|
||||
HOTEL_CHOICES = {'TRUE': format_html('Hotelzimmer benötigt'),
|
||||
'FALSE': format_html('Kein Hotelzimmer benötigt')
|
||||
HOTEL_CHOICES = {'TRUE': mark_safe('Hotelzimmer benötigt'),
|
||||
'FALSE': mark_safe('Kein Hotelzimmer benötigt')
|
||||
}
|
||||
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
|
@ -254,47 +254,95 @@ class Grant(Extern):
|
|||
abstract = True
|
||||
|
||||
|
||||
TYPE_CHOICES = {'BIB': format_html('<a href="https://de.wikipedia.org/wiki/Wikipedia:Förderung/Zugang_zu_Fachliteratur#Bibliotheksstipendium" target="_blank" rel="noopener">Bibliotheksstipendium</a>'),
|
||||
'ELIT': format_html('<a href="https://de.wikipedia.org/wiki/Wikipedia:Förderung/Zugang_zu_Fachliteratur#eLiteraturstipendium" target="_blank" rel="noopener">eLiteraturstipendium</a>'),
|
||||
'MAIL': format_html('<a href="https://de.wikipedia.org/wiki/Wikipedia:Förderung/E-Mail-Adressen_und_Visitenkarten#E-Mail-Adressen" target="_blank" rel="noopener">E-Mail-Adresse</a>'),
|
||||
'IFG': format_html('<a href="https://de.wikipedia.org/wiki/Wikipedia:Förderung/Gebührenerstattungen_für_Behördenanfragen" target="_blank" rel="noopener">Kostenübernahme IFG-Anfrage</a>'),
|
||||
'LIT': format_html('<a href="https://de.wikipedia.org/wiki/Wikipedia:Förderung/Zugang_zu_Fachliteratur#Literaturstipendium" target="_blank" rel="noopener">Literaturstipendium</a>'),
|
||||
'LIST': format_html('<a href="https://de.wikipedia.org/wiki/Wikipedia:Förderung/E-Mail-Adressen_und_Visitenkarten#Mailinglisten" target="_blank" rel="noopener">Mailingliste</a>'),
|
||||
'TRAV': format_html('<a href="https://de.wikipedia.org/wiki/Wikipedia:F%C3%B6rderung/Reisekostenerstattungen" target="_blank" rel="noopener">Reisekosten</a>'),
|
||||
'SOFT': format_html('<a href="https://de.wikipedia.org/wiki/Wikipedia:Förderung/Software-Stipendien" target="_blank" rel="noopener">Softwarestipendium</a>'),
|
||||
'VIS': format_html('<a href="https://de.wikipedia.org/wiki/Wikipedia:Förderung/E-Mail-Adressen_und_Visitenkarten#Visitenkarten" target="_blank" rel="noopener">Visitenkarten</a>'),
|
||||
}
|
||||
def type_link(path, label):
|
||||
return format_html(
|
||||
format_string='<a href="{href}" target="_blank" rel="noopener">{label}</a>',
|
||||
href=f'https://de.wikipedia.org/wiki/Wikipedia:Förderung/{path}',
|
||||
label=label,
|
||||
)
|
||||
|
||||
|
||||
TYPE_BIB = 'BIB'
|
||||
TYPE_ELIT = 'ELIT'
|
||||
TYPE_MAIL = 'MAIL'
|
||||
TYPE_IFG = 'IFG'
|
||||
TYPE_LIT = 'LIT'
|
||||
TYPE_LIST = 'LIST'
|
||||
TYPE_TRAV = 'TRAV'
|
||||
TYPE_SOFT = 'SOFT'
|
||||
TYPE_VIS = 'VIS'
|
||||
|
||||
TYPE_CHOICES = {
|
||||
TYPE_BIB: type_link('Zugang_zu_Fachliteratur#Bibliotheksstipendium', 'Bibliotheksstipendium'),
|
||||
TYPE_ELIT: type_link('Zugang_zu_Fachliteratur#eLiteraturstipendium', 'eLiteraturstipendium'),
|
||||
TYPE_MAIL: type_link('E-Mail-Adressen_und_Visitenkarten#E-Mail-Adressen', 'E-Mail-Adresse'),
|
||||
TYPE_IFG: type_link('Gebührenerstattungen_für_Behördenanfragen', 'Kostenübernahme IFG-Anfrage'),
|
||||
TYPE_LIT: type_link('Zugang_zu_Fachliteratur#Literaturstipendium', 'Literaturstipendium'),
|
||||
TYPE_LIST: type_link('E-Mail-Adressen_und_Visitenkarten#Mailinglisten', 'Mailingliste'),
|
||||
TYPE_TRAV: type_link('Reisekostenerstattungen', 'Reisekosten'),
|
||||
TYPE_SOFT: type_link('Software-Stipendien', 'Softwarestipendium'),
|
||||
TYPE_VIS: type_link('E-Mail-Adressen_und_Visitenkarten#Visitenkarten', 'Visitenkarten'),
|
||||
}
|
||||
|
||||
LIBRARY_TYPES = TYPE_BIB, TYPE_ELIT, TYPE_SOFT
|
||||
LIBRARY_TYPE_CHOICES = [(choice, TYPE_CHOICES[choice]) for choice in LIBRARY_TYPES]
|
||||
|
||||
# same model is used for Library, ELitStip and Software!
|
||||
class Library(Grant):
|
||||
TYPE = TYPE_BIB
|
||||
LIBRARY_LABEL = 'Bibliothek'
|
||||
LIBRARY_HELP_TEXT = 'Für welche Bibliothek gilt das Stipendium?'
|
||||
DURATION_HELP_TEXT = mark_safe('In welchem Zeitraum möchtest du recherchieren oder<br>wie lange ist der Bibliotheksausweis gültig?')
|
||||
|
||||
type = models.CharField(
|
||||
max_length=4,
|
||||
choices=TYPE_CHOICES.items(), #attention: actually only BIB, ELIT, SOFT should be used here
|
||||
default='BIB',
|
||||
)
|
||||
type = models.CharField(max_length=4, choices=LIBRARY_TYPE_CHOICES, default=TYPE_BIB)
|
||||
library = models.CharField(max_length=200)
|
||||
duration = models.CharField(max_length=100, verbose_name="Dauer")
|
||||
intern_notes = models.TextField(max_length=1000, blank=True, verbose_name="interne Anmerkungen")
|
||||
|
||||
def __str__(self):
|
||||
return self.library
|
||||
|
||||
def save(self, **kwargs):
|
||||
self.type = self.TYPE
|
||||
|
||||
SELFBUY_CHOICES = {'TRUE': format_html('Ich möchte das Werk selbst kaufen und per Kostenerstattung bei Wikimedia Deutschland abrechnen.'),
|
||||
'FALSE': format_html('Ich möchte, dass Wikimedia Deutschland das Werk für mich kauft'),
|
||||
return super().save(**kwargs)
|
||||
|
||||
|
||||
class ELiterature(Library):
|
||||
TYPE = TYPE_ELIT
|
||||
LIBRARY_LABEL = 'Datenbank/Online-Ressource'
|
||||
LIBRARY_HELP_TEXT = 'Für welche Datenbank/Online-Ressource gilt das Stipendium?'
|
||||
DURATION_HELP_TEXT = 'Wie lange gilt der Zugang?'
|
||||
|
||||
class Meta:
|
||||
proxy = True
|
||||
|
||||
|
||||
class Software(Library):
|
||||
TYPE = TYPE_SOFT
|
||||
LIBRARY_LABEL = 'Software'
|
||||
LIBRARY_HELP_TEXT = 'Für welche Software gilt das Stipendium?'
|
||||
DURATION_HELP_TEXT = 'Wie lange gilt die Lizenz?'
|
||||
|
||||
class Meta:
|
||||
proxy = True
|
||||
|
||||
|
||||
SELFBUY_CHOICES = {'TRUE': mark_safe('Ich möchte das Werk selbst kaufen und per Kostenerstattung bei Wikimedia Deutschland abrechnen.'),
|
||||
'FALSE': mark_safe('Ich möchte, dass Wikimedia Deutschland das Werk für mich kauft'),
|
||||
}
|
||||
|
||||
|
||||
class Literature(Grant):
|
||||
class Literature(TermsConsentMixin, Grant):
|
||||
info = models.CharField(max_length=500, verbose_name='Informationen zum Werk',
|
||||
help_text=format_html("Bitte gib alle Informationen zum benötigten Werk an,<br>\
|
||||
help_text=mark_safe("Bitte gib alle Informationen zum benötigten Werk an,<br>\
|
||||
die eine eindeutige Identifizierung ermöglichen (Autor, Titel, Verlag, ISBN, ...)"))
|
||||
source = models.CharField(max_length=200, verbose_name='Bezugsquelle',
|
||||
help_text="Bitte gib an, wo du das Werk kaufen möchtest.")
|
||||
selfbuy = models.CharField( max_length=10, verbose_name='Selbstkauf?', choices=SELFBUY_CHOICES.items(), default='TRUE')
|
||||
selfbuy_give_data = models.BooleanField(verbose_name=format_html('Datenweitergabe erlauben'), help_text=format_html('Ich stimme der Weitergabe meiner Daten (Name, Postadresse) an den von mir angegebenen Anbieter/Dienstleister zu.'))
|
||||
selfbuy_give_data = models.BooleanField(verbose_name=mark_safe('Datenweitergabe erlauben'), help_text=mark_safe('Ich stimme der Weitergabe meiner Daten (Name, Postadresse) an den von mir angegebenen Anbieter/Dienstleister zu.'))
|
||||
selfbuy_data = models.TextField(max_length=1000, verbose_name='Persönliche Daten sowie Adresse', default='',\
|
||||
help_text=format_html("Bitte gib hier alle persönlichen Daten an, die wir benötigen, um das Werk<br>\
|
||||
help_text=mark_safe("Bitte gib hier alle persönlichen Daten an, die wir benötigen, um das Werk<br>\
|
||||
für dich zu kaufen und es dir anschließend zu schicken (z.B. Vorname Nachname, Anschrift, <br>\
|
||||
Telefonnummer, E-Mail-Adresse usw.). Trenne die einzelnen Angaben durch Zeilenumbrüche."))
|
||||
intern_notes = models.TextField(max_length=1000, blank=True, verbose_name="interne Anmerkungen")
|
||||
|
|
@ -325,24 +373,24 @@ MAIL_CHOICES = {'REALNAME': 'Vorname.Nachname',
|
|||
'USERNAME': 'Username',
|
||||
'OTHER': 'Sonstiges:'}
|
||||
|
||||
ADULT_CHOICES = {'TRUE': format_html('Ich bin volljährig.'),
|
||||
'FALSE': format_html('Ich bin noch nicht volljährig.')
|
||||
ADULT_CHOICES = {'TRUE': mark_safe('Ich bin volljährig.'),
|
||||
'FALSE': mark_safe('Ich bin noch nicht volljährig.')
|
||||
}
|
||||
|
||||
class Email(Domain):
|
||||
class Email(TermsConsentMixin, Domain):
|
||||
address = models.CharField(max_length=50,
|
||||
choices=MAIL_CHOICES.items(),
|
||||
default='USERNAME', verbose_name='Adressbestandteil',
|
||||
help_text=format_html("Bitte gib hier den gewünschten Adressbestandteil an,<br>der sich vor der Domain befinden soll."))
|
||||
help_text=mark_safe("Bitte gib hier den gewünschten Adressbestandteil an,<br>der sich vor der Domain befinden soll."))
|
||||
|
||||
other = models.CharField(max_length=50,blank=True,null=True, verbose_name="Sonstiges")
|
||||
adult = models.CharField( max_length=10, verbose_name='Volljährigkeit', choices=ADULT_CHOICES.items(), default='FALSE')
|
||||
intern_notes = models.TextField(max_length=1000, blank=True, verbose_name="interne Anmerkungen")
|
||||
|
||||
class List(Domain):
|
||||
class List(TermsConsentMixin, Domain):
|
||||
address = models.CharField(max_length=50, default='NO_ADDRESS',
|
||||
verbose_name="Adressbestandteil für Projektmailingliste",
|
||||
help_text=format_html("Bitte gib hier den gewünschten Adressbestandteil an,<br>der sich vor der Domain befinden soll."))
|
||||
help_text=mark_safe("Bitte gib hier den gewünschten Adressbestandteil an,<br>der sich vor der Domain befinden soll."))
|
||||
intern_notes = models.TextField(max_length=1000, blank=True, verbose_name="interne Anmerkungen")
|
||||
|
||||
PROJECT_CHOICE = {'PEDIA': 'Wikipedia',
|
||||
|
|
@ -358,13 +406,13 @@ PROJECT_CHOICE = {'PEDIA': 'Wikipedia',
|
|||
BC_VARIANT = {'PIC': 'mit Bild',
|
||||
'NOPIC': 'ohne Bild'}
|
||||
|
||||
class BusinessCard(Extern):
|
||||
class BusinessCard(TermsConsentMixin, Extern):
|
||||
project = models.CharField(max_length=20, choices=PROJECT_CHOICE.items(),
|
||||
default='PEDIA', verbose_name='Wikimedia-Projekt',
|
||||
help_text='Für welches Wikimedia-Projekt möchtest Du Visitenkarten?')
|
||||
|
||||
data = models.TextField(max_length=1000, verbose_name='Persönliche Daten für die Visitenkarten', default='',
|
||||
help_text=format_html("Bitte gib hier alle persönlichen Daten an, und zwar genau so,<br>\
|
||||
help_text=mark_safe("Bitte gib hier alle persönlichen Daten an, und zwar genau so,<br>\
|
||||
wie sie (auch in der entsprechenden Reihenfolge) auf den Visitenkarten stehen sollen<br>\
|
||||
(z.B. Vorname Nachname, Benutzer:/Benutzerin:, Benutzer-/-innenname, Anschrift,<br>\
|
||||
Telefonnummer, E-Mail-Adresse usw.). Trenne die einzelnen Angaben durch Zeilenumbrüche.<br>\
|
||||
|
|
@ -373,12 +421,25 @@ class BusinessCard(Extern):
|
|||
Adresse, die du ebenfalls beantragen kannst, sofern du nicht bereits eine besitzt."))
|
||||
variant = models.CharField(max_length=5, choices=BC_VARIANT.items(),
|
||||
default='NOPIC', verbose_name='Variante',
|
||||
help_text=format_html('so sehen die Varianten aus: <a href="https://upload.wikimedia.org/wikipedia/commons/c/cd/Muster_Visitenkarten_WMDE_2018.jpg">\
|
||||
help_text=mark_safe('so sehen die Varianten aus: <a href="https://upload.wikimedia.org/wikipedia/commons/c/cd/Muster_Visitenkarten_WMDE_2018.jpg">\
|
||||
mit Bild</a> <a href="https://upload.wikimedia.org/wikipedia/commons/d/d3/Muster_Visitenkarte_WMDE.png">ohne Bild</a>' ))
|
||||
|
||||
url_of_pic = models.CharField(max_length=200, verbose_name='Url des Bildes', default='', help_text="Bitte gib die Wikimedia-Commons-URL des Bildes an.")
|
||||
|
||||
sent_to = models.TextField(max_length=1000, verbose_name='Versandadresse',
|
||||
default='', help_text="Bitte gib den Namen und die vollständige Adresse ein, an welche die Visitenkarten geschickt werden sollen.")
|
||||
send_data_to_print = models.BooleanField(default=False, verbose_name=format_html('Datenweitergabe erlauben'), help_text=format_html('Hiermit erlaube ich die Weitergabe meiner Daten (Name, Postadresse) an den von Wikimedia<br> Deutschland ausgewählten Dienstleister (z. B. <a href="wir-machen-druck.de">wir-machen-druck.de</a>) zum Zwecke des direkten <br> Versands der Druckerzeugnisse an mich.'))
|
||||
send_data_to_print = models.BooleanField(default=False, verbose_name=mark_safe('Datenweitergabe erlauben'), help_text=mark_safe('Hiermit erlaube ich die Weitergabe meiner Daten (Name, Postadresse) an den von Wikimedia<br> Deutschland ausgewählten Dienstleister (z. B. <a href="wir-machen-druck.de">wir-machen-druck.de</a>) zum Zwecke des direkten <br> Versands der Druckerzeugnisse an mich.'))
|
||||
intern_notes = models.TextField(max_length=1000, blank=True, verbose_name="interne Anmerkungen")
|
||||
|
||||
|
||||
MODELS = {
|
||||
TYPE_BIB: Library,
|
||||
TYPE_ELIT: ELiterature,
|
||||
TYPE_MAIL: Email,
|
||||
TYPE_IFG: IFG,
|
||||
TYPE_LIT: Literature,
|
||||
TYPE_LIST: List,
|
||||
TYPE_TRAV: Travel,
|
||||
TYPE_SOFT: Software,
|
||||
TYPE_VIS: BusinessCard,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,78 +0,0 @@
|
|||
# mail for IF-OTRS
|
||||
IF_EMAIL = 'community@wikimedia.de'
|
||||
#IF_EMAIL = 'test-luca-ext@wikimedia.de'
|
||||
#SURVEY_EMAIL = 'christof.pins@wikimedia.de'
|
||||
#SURVEY_EMAIL = 'luca.wulf@cannabinieri.de'
|
||||
SURVEY_EMAIL = 'sandro.halank@wikimedia.de'
|
||||
# prefix for urls
|
||||
SURVEYPREFIX = 'https://wikimedia.sslsurvey.de/Foerderbarometer/?'
|
||||
|
||||
# some links
|
||||
DATAPROTECTION = "https://www.wikimedia.de/datenschutz/#datenerfassung"
|
||||
#FOERDERRICHTLINIEN = "https://de.wikipedia.org/wiki/Wikipedia:Wikimedia_Deutschland/F%C3%B6rderrichtlinien"
|
||||
FOERDERRICHTLINIEN = "https://de.wikipedia.org/wiki/Wikipedia:Wikimedia_Deutschland/Richtlinie_zur_Förderung_der_Communitys"
|
||||
|
||||
NUTZUNGSBEDINGUNGEN = 'static/input/nutzungsbedingungen.html'
|
||||
NUTZUNGSBEDINGUNGEN_EMAIL_SERVICE = 'static/input/nutzungsbedingungen-mail.pdf'
|
||||
NUTZUNGSBEDINGUNGEN_MAILINGLISTEN = 'static/input/nutzungsbedingungen-mailinglisten.pdf'
|
||||
NUTZUNGSBEDINGUNGEN_LITERATURSTIPENDIUM = 'static/input/nutzungsbedingungen-literaturstipendium.pdf'
|
||||
NUTZUNGSBEDINGUNGEN_OTRS = 'static/input/2025_Nutzungsvereinbarung_OTRS.docx.pdf'
|
||||
NUTZUNGSBEDINGUNGEN_VISITENKARTEN = 'static/input/nutzungsbedingungen-visitenkarten.pdf'
|
||||
|
||||
LANGUAGE_CODE = 'de'
|
||||
TIME_ZONE = 'UTC'
|
||||
USE_I18N = True
|
||||
USE_L10N = True
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
ACCOUNTS ={ # "21103": '21103 Willkommen',
|
||||
"DEF": 'DEFAULT VALUE, you hould not see this!',
|
||||
"21111": '21111 Förderung (reaktiv)',
|
||||
"21112": '21112 WikiCon',
|
||||
# "21113": '21113 Wikimania/Unterstützung Ehrenamtliche',
|
||||
"21115": '21115 Lokale Räume, Berlin',
|
||||
"21116": '21116 Lokale Räume, Hamburg',
|
||||
"21117": '21117 Lokale Räume, Hannover',
|
||||
"21118": '21118 Lokale Räume, Köln',
|
||||
"21119": '21119 Lokale Räume, München',
|
||||
"21120": '21120 Lokale Räume, Fürth',
|
||||
"21125": '21125 Lokale Räume, allgemein',
|
||||
"21130": '21130 GLAM-Förderung',
|
||||
"21131": '21131 Initiative Förderung',
|
||||
# "21134": '21134 Größe',
|
||||
# "21137": '21137 Beitragen',
|
||||
# "21138": '21138 Vermittlung',
|
||||
"21140": '21140 Wikipedia-Kampagne',
|
||||
"21141": '21141 Wikipedia-Onboarding',
|
||||
"21150": '21150 Fürsorge und Online-Kommunikationskultur',}
|
||||
|
||||
|
||||
|
||||
# teken from working oauth prototype as additional settings
|
||||
|
||||
WSGI_APPLICATION = 'oauth_demo.wsgi.application'
|
||||
|
||||
# OAuth Settings
|
||||
OAUTH_URL_WHITELISTS = []
|
||||
|
||||
OAUTH_CLIENT_NAME = '<name-of-the-configured-wikimedia-app>'
|
||||
|
||||
|
||||
|
||||
OAUTH_CLIENT = {
|
||||
'client_id': '<client-application-key-of-wikimedia-app>',
|
||||
'client_secret': '<client-application-secret-of-wikimedia-app>',
|
||||
'access_token_url': 'https://meta.wikimedia.org/w/rest.php/oauth2/access_token',
|
||||
'authorize_url': 'https://meta.wikimedia.org/w/rest.php/oauth2/authorize',
|
||||
'api_base_url': 'https://meta.wikimedia.org/w/rest.php/oauth2/resource',
|
||||
'redirect_uri': 'http://localhost:8000/oauth/callback',
|
||||
'client_kwargs': {
|
||||
'scope': 'basic',
|
||||
'token_placement': 'header'
|
||||
},
|
||||
'userinfo_endpoint': 'resource/profile',
|
||||
}
|
||||
|
||||
OAUTH_COOKIE_SESSION_ID = 'sso_session_id'
|
||||
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
# mail for IF-OTRS
|
||||
IF_EMAIL = 'community@wikimedia.de'
|
||||
#IF_EMAIL = 'test-luca-ext@wikimedia.de'
|
||||
#SURVEY_EMAIL = 'christof.pins@wikimedia.de'
|
||||
#SURVEY_EMAIL = 'luca.wulf@cannabinieri.de'
|
||||
SURVEY_EMAIL = 'sandro.halank@wikimedia.de'
|
||||
# prefix for urls
|
||||
SURVEYPREFIX = 'https://wikimedia.sslsurvey.de/Foerderbarometer/?'
|
||||
|
||||
# some links
|
||||
DATAPROTECTION = "https://www.wikimedia.de/datenschutz/#datenerfassung"
|
||||
FOERDERRICHTLINIEN = "https://de.wikipedia.org/wiki/Wikipedia:Wikimedia_Deutschland/F%C3%B6rderrichtlinien"
|
||||
NUTZUNGSBEDINGUNGEN = 'static/input/nutzungsbedingungen.html'
|
||||
|
||||
LANGUAGE_CODE = 'de'
|
||||
TIME_ZONE = 'UTC'
|
||||
USE_I18N = True
|
||||
USE_L10N = True
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
ACCOUNTS ={ # "21103": '21103 Willkommen',
|
||||
"DEF": 'DEFAULT VALUE, you hould not see this!',
|
||||
"21111": '21111 Förderung (reaktiv)',
|
||||
"21112": '21112 WikiCon',
|
||||
# "21113": '21113 Wikimania/Unterstützung Ehrenamtliche',
|
||||
"21115": '21115 Lokale Räume, Berlin',
|
||||
"21116": '21116 Lokale Räume, Hamburg',
|
||||
"21117": '21117 Lokale Räume, Hannover',
|
||||
"21118": '21118 Lokale Räume, Köln',
|
||||
"21119": '21119 Lokale Räume, München',
|
||||
"21120": '21120 Lokale Räume, Fürth',
|
||||
"21125": '21125 Lokale Räume, allgemein',
|
||||
"21130": '21130 GLAM-Förderung',
|
||||
"21131": '21131 Initiative Förderung',
|
||||
# "21134": '21134 Größe',
|
||||
# "21137": '21137 Beitragen',
|
||||
# "21138": '21138 Vermittlung',
|
||||
"21140": '21140 Wikipedia-Kampagne',
|
||||
"21141": '21141 Wikipedia-Onboarding',
|
||||
"21150": '21150 Fürsorge und Online-Kommunikationskultur',}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
ul > li {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
ul {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
label.required::after {
|
||||
content: ' *';
|
||||
color: red;
|
||||
}
|
||||
|
||||
.spacer-15 {
|
||||
height: 15%;
|
||||
}
|
||||
|
||||
.spacer-5 {
|
||||
height: 5%;
|
||||
}
|
||||
|
||||
.page-centered {
|
||||
text-align: center;
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
.page-centered .button-login {
|
||||
width: 40vw;
|
||||
height: 6vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-weight: bold;
|
||||
font-size: 4vh;
|
||||
margin: 0 auto;
|
||||
background-color: #79AEC8;
|
||||
color: #000000;
|
||||
text-decoration: none;
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
.page-centered .button-login:hover {
|
||||
background-color: #659DB8;
|
||||
}
|
||||
|
||||
.page-centered .button-login:focus-visible {
|
||||
outline: 2px solid #000;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@ Ende erreicht.<br><br>
|
|||
|
||||
Hier könnt ihr es in der Datenbank editieren:
|
||||
<br><br>
|
||||
<a href="{{URLPREFIX}}/admin/input/project/{{project.pk}}/change">{{URLPREFIX}}/admin/input/project/{{project.pk}}/change</a>
|
||||
<a href="{{URL_PREFIX}}/admin/input/project/{{project.pk}}/change">{{URL_PREFIX}}/admin/input/project/{{project.pk}}/change</a>
|
||||
<br><br>
|
||||
mit freundlichen Grüßen, Eure Lieblingsdatenbank
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,6 @@ Ende erreicht.
|
|||
|
||||
Hier könnt ihr es in der Datenbank editieren:
|
||||
|
||||
{{URLPREFIX}}/admin/input/project/{{project.pk}}/change
|
||||
{{URL_PREFIX}}/admin/input/project/{{project.pk}}/change
|
||||
|
||||
mit freundlichen Grüßen, Eure Lieblingsdatenbank
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ Ende erreicht.
|
|||
<br><br>
|
||||
Hier könnt ihr es in der Datenbank editieren:
|
||||
<br><br>
|
||||
<a href="{{URLPREFIX}}/admin/input/project/{{project.pk}}/change">{{URLPREFIX}}/admin/input/project/{{project.pk}}/change</a>
|
||||
<a href="{{URL_PREFIX}}/admin/input/project/{{project.pk}}/change">{{URL_PREFIX}}/admin/input/project/{{project.pk}}/change</a>
|
||||
<br><br>
|
||||
|
||||
Projektorganisator*in wurde über den Projektabschluss informiert.
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ Ende erreicht.
|
|||
|
||||
Hier könnt ihr es in der Datenbank editieren:
|
||||
|
||||
{{URLPREFIX}}/admin/input/project/{{project.pk}}/change
|
||||
{{URL_PREFIX}}/admin/input/project/{{project.pk}}/change
|
||||
|
||||
|
||||
Projektorganisator*in wurde über den Projektabschluss informiert.
|
||||
|
|
|
|||
|
|
@ -28,29 +28,29 @@ Sendungsadrese: {{data.send_to}} <br> {% endif %}
|
|||
|
||||
Zum Eintrag in der Förderdatenbank:
|
||||
{% if data.choice == 'BIB' %}
|
||||
<a href="{{data.urlprefix}}/admin/input/library/{{data.pk}}/change">{{data.urlprefix}}/admin/input/library/{{data.pk}}/change</a>
|
||||
<a href="{{data.url_prefix}}/admin/input/library/{{data.pk}}/change">{{data.url_prefix}}/admin/input/library/{{data.pk}}/change</a>
|
||||
{% elif data.choice == 'ELIT'%}
|
||||
<a href="{{data.urlprefix}}/admin/input/library/{{data.pk}}/change">{{data.urlprefix}}/admin/input/library/{{data.pk}}/change</a>
|
||||
<a href="{{data.url_prefix}}/admin/input/library/{{data.pk}}/change">{{data.url_prefix}}/admin/input/library/{{data.pk}}/change</a>
|
||||
{% elif data.choice == 'LIT'%}
|
||||
<a href="{{data.urlprefix}}/admin/input/literature/{{data.pk}}/change">{{data.urlprefix}}/admin/input/literature/{{data.pk}}/change</a>
|
||||
<a href="{{data.url_prefix}}/admin/input/literature/{{data.pk}}/change">{{data.url_prefix}}/admin/input/literature/{{data.pk}}/change</a>
|
||||
{% elif data.choice == 'MAIL'%}
|
||||
<a href="{{data.urlprefix}}/admin/input/email/{{data.pk}}/change">{{data.urlprefix}}/admin/input/email/{{data.pk}}/change</a>
|
||||
<a href="{{data.url_prefix}}/admin/input/email/{{data.pk}}/change">{{data.url_prefix}}/admin/input/email/{{data.pk}}/change</a>
|
||||
{% elif data.choice == 'IFG'%}
|
||||
<a href="{{data.urlprefix}}/admin/input/ifg/{{data.pk}}/change">{{data.urlprefix}}/admin/input/ifg/{{data.pk}}/change</a>
|
||||
<a href="{{data.url_prefix}}/admin/input/ifg/{{data.pk}}/change">{{data.url_prefix}}/admin/input/ifg/{{data.pk}}/change</a>
|
||||
{% elif data.choice == 'LIST'%}
|
||||
<a href="{{data.urlprefix}}/admin/input/list/{{data.pk}}/change">{{data.urlprefix}}/admin/input/list/{{data.pk}}/change</a>
|
||||
<a href="{{data.url_prefix}}/admin/input/list/{{data.pk}}/change">{{data.url_prefix}}/admin/input/list/{{data.pk}}/change</a>
|
||||
{% elif data.choice == 'TRAV'%}
|
||||
<a href="{{data.urlprefix}}/admin/input/travel/{{data.pk}}/change">{{data.urlprefix}}/admin/input/travel/{{data.pk}}/change</a>
|
||||
<a href="{{data.url_prefix}}/admin/input/travel/{{data.pk}}/change">{{data.url_prefix}}/admin/input/travel/{{data.pk}}/change</a>
|
||||
{% elif data.choice == 'SOFT'%}
|
||||
<a href="{{data.urlprefix}}/admin/input/library/{{data.pk}}/change">{{data.urlprefix}}/admin/input/library/{{data.pk}}/change</a>
|
||||
<a href="{{data.url_prefix}}/admin/input/library/{{data.pk}}/change">{{data.url_prefix}}/admin/input/library/{{data.pk}}/change</a>
|
||||
{% elif data.choice == 'VIS'%}
|
||||
<a href="{{data.urlprefix}}/admin/input/businesscard/{{data.pk}}/change">{{data.urlprefix}}/admin/input/businesscard/{{data.pk}}/change</a>
|
||||
<a href="{{data.url_prefix}}/admin/input/businesscard/{{data.pk}}/change">{{data.url_prefix}}/admin/input/businesscard/{{data.pk}}/change</a>
|
||||
{% endif %}
|
||||
<br><br>
|
||||
|
||||
Zum Genehmigen hier klicken: <a href="{{data.urlprefix}}{% url 'authorize' data.choice data.pk %}">{{data.urlprefix}}{% url 'authorize' data.choice data.pk %}</a>
|
||||
Zum Genehmigen hier klicken: <a href="{{data.url_prefix}}{% url 'authorize' data.choice data.pk %}">{{data.url_prefix}}{% url 'authorize' data.choice data.pk %}</a>
|
||||
<br><br>
|
||||
Zu Ablehnen hier klicken: <a href="{{data.urlprefix}}{% url 'deny' data.choice data.pk %}">{{data.urlprefix}}{% url 'deny' data.choice data.pk %}</a>
|
||||
Zu Ablehnen hier klicken: <a href="{{data.url_prefix}}{% url 'deny' data.choice data.pk %}">{{data.url_prefix}}{% url 'deny' data.choice data.pk %}</a>
|
||||
<br><br>
|
||||
Stets zu Diensten, Deine Förderdatenbank
|
||||
|
||||
|
|
|
|||
|
|
@ -25,28 +25,28 @@ Sendungsadrese: {{data.send_to}} {% endif %}
|
|||
|
||||
Zum Eintrag in der Förderdatenbank:
|
||||
{% if data.choice == 'BIB' %}
|
||||
<a href="{{data.urlprefix}}/admin/input/library/{{data.pk}}/change">{{data.urlprefix}}/admin/input/library/{{data.pk}}/change</a>
|
||||
<a href="{{data.url_prefix}}/admin/input/library/{{data.pk}}/change">{{data.url_prefix}}/admin/input/library/{{data.pk}}/change</a>
|
||||
{% elif data.choice == 'ELIT'%}
|
||||
<a href="{{data.urlprefix}}/admin/input/library/{{data.pk}}/change">{{data.urlprefix}}/admin/input/library/{{data.pk}}/change</a>
|
||||
<a href="{{data.url_prefix}}/admin/input/library/{{data.pk}}/change">{{data.url_prefix}}/admin/input/library/{{data.pk}}/change</a>
|
||||
{% elif data.choice == 'LIT'%}
|
||||
<a href="{{data.urlprefix}}/admin/input/literature/{{data.pk}}/change">{{data.urlprefix}}/admin/input/literature/{{data.pk}}/change</a>
|
||||
<a href="{{data.url_prefix}}/admin/input/literature/{{data.pk}}/change">{{data.url_prefix}}/admin/input/literature/{{data.pk}}/change</a>
|
||||
{% elif data.choice == 'MAIL'%}
|
||||
<a href="{{data.urlprefix}}/admin/input/email/{{data.pk}}/change">{{data.urlprefix}}/admin/input/email/{{data.pk}}/change</a>
|
||||
<a href="{{data.url_prefix}}/admin/input/email/{{data.pk}}/change">{{data.url_prefix}}/admin/input/email/{{data.pk}}/change</a>
|
||||
{% elif data.choice == 'IFG'%}
|
||||
<a href="{{data.urlprefix}}/admin/input/ifg/{{data.pk}}/change">{{data.urlprefix}}/admin/input/ifg/{{data.pk}}/change</a>
|
||||
<a href="{{data.url_prefix}}/admin/input/ifg/{{data.pk}}/change">{{data.url_prefix}}/admin/input/ifg/{{data.pk}}/change</a>
|
||||
{% elif data.choice == 'LIST'%}
|
||||
<a href="{{data.urlprefix}}/admin/input/list/{{data.pk}}/change">{{data.urlprefix}}/admin/input/list/{{data.pk}}/change</a>
|
||||
<a href="{{data.url_prefix}}/admin/input/list/{{data.pk}}/change">{{data.url_prefix}}/admin/input/list/{{data.pk}}/change</a>
|
||||
{% elif data.choice == 'TRAV'%}
|
||||
<a href="{{data.urlprefix}}/admin/input/travel/{{data.pk}}/change">{{data.urlprefix}}/admin/input/travel/{{data.pk}}/change</a>
|
||||
<a href="{{data.url_prefix}}/admin/input/travel/{{data.pk}}/change">{{data.url_prefix}}/admin/input/travel/{{data.pk}}/change</a>
|
||||
{% elif data.choice == 'SOFT'%}
|
||||
<a href="{{data.urlprefix}}/admin/input/library/{{data.pk}}/change">{{data.urlprefix}}/admin/input/library/{{data.pk}}/change</a>
|
||||
<a href="{{data.url_prefix}}/admin/input/library/{{data.pk}}/change">{{data.url_prefix}}/admin/input/library/{{data.pk}}/change</a>
|
||||
{% elif data.choice == 'VIS'%}
|
||||
<a href="{{data.urlprefix}}/admin/input/businesscard/{{data.pk}}/change">{{data.urlprefix}}/admin/input/businesscard/{{data.pk}}/change</a>
|
||||
<a href="{{data.url_prefix}}/admin/input/businesscard/{{data.pk}}/change">{{data.url_prefix}}/admin/input/businesscard/{{data.pk}}/change</a>
|
||||
{% endif %}
|
||||
|
||||
|
||||
Zum Genehmigen hier klicken: {{data.urlprefix}}{% url 'authorize' data.choice data.pk %}
|
||||
Zum Genehmigen hier klicken: {{data.url_prefix}}{% url 'authorize' data.choice data.pk %}
|
||||
|
||||
Zu Ablehnen hier klicken: {{data.urlprefix}}{% url 'deny' data.choice data.pk %}
|
||||
Zu Ablehnen hier klicken: {{data.url_prefix}}{% url 'deny' data.choice data.pk %}
|
||||
|
||||
Stets zu Diensten, Deine Förderdatenbank
|
||||
|
|
|
|||
|
|
@ -1,69 +1,38 @@
|
|||
{% load static %}
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'admin/css/base.css' %}" />
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'admin/css/widgets.css' %}" />
|
||||
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% csrf_token %}
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'admin/css/base.css' %}"/>
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'admin/css/widgets.css' %}"/>
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'css/base.css' %}"/>
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'css/button.css' %}">
|
||||
|
||||
|
||||
<center>
|
||||
<style>
|
||||
ul > li {
|
||||
list-style-type: none;
|
||||
}
|
||||
ul {
|
||||
padding-left: 10;
|
||||
}
|
||||
label.required::after {
|
||||
content: ' *';
|
||||
color: red;
|
||||
}
|
||||
.div15 {
|
||||
height: 15%;
|
||||
}
|
||||
.div5 {
|
||||
height: 5%;
|
||||
}
|
||||
.button1 {
|
||||
width: 40vw;
|
||||
height: 6vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-weight: bold;
|
||||
font-size: 4vh;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div class="div5"></div>
|
||||
<p>
|
||||
Herzlich willkommen im Förderanfrageportal von Wikimedia Deutschland!
|
||||
</p>
|
||||
<div class="div5"></div>
|
||||
<!-- <a href="http://fdb-devel.wikimedia.de/extern"style="float:right;padding-right:10%;">OAUTH</a>
|
||||
<a href="http://fdb-devel.wikimedia.de/extern" style="float:left;padding-left:10%;">OAUTH</a> -->
|
||||
<p>
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/c/c4/Figuren_klein.jpg"><p>
|
||||
Um eine Unterstützungsleistung im Rahmen der Förderangebote anfragen zu können, verifiziere dich bitte mit deinem Wikimedia-Konto.
|
||||
<br>Weitere Informationen und Hintergründe findest du unter
|
||||
<a href="https://de.wikipedia.org/wiki/Wikipedia:Förderung/Förderangebote">
|
||||
<div class="page-centered">
|
||||
<div class="spacer-5"></div>
|
||||
<p role="heading" aria-level="1">
|
||||
Herzlich willkommen im Förderanfrageportal von Wikimedia Deutschland!
|
||||
</p>
|
||||
<div class="spacer-5"></div>
|
||||
<p>
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/c/c4/Figuren_klein.jpg">
|
||||
</p>
|
||||
<p>
|
||||
Um eine Unterstützungsleistung im Rahmen der Förderangebote anfragen zu können, verifiziere dich bitte mit
|
||||
deinem Wikimedia-Konto.
|
||||
<br>Weitere Informationen und Hintergründe findest du unter
|
||||
<a href="https://de.wikipedia.org/wiki/Wikipedia:Förderung/Förderangebote">
|
||||
Förderportal</a> in der deutschsprachigen Wikipedia.
|
||||
<p>
|
||||
<div class="div5"></div>
|
||||
<div class="button button1"><a href="/extern"><div class="button1_text">Anmelden</div></a></div>
|
||||
<div class="div5"></div>
|
||||
<div class="div5"></div>
|
||||
<br>Für alle Fragen wende dich gern an das <a href="https://de.wikipedia.org/wiki/Wikipedia:Förderung/Wikimedia_Deutschland">Team Communitys und Engagement</a>.
|
||||
<br>Für interessierte Hacker gibts auch den <a href="https://srcsrv.wikimedia.de/beba/foerderbarometer">Sourcecode</a> zum Formular und was damit passiert.
|
||||
<p>
|
||||
</p>
|
||||
<div class="spacer-5"></div>
|
||||
<a href="/extern" class="button button-login">Anmelden</a>
|
||||
<div class="spacer-5"></div>
|
||||
<div class="spacer-5"></div>
|
||||
<br>Für alle Fragen wende dich gern an das <a
|
||||
href="https://de.wikipedia.org/wiki/Wikipedia:Förderung/Wikimedia_Deutschland">Team Communitys und
|
||||
Engagement</a>.
|
||||
<br>Für interessierte Hacker gibts auch den <a
|
||||
href="https://srcsrv.wikimedia.de/beba/foerderbarometer">Sourcecode</a> zum Formular und was damit passiert.
|
||||
<p>
|
||||
<a href="https://www.wikimedia.de/impressum/">Impressum</a>
|
||||
<p>
|
||||
</center>
|
||||
|
||||
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Projektförderung ab 1.000,— EUR</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Projektförderung mit einer Gesamtsumme ab 1.000,— EUR</h1>
|
||||
<p>Für Projektförderungen ab 1.000,— EUR ist ein öffentlicher Projektplan erforderlich.</p>
|
||||
<p><em>Dummy-Content – wird bei Freigabe ersetzt.</em></p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -34,7 +34,7 @@ Förderprogramme im Sinne der Communitys weiter zu verbessern. Wir freuen uns,
|
|||
wenn du dir kurz die Zeit dafür nehmen würdest. Die Umfrage mit weiteren
|
||||
Informationen findest du unter dem folgenden Link:<br>
|
||||
|
||||
<a href="{{SURVEYPREFIX}}{% if type == 'PRO' %}O{% else %}I{% endif %}=1&{{pid}}=1">{{SURVEYPREFIX}}{% if type == 'PRO' %}O{% else %}I{% endif %}=1&{{pid}}=1</a><br><br>
|
||||
<a href="{{SURVEY_PREFIX}}{% if type == 'PRO' %}O{% else %}I{% endif %}=1&{{pid}}=1">{{SURVEY_PREFIX}}{% if type == 'PRO' %}O{% else %}I{% endif %}=1&{{pid}}=1</a><br><br>
|
||||
|
||||
Da dies eine automatisch erzeugte Nachricht ist, wende dich bei Rückfragen zur Umfrage bitte an <a href="mailto: community@wikimedia.de">community@wikimedia.de</a>
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,6 @@ Förderprogramme im Sinne der Communitys weiter zu verbessern. Wir freuen uns,
|
|||
wenn du dir kurz die Zeit dafür nehmen würdest. Die Umfrage mit weiteren
|
||||
Informationen findest du unter dem folgenden Link:
|
||||
|
||||
{{SURVEYPREFIX}}{% if type == 'PRO' %}O{% else %}I{% endif %}=1&{{pid}}=1
|
||||
{{SURVEY_PREFIX}}{% if type == 'PRO' %}O{% else %}I{% endif %}=1&{{pid}}=1
|
||||
|
||||
Da dies eine automatisch erzeugte Nachricht ist, wende dich bei Rückfragen zur Umfrage bitte an community@wikimedia.de
|
||||
|
|
|
|||
155
input/tests.py
155
input/tests.py
|
|
@ -1,155 +0,0 @@
|
|||
from django.test import TestCase, Client
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.http import HttpResponse
|
||||
from datetime import date
|
||||
|
||||
from .models import HonoraryCertificate, Project, Account, Literature
|
||||
from .forms import LibraryForm
|
||||
|
||||
class TestWithoutLogin(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
#this setting supress an unwanted warning about missing root dir
|
||||
settings.WHITENOISE_AUTOREFRESH = True
|
||||
self.client = Client()
|
||||
|
||||
def test_set_granted(self):
|
||||
'''test if the model function set_granted() works as intended'''
|
||||
obj = HonoraryCertificate.objects.create(realname='hurzel',email='hurzel@web.de')
|
||||
self.assertEqual(obj.granted,None)
|
||||
HonoraryCertificate.set_granted(obj.pk, True)
|
||||
obj2 = HonoraryCertificate.objects.get(pk=obj.pk)
|
||||
self.assertEqual(obj2.granted,True)
|
||||
|
||||
def test_source_link(self):
|
||||
'''test if link to source code is included in main page'''
|
||||
response = self.client.get('', follow=True)
|
||||
#print (response.content)
|
||||
self.assertContains(response,'<a href="https://srcsrv.wikimedia.de/beba/foerderbarometer">Sourcecode</a>')
|
||||
|
||||
def test_access_denied(self):
|
||||
'''test if /intern redirects to login page if not logged in'''
|
||||
response = self.client.get('/intern', follow=True)
|
||||
self.assertContains(response,'password')
|
||||
|
||||
def _postform(self, data, expected_form):
|
||||
'''helper function to manage the Wizzard'''
|
||||
response = self.client.post('/', data, follow=False)
|
||||
self.assertEqual(200, self.response.status_code)
|
||||
if not type(response) == HttpResponse:
|
||||
if 'form' in response.context:
|
||||
print('CONTENT')
|
||||
print(response.content)
|
||||
print('ITEMS')
|
||||
print(response.items())
|
||||
print('DATA')
|
||||
print(data)
|
||||
self.assertFalse(response.context['form'].errors)
|
||||
else:
|
||||
if expected_form:
|
||||
print(response.context)
|
||||
raise BaseException("NO FORM FOUND")
|
||||
else:
|
||||
self.assertContains(response,"Deine Anfrage wurde gesendet.")
|
||||
self.assertEqual(
|
||||
type(response.context['wizard']['form']),
|
||||
expected_form
|
||||
)
|
||||
return response
|
||||
|
||||
def _notest_bib(self): # renamed because not working
|
||||
'''full run through the forms to check Bibliotheksstipendium'''
|
||||
self.response = self.client.get('/')
|
||||
self.assertEqual(200, self.response.status_code)
|
||||
|
||||
print("\n\nEINS EINS\n\n")
|
||||
|
||||
response = self._postform({
|
||||
'extern_view-current_step': '0',
|
||||
'0-realname': 'vladimir reiherzehe',
|
||||
'0-email': 'vlre@wikimedia.de',
|
||||
'0-username': 'stoffel',
|
||||
'0-choice': 'BIB',
|
||||
'0-check': True
|
||||
}, LibraryForm)
|
||||
|
||||
print("\n\nZWEI ZWEI\n\n")
|
||||
|
||||
response = self._postform({
|
||||
'extern_view-current_step': '1',
|
||||
'1-cost': 'teuroooo!',
|
||||
'1-duration': 'looooong',
|
||||
'1-library': 'of congress',
|
||||
}, None)
|
||||
|
||||
|
||||
|
||||
class TestWithLogin(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
User.objects.create_superuser('testuser', 'nomail@nomail.com', 'testpasswd')
|
||||
self.client = Client()
|
||||
self.user = User.objects.create_user('vladimir', 'vladimir@reiherzehe.com', 'reiherzehe')
|
||||
|
||||
def test_access(self):
|
||||
'''test if /intern gives an answer'''
|
||||
self.assertEqual(self.client.login(username='testuser', password='testpasswd'), True)
|
||||
response = self.client.get('/intern')
|
||||
self.assertContains(response,'Übersicht aller Förderangebote')
|
||||
|
||||
def test_project_of_year(self):
|
||||
''' test if the finance id is resettet ad start of year'''
|
||||
acc = Account.objects.create()
|
||||
acc.code='1234'
|
||||
acc.description='blabla'
|
||||
acc.save()
|
||||
startdate = date(2022,1,1)
|
||||
obj = Project.objects.create(account= acc, name='testproject', start=startdate)
|
||||
self.assertEqual(obj.project_of_year,1)
|
||||
|
||||
obj2 = Project.objects.create(account= acc, name='testproject2', start=startdate)
|
||||
self.assertEqual(obj2.project_of_year,2)
|
||||
|
||||
olddate = date(2021,12,31)
|
||||
obj4 = Project.objects.create(account= acc, name='testproject2', start=olddate)
|
||||
|
||||
obj3 = Project.objects.create(account= acc, name='testproject2', start=startdate)
|
||||
self.assertEqual(obj3.project_of_year,3)
|
||||
|
||||
def test_finance_id(self):
|
||||
''' test if the finance counting is correct'''
|
||||
acc = Account.objects.create(code='1234', description='blabla')
|
||||
startdate = date(2022,1,1)
|
||||
obj = Project.objects.create(account= acc, name='testproject', start=startdate)
|
||||
self.assertEqual(obj.finance_id,"1234001")
|
||||
|
||||
obj2 = Project.objects.create(account= acc, name='testproject2', start=startdate)
|
||||
self.assertEqual(obj2.finance_id,"1234002")
|
||||
|
||||
olddate = date(2021,12,31)
|
||||
obj4 = Project.objects.create(account= acc, name='testproject2', start=olddate)
|
||||
|
||||
obj3 = Project.objects.create(account= acc, name='testproject2', start=startdate)
|
||||
self.assertEqual(obj3.finance_id,"1234003")
|
||||
|
||||
# def test_pid(self):
|
||||
# ''' test if the pid counting is correct '''
|
||||
# acc = Account.objects.create(code='1234', description='blabla')
|
||||
# startdate = date(2022,1,1)
|
||||
# obj = Project.objects.create(account= acc, name='testproject', start=startdate)
|
||||
# self.assertEqual(obj.pid,"1234001")
|
||||
# self.assertEqual(obj.account.code,"1234")
|
||||
#
|
||||
# obj2 = Project.objects.create(account= acc, name='testproject2', start=startdate)
|
||||
# self.assertEqual(obj2.pid,"1234002")
|
||||
#
|
||||
# olddate = date(2021,12,31)
|
||||
# obj4 = Project.objects.create(account= acc, name='testproject2', start=olddate)
|
||||
#
|
||||
# obj3 = Project.objects.create(account= acc, name='testproject2', start=startdate)
|
||||
# self.assertEqual(obj3.pid,"1234004")
|
||||
|
||||
def test_literature(self):
|
||||
obj = Literature.objects.create(cost='100', notes='jolo')
|
||||
self.assertEqual(obj.service_id,'Literature1')
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
from .models import ModelTestCase
|
||||
from .views import AuthenticatedViewTestCase, AnonymousViewTestCase
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
from datetime import date
|
||||
from unittest import skip
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
from input.models import HonoraryCertificate, Project, Account, Literature
|
||||
|
||||
|
||||
class ModelTestCase(TestCase):
|
||||
|
||||
def test_set_granted(self):
|
||||
'''test if the model function set_granted() works as intended'''
|
||||
obj = HonoraryCertificate.objects.create(realname='hurzel',email='hurzel@web.de')
|
||||
self.assertEqual(obj.granted,None)
|
||||
HonoraryCertificate.set_granted(obj.pk, True)
|
||||
obj2 = HonoraryCertificate.objects.get(pk=obj.pk)
|
||||
self.assertEqual(obj2.granted,True)
|
||||
|
||||
def test_project_of_year(self):
|
||||
''' test if the finance id is resettet ad start of year'''
|
||||
acc = Account.objects.create()
|
||||
acc.code='1234'
|
||||
acc.description='blabla'
|
||||
acc.save()
|
||||
startdate = date(2022,1,1)
|
||||
obj = Project.objects.create(account= acc, name='testproject', start=startdate)
|
||||
self.assertEqual(obj.project_of_year,1)
|
||||
|
||||
obj2 = Project.objects.create(account= acc, name='testproject2', start=startdate)
|
||||
self.assertEqual(obj2.project_of_year,2)
|
||||
|
||||
olddate = date(2021,12,31)
|
||||
obj4 = Project.objects.create(account= acc, name='testproject2', start=olddate)
|
||||
|
||||
obj3 = Project.objects.create(account= acc, name='testproject2', start=startdate)
|
||||
self.assertEqual(obj3.project_of_year,3)
|
||||
|
||||
@skip('Finance ID generation has been changed and this test has not been adapted accordingly.')
|
||||
def test_finance_id(self):
|
||||
''' test if the finance counting is correct'''
|
||||
acc = Account.objects.create(code='1234', description='blabla')
|
||||
startdate = date(2022,1,1)
|
||||
obj = Project.objects.create(account= acc, name='testproject', start=startdate)
|
||||
self.assertEqual(obj.finance_id,"1234001")
|
||||
|
||||
obj2 = Project.objects.create(account= acc, name='testproject2', start=startdate)
|
||||
self.assertEqual(obj2.finance_id,"1234002")
|
||||
|
||||
olddate = date(2021,12,31)
|
||||
obj4 = Project.objects.create(account= acc, name='testproject2', start=olddate)
|
||||
|
||||
obj3 = Project.objects.create(account= acc, name='testproject2', start=startdate)
|
||||
self.assertEqual(obj3.finance_id,"1234003")
|
||||
|
||||
# def test_pid(self):
|
||||
# ''' test if the pid counting is correct '''
|
||||
# acc = Account.objects.create(code='1234', description='blabla')
|
||||
# startdate = date(2022,1,1)
|
||||
# obj = Project.objects.create(account= acc, name='testproject', start=startdate)
|
||||
# self.assertEqual(obj.pid,"1234001")
|
||||
# self.assertEqual(obj.account.code,"1234")
|
||||
#
|
||||
# obj2 = Project.objects.create(account= acc, name='testproject2', start=startdate)
|
||||
# self.assertEqual(obj2.pid,"1234002")
|
||||
#
|
||||
# olddate = date(2021,12,31)
|
||||
# obj4 = Project.objects.create(account= acc, name='testproject2', start=olddate)
|
||||
#
|
||||
# obj3 = Project.objects.create(account= acc, name='testproject2', start=startdate)
|
||||
# self.assertEqual(obj3.pid,"1234004")
|
||||
|
||||
def test_literature(self):
|
||||
obj = Literature.objects.create(cost='100', notes='jolo', selfbuy_give_data=False)
|
||||
self.assertEqual(obj.service_id, f'Literature{obj.id}')
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
from django.test import TestCase
|
||||
|
||||
from input.models import Library
|
||||
from input.utils.testing import create_superuser, login, request
|
||||
|
||||
|
||||
class AnonymousViewTestCase(TestCase):
|
||||
|
||||
def test_index(self):
|
||||
response = request(self, 'index')
|
||||
|
||||
self.assertContains(response,'<a href="https://srcsrv.wikimedia.de/beba/foerderbarometer">Sourcecode</a>')
|
||||
|
||||
def test_extern(self):
|
||||
request(self, 'extern')
|
||||
|
||||
@staticmethod
|
||||
def get_step_data(step, data):
|
||||
return {'extern_view-current_step': step, **data}
|
||||
|
||||
@classmethod
|
||||
def get_first_step_data(cls, choice):
|
||||
return cls.get_step_data(0, {
|
||||
'0-realname': 'Test',
|
||||
'0-email': 'test@example.com',
|
||||
'0-choice': choice,
|
||||
'0-check': True,
|
||||
})
|
||||
|
||||
def helper_extern(self, choice, text, data):
|
||||
first_step_data = self.get_first_step_data(choice)
|
||||
|
||||
response = request(self, 'extern', data=first_step_data)
|
||||
|
||||
self.assertContains(response, text)
|
||||
|
||||
second_step_data = self.get_step_data(1, data)
|
||||
|
||||
response = request(self, 'extern', data=second_step_data)
|
||||
|
||||
self.assertContains(response, 'Deine Anfrage wurde gesendet.')
|
||||
|
||||
def test_extern_first_steps(self):
|
||||
types = [
|
||||
('BIB', 'Bibliotheksausweis'),
|
||||
('ELIT', 'Online-Ressource'),
|
||||
('MAIL', 'Mailadresse beantragen'),
|
||||
('IFG', 'gewonnenen Informationen'),
|
||||
('LIT', 'Literatur verwenden'),
|
||||
('LIST', 'Mailingliste beantragen'),
|
||||
('TRAV', 'Transportmittel'),
|
||||
('SOFT', 'Lizenz'),
|
||||
('VIS', 'DIN 5008'),
|
||||
]
|
||||
|
||||
for choice, text in types:
|
||||
with self.subTest(type=choice):
|
||||
self.client.session.clear()
|
||||
|
||||
data = self.get_first_step_data(choice)
|
||||
response = request(self, 'extern', data=data)
|
||||
|
||||
self.assertContains(response, text)
|
||||
|
||||
def test_extern_travel(self):
|
||||
self.helper_extern('TRAV', 'Transportmittel', {
|
||||
'project_name': 'Test',
|
||||
'transport': 'BAHN',
|
||||
'travelcost': 10,
|
||||
'checkin': '2025-01-01',
|
||||
'checkout': '2025-01-02',
|
||||
'hotel': 'TRUE',
|
||||
'notes': '',
|
||||
})
|
||||
|
||||
def test_extern_lit(self):
|
||||
self.helper_extern('LIT', 'Literatur verwenden', {
|
||||
'cost': 20,
|
||||
'info': 'Test',
|
||||
'source': 'Test',
|
||||
'notes': '',
|
||||
'selfbuy': 'TRUE',
|
||||
'selfbuy_data': 'NONE',
|
||||
'selfbuy_give_data': True,
|
||||
'check': True,
|
||||
})
|
||||
|
||||
def test_extern_bib(self):
|
||||
self.helper_extern('BIB', 'Bibliotheksausweis', {
|
||||
'cost': 20,
|
||||
'library': 'Test',
|
||||
'duration': 'Test',
|
||||
'notes': '',
|
||||
})
|
||||
|
||||
|
||||
class AuthenticatedViewTestCase(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.user = create_superuser('staff')
|
||||
|
||||
def setUp(self):
|
||||
login(self)
|
||||
|
||||
def test_export(self):
|
||||
request(self, 'export')
|
||||
|
||||
def helper_auth_deny(self, view, expected):
|
||||
obj = Library.objects.create(library='Test')
|
||||
|
||||
request(self, view, args=[obj.type, obj.id])
|
||||
|
||||
obj.refresh_from_db(fields=['granted'])
|
||||
|
||||
self.assertEqual(obj.granted, expected)
|
||||
|
||||
def helper_auth_deny_error(self, view):
|
||||
response = request(self, view, args=['TEST', 1])
|
||||
|
||||
self.assertContains(response, 'ERROR')
|
||||
|
||||
def test_authorize(self):
|
||||
self.helper_auth_deny('authorize', True)
|
||||
|
||||
def test_authorize_error(self):
|
||||
self.helper_auth_deny_error('authorize')
|
||||
|
||||
def test_deny(self):
|
||||
self.helper_auth_deny('deny', False)
|
||||
|
||||
def test_deny_error(self):
|
||||
self.helper_auth_deny_error('deny')
|
||||
|
|
@ -1,14 +1,15 @@
|
|||
from django.urls import path
|
||||
from .views import ExternView, index, done, authorize, deny, InternView, export
|
||||
from django.contrib import admin
|
||||
from django.views.generic import TemplateView
|
||||
from .views import ExternView, index, done, authorize, deny, export
|
||||
|
||||
urlpatterns = [
|
||||
path('', index, name='index'),
|
||||
path('extern', ExternView.as_view(), name='extern'),
|
||||
# path('intern', InternView.as_view(), name='intern'),
|
||||
path('admin/', admin.site.urls),
|
||||
path('saved', done, name='done'),
|
||||
path('export', export, name='export'),
|
||||
path('authorize/<str:choice>/<int:pk>', authorize, name='authorize'),
|
||||
path('deny/<str:choice>/<int:pk>', deny, name='deny'),
|
||||
path('extern/info/projektfoerderung-ab-1000/',
|
||||
TemplateView.as_view(template_name='input/info_project_funding_gt_1000.html'),
|
||||
name="info-foerderprojekt-ab-1000"),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
YES_NO = {
|
||||
'y': True,
|
||||
'Y': True,
|
||||
'yes': True,
|
||||
'YES': True,
|
||||
'n': False,
|
||||
'N': False,
|
||||
'no': False,
|
||||
'NO': False,
|
||||
}
|
||||
|
||||
ZERO_ONE = {
|
||||
1: True,
|
||||
'1': True,
|
||||
0: False,
|
||||
'0': False,
|
||||
}
|
||||
|
||||
TRUE_FALSE = {
|
||||
True: True,
|
||||
'TRUE': True,
|
||||
'True': True,
|
||||
'true': True,
|
||||
't': True,
|
||||
False: False,
|
||||
'FALSE': False,
|
||||
'False': False,
|
||||
'false': False,
|
||||
'f': False,
|
||||
None: False,
|
||||
}
|
||||
|
||||
ON_OFF = {
|
||||
'on': True,
|
||||
'ON': True,
|
||||
'off': False,
|
||||
'OFF': False,
|
||||
}
|
||||
|
||||
TRUTHY = {
|
||||
**YES_NO,
|
||||
**ZERO_ONE,
|
||||
**TRUE_FALSE,
|
||||
**ON_OFF,
|
||||
}
|
||||
|
||||
|
||||
def ask(question, default=False, truthy=None):
|
||||
response = input(question).strip()
|
||||
|
||||
return (truthy or YES_NO).get(response, default)
|
||||
|
||||
|
||||
confirm = ask
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
import os
|
||||
|
||||
from .confirmation import TRUTHY
|
||||
|
||||
|
||||
def env(key, default=None, parser=None):
|
||||
value = os.environ.get(key)
|
||||
|
||||
if value is None:
|
||||
return default
|
||||
|
||||
if parser is None:
|
||||
if default is None:
|
||||
return value
|
||||
else:
|
||||
parser = type(default)
|
||||
|
||||
if parser is bool:
|
||||
return truthy(value, default)
|
||||
|
||||
return parser(value)
|
||||
|
||||
|
||||
def truthy(value, default=False):
|
||||
return TRUTHY.get(value, default)
|
||||
|
||||
|
||||
def password_validators(*validators):
|
||||
return list(_parse_password_validators(validators))
|
||||
|
||||
|
||||
def _parse_password_validators(validators):
|
||||
for validator in validators:
|
||||
if isinstance(validator, (tuple, list)):
|
||||
validator, options = validator
|
||||
else:
|
||||
validator, options = validator, {}
|
||||
|
||||
if '.' not in validator:
|
||||
validator = 'django.contrib.auth.password_validation.%s' % validator
|
||||
|
||||
yield dict(NAME=validator, OPTIONS=options)
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
from typing import Any, Iterable, Mapping, Union, Tuple, Protocol
|
||||
|
||||
from django.apps import apps
|
||||
from django.conf import settings
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.http.response import HttpResponseRedirectBase, StreamingHttpResponse
|
||||
from django.shortcuts import resolve_url
|
||||
from django.template import Context
|
||||
from django.template.response import TemplateResponse
|
||||
from django.test import Client, SimpleTestCase
|
||||
from django.urls import reverse, ResolverMatch
|
||||
from django.utils.http import urlencode
|
||||
|
||||
FormData = dict
|
||||
JSONDict = dict
|
||||
JSONList = list
|
||||
RequestData = Union[FormData, JSONDict, JSONList]
|
||||
QueryParams = Union[Mapping[str, Any], Iterable[Tuple[str, Any]]]
|
||||
|
||||
|
||||
class TestClientResponse(Protocol):
|
||||
client: Client
|
||||
request: HttpRequest
|
||||
templates: list
|
||||
context: Context
|
||||
resolver_match: ResolverMatch
|
||||
|
||||
def json(self) -> Union[JSONList, JSONDict]: ...
|
||||
|
||||
|
||||
Response = Union[
|
||||
HttpResponse,
|
||||
HttpResponseRedirectBase,
|
||||
StreamingHttpResponse,
|
||||
TemplateResponse,
|
||||
TestClientResponse,
|
||||
]
|
||||
|
||||
|
||||
class ObjectWithGetAbsoluteURLMethod(Protocol):
|
||||
|
||||
def get_absolute_url(self) -> str: ...
|
||||
|
||||
|
||||
URL = Union[str, ObjectWithGetAbsoluteURLMethod]
|
||||
URLArgs = Union[tuple, list]
|
||||
URLKwargs = dict
|
||||
|
||||
|
||||
def get_url(url: URL, args: URLArgs = None, kwargs: URLKwargs = None) -> str:
|
||||
"""
|
||||
Helper to reverse the given url name.
|
||||
"""
|
||||
|
||||
if args or kwargs:
|
||||
return reverse(url, args=args, kwargs=kwargs)
|
||||
|
||||
return resolve_url(url)
|
||||
|
||||
|
||||
def get_handler(test_case: SimpleTestCase, method: str = None, data=None):
|
||||
if data:
|
||||
method = str.lower(method or 'POST')
|
||||
else:
|
||||
method = str.lower(method or 'GET')
|
||||
|
||||
return getattr(test_case.client, method)
|
||||
|
||||
|
||||
def request(
|
||||
test_case: SimpleTestCase,
|
||||
url: URL,
|
||||
status_code: int = None,
|
||||
expected_url: URL = None,
|
||||
args: URLArgs = None,
|
||||
kwargs: URLKwargs = None,
|
||||
headers: dict = None,
|
||||
msg: str = None,
|
||||
query_params: QueryParams = None,
|
||||
method: str = None,
|
||||
data: RequestData = None,
|
||||
**options,
|
||||
) -> Response:
|
||||
"""
|
||||
A helper to make a request with the test case's http client.
|
||||
|
||||
The given args and kwargs are used to reverse the url
|
||||
but not the expected url. When expected url needs
|
||||
args/kwargs pass an absolute url instead.
|
||||
|
||||
All additional kwargs are passed as post parameters.
|
||||
When posting without parameters just pass post=True.
|
||||
"""
|
||||
|
||||
data = data or options or None
|
||||
handler = get_handler(test_case, method, data)
|
||||
url = get_url(url, args, kwargs)
|
||||
|
||||
if query_params:
|
||||
url = f'{url}?%s' % urlencode(query_params, doseq=True)
|
||||
|
||||
headers = headers or {}
|
||||
status_code = status_code or 200
|
||||
response = handler(url, data=data, **headers)
|
||||
msg = msg or getattr(response, 'content', None)
|
||||
|
||||
if expected_url:
|
||||
test_case.assertRedirects(
|
||||
response=response,
|
||||
expected_url=get_url(expected_url),
|
||||
target_status_code=status_code,
|
||||
)
|
||||
else:
|
||||
test_case.assertEqual(response.status_code, status_code, msg=msg)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def login(test_case: SimpleTestCase, user=None, password: str = None) -> bool:
|
||||
"""
|
||||
Logs in the user trying to use the raw password or the given password.
|
||||
Force logs in the user when no password is found.
|
||||
"""
|
||||
|
||||
user = user or getattr(test_case, 'user')
|
||||
password = password or getattr(user, 'raw_password', password)
|
||||
|
||||
if password is None:
|
||||
return test_case.client.force_login(user=user) or True
|
||||
|
||||
return test_case.client.login(username=user.username, password=password)
|
||||
|
||||
|
||||
def create_user(username: str, *, model=None, **kwargs):
|
||||
model = model or apps.get_model(settings.AUTH_USER_MODEL)
|
||||
password = kwargs.setdefault('password', 'P4sSW0rD')
|
||||
|
||||
kwargs.setdefault('email', f'{username}@test.case')
|
||||
kwargs.setdefault(model.USERNAME_FIELD, username)
|
||||
|
||||
user = model.objects.create_user(**kwargs)
|
||||
|
||||
user.raw_password = password
|
||||
|
||||
return user
|
||||
|
||||
|
||||
def create_superuser(username: str, **kwargs):
|
||||
kwargs['is_superuser'] = True
|
||||
kwargs['is_staff'] = True
|
||||
|
||||
return create_user(username, **kwargs)
|
||||
180
input/views.py
180
input/views.py
|
|
@ -1,67 +1,65 @@
|
|||
from datetime import date
|
||||
from smtplib import SMTPException
|
||||
|
||||
from django.shortcuts import render
|
||||
from django.forms import modelformset_factory
|
||||
from django.http import HttpResponse
|
||||
from django.utils.safestring import mark_safe
|
||||
from formtools.wizard.views import CookieWizardView
|
||||
from django.core.mail import send_mail, BadHeaderError, EmailMultiAlternatives
|
||||
from django.conf import settings
|
||||
from django.core.mail import BadHeaderError, EmailMultiAlternatives
|
||||
from django.template.loader import get_template
|
||||
from django.template import Context
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.utils.html import format_html
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from .forms import ProjectForm, ExternForm, LibraryForm, IFGForm, LiteratureForm,\
|
||||
HonoraryCertificateForm, InternForm, TravelForm, EmailForm,\
|
||||
ListForm, BusinessCardForm, INTERN_CHOICES
|
||||
from .models import Project, TYPE_CHOICES, Library, Literature, Travel, IFG, BusinessCard, Email, List
|
||||
from .settings import IF_EMAIL
|
||||
from .forms import (
|
||||
ExternForm,
|
||||
LibraryForm,
|
||||
ELiteratureForm,
|
||||
SoftwareForm,
|
||||
IFGForm,
|
||||
LiteratureForm,
|
||||
TravelForm,
|
||||
EmailForm,
|
||||
ListForm,
|
||||
BusinessCardForm,
|
||||
)
|
||||
from .models import TYPE_CHOICES, MODELS, TYPE_BIB, TYPE_ELIT, TYPE_SOFT
|
||||
|
||||
def auth_deny(choice,pk,auth):
|
||||
if choice in ('BIB', 'ELIT', 'SOFT'):
|
||||
Library.set_granted(pk,auth)
|
||||
elif choice == 'LIT':
|
||||
Literature.set_granted(pk,auth)
|
||||
elif choice == 'IFG':
|
||||
IFG.set_granted(pk,auth)
|
||||
elif choice == 'TRAV':
|
||||
Travel.set_granted(pk,auth)
|
||||
elif choice == 'VIS':
|
||||
BusinessCard.set_granted(pk,auth)
|
||||
elif choice == 'MAIL':
|
||||
Email.set_granted(pk,auth)
|
||||
elif choice == 'LIST':
|
||||
List.set_granted(pk,auth)
|
||||
else:
|
||||
LIBRARY_FORMS = {
|
||||
TYPE_BIB: LibraryForm,
|
||||
TYPE_ELIT: ELiteratureForm,
|
||||
TYPE_SOFT: SoftwareForm,
|
||||
}
|
||||
|
||||
|
||||
def auth_deny(choice, pk, auth):
|
||||
if choice not in MODELS:
|
||||
return HttpResponse(f'ERROR! UNKNOWN CHOICE TYPE! {choice}')
|
||||
return False
|
||||
|
||||
MODELS[choice].set_granted(pk, auth)
|
||||
|
||||
|
||||
@login_required
|
||||
def export(request):
|
||||
'''export the project database to a csv'''
|
||||
return HttpResponse('WE WANT CSV!')
|
||||
|
||||
|
||||
@login_required
|
||||
def authorize(request, choice, pk):
|
||||
'''If IF grant a support they click a link in a mail which leads here.
|
||||
We write the granted field in the database here and set a timestamp.'''
|
||||
|
||||
ret = auth_deny(choice, pk, True)
|
||||
if ret:
|
||||
if ret := auth_deny(choice, pk, True):
|
||||
return ret
|
||||
else:
|
||||
return HttpResponse(f"AUTHORIZED! choice: {choice}, pk: {pk}")
|
||||
|
||||
|
||||
@login_required
|
||||
def deny(request, choice, pk):
|
||||
'''If IF denies a support they click a link in a mail which leads here
|
||||
We write the granted field in the database here.'''
|
||||
|
||||
ret = auth_deny(choice, pk, False)
|
||||
if ret:
|
||||
if ret := auth_deny(choice, pk, False):
|
||||
return ret
|
||||
else:
|
||||
return HttpResponse(f"DENIED! choice: {choice}, pk: {pk}")
|
||||
|
|
@ -70,95 +68,10 @@ def deny(request, choice, pk):
|
|||
def done(request):
|
||||
return HttpResponse("Deine Anfrage wurde gesendet. Du erhältst in Kürze eine E-Mail-Benachrichtigung mit deinen Angaben. Für alle Fragen kontaktiere bitte das Team Communitys und Engagement unter community@wikimedia.de.")
|
||||
|
||||
|
||||
def index(request):
|
||||
return render(request, 'input/index.html')
|
||||
|
||||
class InternView(LoginRequiredMixin, CookieWizardView):
|
||||
'''This View is for WMDE-employees only'''
|
||||
|
||||
template_name = 'input/extern.html'
|
||||
form_list = [InternForm, ProjectForm]
|
||||
|
||||
def get_form(self, step=None, data=None, files=None):
|
||||
'''this function determines which part of the multipart form is
|
||||
displayed next'''
|
||||
|
||||
if step is None:
|
||||
step = self.steps.current
|
||||
print ("get_form() step " + step)
|
||||
|
||||
if step == '1':
|
||||
prev_data = self.get_cleaned_data_for_step('0')
|
||||
choice = prev_data.get('choice')
|
||||
print(f'choice detection: {INTERN_CHOICES[choice]}')
|
||||
if choice == 'HON':
|
||||
form = HonoraryCertificateForm(data)
|
||||
elif choice == 'PRO':
|
||||
form = ProjectForm(data)
|
||||
elif choice == 'TRAV':
|
||||
form = TravelForm(data)
|
||||
else:
|
||||
raise RuntimeError(f'ERROR! UNKNOWN FORMTYPE {choice} in InternView')
|
||||
self.choice = choice
|
||||
else:
|
||||
form = super().get_form(step, data, files)
|
||||
form.fields['realname'].help_text = format_html("Vor- und Zuname (Realname), Wer hat das Projekt beantragt?<br>\
|
||||
Wer ist Hauptansprechperson? Bei WMDE-MAs immer „(WMDE)“,<br>\
|
||||
bei externen Partnern „(PART)“ hinzufügen.")
|
||||
return form
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
if hasattr(self, 'choice'):
|
||||
context["choice"] = INTERN_CHOICES[self.choice]
|
||||
return context
|
||||
|
||||
def done(self, form_list, **kwargs):
|
||||
print('InternView.done() reached')
|
||||
# gather data from all forms
|
||||
data = {}
|
||||
for form in form_list:
|
||||
data = {**data, **form.cleaned_data}
|
||||
|
||||
if data['choice'] == 'LIT':
|
||||
if data['selfbuy'] == 'TRUE':
|
||||
data['selfbuy_give_data'] = 'False'
|
||||
|
||||
# write data to database
|
||||
form = form.save(commit=False)
|
||||
# we have to copy the data from the first form here
|
||||
# this is ugly code. how can we copy this without explicit writing?
|
||||
# i found no way to access the ModelForm.Meta.exclude-tupel
|
||||
form.realname = data['realname']
|
||||
# form.username = data['username']
|
||||
form.email = data['email']
|
||||
form.granted = True
|
||||
form.granted_date = date.today()
|
||||
|
||||
if data['choice'] == 'LIT':
|
||||
form.selfbuy_give_data = data['selfbuy_give_data']
|
||||
|
||||
form.save()
|
||||
|
||||
return done(self.request)
|
||||
|
||||
# these where used as labels in the second form TYPE_CHOICES is used for the first form and the
|
||||
# text above the second form. only used for BIB, SOFT, ELIT in the moment
|
||||
LABEL_CHOICES = {'BIB': format_html('Bibliothek'),
|
||||
'ELIT': format_html('Datenbank/Online-Ressource'),
|
||||
'MAIL': format_html('E-Mail-Adresse'),
|
||||
'IFG': format_html('Kostenübernahme IFG-Anfrage'),
|
||||
'LIT': format_html('Literaturstipendium'),
|
||||
'LIST': format_html('Mailingliste'),
|
||||
'TRAV': format_html('Reisekosten'),
|
||||
'SOFT': format_html('Software'),
|
||||
'VIS': format_html('Visitenkarten'),
|
||||
}
|
||||
|
||||
HELP_CHOICES = {'BIB': format_html("In welchem Zeitraum möchtest du recherchieren oder<br>wie lange ist der Bibliotheksausweis gültig?"),
|
||||
'ELIT': "Wie lange gilt der Zugang?",
|
||||
'SOFT': "Wie lange gilt die Lizenz?",
|
||||
}
|
||||
|
||||
class ExternView(CookieWizardView):
|
||||
'''This View is for Volunteers'''
|
||||
|
|
@ -180,15 +93,12 @@ class ExternView(CookieWizardView):
|
|||
print(f'choice detection in ExternView: {TYPE_CHOICES[choice]}')
|
||||
if choice == 'IFG':
|
||||
form = IFGForm(data)
|
||||
form.fields['notes'].help_text = format_html("Bitte gib an, wie die gewonnenen Informationen den<br>Wikimedia-Projekten zugute kommen sollen.")
|
||||
elif choice in ('BIB', 'SOFT', 'ELIT'):
|
||||
form = LibraryForm(data)
|
||||
form.fields['library'].label = LABEL_CHOICES[choice]
|
||||
form.fields['library'].help_text = f"Für welche {LABEL_CHOICES[choice]} gilt das Stipendium?"
|
||||
form.fields['duration'].help_text = HELP_CHOICES[choice]
|
||||
form.fields['notes'].help_text = mark_safe("Bitte gib an, wie die gewonnenen Informationen den<br>Wikimedia-Projekten zugute kommen sollen.")
|
||||
elif choice in LIBRARY_FORMS:
|
||||
form = LIBRARY_FORMS[choice](data)
|
||||
elif choice == 'MAIL':
|
||||
form = EmailForm(data)
|
||||
form.fields['domain'].help_text = format_html("Mit welcher Domain, bzw. für welches Wikimedia-Projekt,<br>möchtest du eine Mailadresse beantragen?")
|
||||
form.fields['domain'].help_text = mark_safe("Mit welcher Domain, bzw. für welches Wikimedia-Projekt,<br>möchtest du eine Mailadresse beantragen?")
|
||||
elif choice == 'LIT':
|
||||
form = LiteratureForm(data)
|
||||
form.fields['notes'].help_text = "Bitte gib an, wofür du die Literatur verwenden möchtest."
|
||||
|
|
@ -196,10 +106,10 @@ class ExternView(CookieWizardView):
|
|||
form = BusinessCardForm(data)
|
||||
elif choice == 'LIST':
|
||||
form = ListForm(data)
|
||||
form.fields['domain'].help_text = format_html("Mit welcher Domain, bzw. für welches Wikimedia-Projekt,<br>möchtest du eine Mailingliste beantragen?")
|
||||
form.fields['domain'].help_text = mark_safe("Mit welcher Domain, bzw. für welches Wikimedia-Projekt,<br>möchtest du eine Mailingliste beantragen?")
|
||||
elif choice == 'TRAV':
|
||||
form = TravelForm(data)
|
||||
else:
|
||||
else: # pragma: no cover
|
||||
raise RuntimeError(f'ERROR! UNKNOWN FORMTYPE {choice} in ExternView')
|
||||
self.choice = choice
|
||||
else:
|
||||
|
|
@ -219,8 +129,6 @@ class ExternView(CookieWizardView):
|
|||
for form in form_list:
|
||||
data = {**data, **form.cleaned_data}
|
||||
|
||||
data['username'] = self.request.session['user']['username']
|
||||
|
||||
if data['choice'] == 'LIT':
|
||||
if data['selfbuy'] == 'TRUE':
|
||||
data['selfbuy_give_data'] = 'False'
|
||||
|
|
@ -233,8 +141,10 @@ class ExternView(CookieWizardView):
|
|||
if data['choice'] == 'LIT':
|
||||
modell.selfbuy_give_data = data['selfbuy_give_data']
|
||||
|
||||
if user := self.request.session.get('user'):
|
||||
modell.username = user['username']
|
||||
|
||||
modell.realname = data['realname']
|
||||
modell.username = data['username']
|
||||
modell.email = data['email']
|
||||
# write type of form in some cases
|
||||
if data['choice'] in ('BIB', 'ELIT', 'SOFT'):
|
||||
|
|
@ -244,7 +154,7 @@ class ExternView(CookieWizardView):
|
|||
|
||||
# add some data to context for mail templates
|
||||
data['pk'] = modell.pk
|
||||
data['urlprefix'] = settings.URLPREFIX
|
||||
data['url_prefix'] = settings.EMAIL_URL_PREFIX
|
||||
data['grant'] = ('LIT', 'SOFT', 'ELIT', 'BIB', 'IFG')
|
||||
data['DOMAIN'] = ('MAIL', 'LIST')
|
||||
data['typestring'] = TYPE_CHOICES[data['choice']]
|
||||
|
|
@ -257,7 +167,7 @@ class ExternView(CookieWizardView):
|
|||
txt_mail_template1 = get_template('input/ifg_volunteer_mail.txt')
|
||||
html_mail_template1 = get_template('input/ifg_volunteer_mail.html')
|
||||
|
||||
subject1, from_email1, to1 = 'Formular ausgefüllt', IF_EMAIL, data['email']
|
||||
subject1, from_email1, to1 = 'Formular ausgefüllt', settings.IF_EMAIL, data['email']
|
||||
text_content1 = txt_mail_template1.render(context)
|
||||
html_content1 = html_mail_template1.render(context)
|
||||
msg1 = EmailMultiAlternatives(subject1, text_content1, from_email1, [to1])
|
||||
|
|
@ -275,7 +185,7 @@ class ExternView(CookieWizardView):
|
|||
txt_mail_template = get_template('input/if_mail.txt')
|
||||
html_mail_template = get_template('input/if_mail.html')
|
||||
|
||||
subject, from_email, to = 'Formular ausgefüllt', IF_EMAIL, IF_EMAIL
|
||||
subject, from_email, to = 'Formular ausgefüllt', settings.IF_EMAIL, settings.IF_EMAIL
|
||||
text_content = txt_mail_template.render(context)
|
||||
html_content = html_mail_template.render(context)
|
||||
msg2 = EmailMultiAlternatives(subject, text_content, from_email, [to])
|
||||
|
|
|
|||
|
|
@ -1,20 +1,7 @@
|
|||
asgiref==3.2.10
|
||||
Authlib==1.2.1
|
||||
certifi==2023.7.22
|
||||
cffi==1.16.0
|
||||
chardet==5.2.0
|
||||
charset-normalizer==3.3.0
|
||||
cryptography==41.0.4
|
||||
Django==3.1.2
|
||||
django-formtools==2.4
|
||||
gunicorn==20.0.4
|
||||
idna==3.4
|
||||
mysqlclient==2.1.1
|
||||
pycparser==2.21
|
||||
pytz==2023.3.post1
|
||||
requests==2.31.0
|
||||
six==1.16.0
|
||||
sqlparse==0.4.3
|
||||
typing_extensions==4.8.0
|
||||
urllib3==2.0.6
|
||||
whitenoise==6.2.0
|
||||
Authlib==1.6.1
|
||||
Django==5.2.5
|
||||
django-formtools==2.5.1
|
||||
gunicorn==23.0.0
|
||||
mysqlclient==2.2.7
|
||||
python-dotenv==1.1.1
|
||||
whitenoise==6.9.0
|
||||
|
|
|
|||
Loading…
Reference in New Issue