WMDE
/
eva
forked from tohe/eva
7
1
Fork 0

Compare commits

..

71 Commits

Author SHA1 Message Date
Masin Wiedner 1cc2a50df8 documentation on how to use systemctl (or service)
Puppet deploys a service unit file so EVA can be started at boot time and logs go the journal instead of some logfile at some opaque location
2024-11-11 10:58:00 +00:00
Masin Wiedner a7774f6a41 max_length fix 2023-08-17 13:08:47 +02:00
Masin Wiedner b776c4811b Migrations für vorigen Commit erzeugt 2023-08-11 12:51:51 +02:00
Masin Wiedner ebe3cbedc6 Bereiche umbenannt
Das sollte https://otrs.wikimedia.de/otrs/index.pl?Action=AgentTicketZoom;TicketID=1314485 lösen. Angaben von Jens Behrend.
2023-08-09 15:25:14 +00:00
Masin Wiedner 371cb55544 Austausch Eileen gegen Anna Nölte 2023-04-06 12:29:02 +00:00
Tobias Herre 87e1d6b8f0 Added finance email 2022-05-25 16:06:22 +02:00
Benni Bärmann 1496e3d4b6 changes in production setting 2022-02-09 10:34:51 +01:00
Benni Bärmann c6dabb2213 add translation requirements to README 2022-02-08 12:59:20 +01:00
Benni Bärmann ff1aef386f removed done TODO 2022-02-08 10:57:40 +01:00
Benni Bärmann ad93ab5df1 longer team field 2022-02-08 10:56:46 +01:00
Benni Bärmann 361b6b497c translation of dataloop works now 2022-02-07 14:54:40 +01:00
Benni Bärmann f992d4cc00 mail translation added. test for dataloop translation added (failing) 2022-02-07 12:35:37 +01:00
Benni Bärmann c72b6bd025 translation fixes 2022-01-31 12:08:14 +01:00
Benni Bärmann 19559553b4 additional translations 2022-01-27 20:27:02 +01:00
Benni Bärmann 254ddd2496 translation work 2022-01-27 15:52:27 +01:00
Benni Bärmann 9802446e05 more translation work 2022-01-27 15:46:33 +01:00
Benni Bärmann 40bcae239a some more translation work 2022-01-27 13:36:01 +01:00
Benni Bärmann 22e33327fc added language testing for en (besides en-us) 2022-01-27 13:26:54 +01:00
Benni Bärmann 1cb419f73f in modells we use lazy translation 2022-01-26 15:54:27 +01:00
Benni Bärmann 82dd63a1b5 more translations 2022-01-26 13:29:21 +01:00
Benni Bärmann b94e471ae4 translation working in principle with dev settings 2022-01-25 11:42:13 +01:00
Benni Bärmann aec2fdac16 translation (not working actually) 2022-01-25 11:21:57 +01:00
Benni Bärmann b1b68ae68d added first translation test 2022-01-19 13:36:19 +01:00
Benni Bärmann 76abe007ec added job description to basic data 2021-12-22 10:57:58 +01:00
Benni Bärmann db581e3208 just another TODO change 2021-12-20 16:00:28 +01:00
Benni Bärmann f423f3c6b6 just TODO 2021-12-20 15:51:38 +01:00
Benni Bärmann 594389be0c just some TODO changes 2021-12-15 12:43:56 +01:00
Benni Bärmann 1979dd819b bur removed from TODO 2021-11-17 17:29:57 +01:00
Benni Bärmann 8d997e88f1 bugfix: mobile added to some mails 2021-11-17 16:29:27 +01:00
Benni Bärmann 9434752ebe polution from offboarding branch to master removed 2021-11-17 16:14:30 +01:00
Benni Bärmann b41f624a57 new test in master (?) 2021-11-17 16:12:06 +01:00
Benni Bärmann 4833038eff bugreport added 2021-11-15 12:35:47 +01:00
Benni Bärmann 476def4826 added department "kommunikation und events" 2021-10-14 12:22:30 +02:00
Benni Bärmann ed4d47dd40 firstname lastname added to mail subjects 2021-09-20 13:55:43 +02:00
Benni Bärmann 8cd195a336 test for mail sending added 2021-09-20 13:40:26 +02:00
Benni Bärmann 61523c32b2 walkthrough test completed 2021-09-20 12:15:13 +02:00
Benni Bärmann 5cda8400cc refactoring of formtools test code 2021-09-20 11:31:00 +02:00
Benni Bärmann 032245ae3b better test of debug warning 2021-09-20 10:28:53 +02:00
Benni Bärmann b0bdf31a2c more tests 2021-09-16 14:26:02 +02:00
Benni Bärmann db74d3db5e bugfix in test, better error handling in mail sending 2021-09-15 13:41:21 +02:00
Benni Bärmann 5e8c99354e changed support address 2021-09-14 13:13:47 +02:00
Benni Bärmann 20a38b5a82 mac os enforced with mac. test about this. bugfix: remore renamed and
switched in meaning
2021-09-14 12:59:18 +02:00
Benni Bärmann bbd1e7ff6d new test mac should have mac os 2021-09-14 11:58:22 +02:00
Benni Bärmann 4229928aae testmode warning 2021-09-14 09:58:41 +02:00
Benni Bärmann 39cee37be8 new test for not yet existing debug mode warning 2021-09-14 08:29:45 +02:00
Benni Bärmann 6becd8278b added login test 2021-09-14 07:17:36 +02:00
Benni Bärmann b1ba9e2cd0 migrations reset, first simple test 2021-09-13 15:32:16 +02:00
Benni Bärmann b7456ca77b minor TODO change 2021-09-09 11:57:00 +02:00
Benni Bärmann 4d11ce293f new wording for homeoffice and switch of Default 2021-09-09 11:55:16 +02:00
Benni Bärmann 0955751be3 ACCOUNT_EMAIL_REQUIRED = True not longer needed, TODO changed 2021-09-09 10:13:53 +02:00
Benni Bärmann 6bcb758952 documentation bugfix 2021-09-08 13:49:34 +02:00
Benni Bärmann 473f10cf43 some cleanup, bugfix: keyboard in it mail 2021-09-06 15:56:01 +02:00
Benni Bärmann 0d56626cb9 clean up of TODO 2021-08-30 14:27:51 +02:00
Benni Bärmann 24df9e4a93 bugfix in mail sending 2021-08-30 14:24:08 +02:00
Benni Bärmann 2b25c6d09d sim and intern removed, language => sprache 2021-05-26 15:09:40 +02:00
Benni Bärmann 0f55c8f82d added MacOS to OS choices 2021-05-18 10:57:11 +02:00
Benni Bärmann 6352064931 usermail fix in mail templates 2021-05-18 09:42:00 +02:00
Benni Bärmann 1b122d8f0d removed debug settings 2021-05-17 16:34:58 +02:00
Benni Bärmann 60d870ca8d merge migrations 2021-05-17 10:59:43 +00:00
Benni Bärmann aaba27551c getting email via oauth now. 2021-05-17 12:41:46 +02:00
Benni Bärmann f56c61fee9 new login page template 2021-05-17 10:34:21 +02:00
Benni Bärmann 3c6815fa6e logout on GET (there is no security risk here, we trust our users in this) 2021-05-17 09:54:08 +02:00
Benni Bärmann 780a5a0464 added logout link 2021-05-17 09:47:44 +02:00
Benni Bärmann 9854e42e9a allauth settings added to production 2021-05-11 12:22:04 +02:00
Benni Bärmann e4207af2ef bugfix for allauth 2021-05-11 10:34:25 +02:00
Benni Bärmann 54881f9b8b Merge branch 'simpleauth' 2021-05-06 16:19:58 +02:00
Benni Bärmann afcd73b287 broken version with nextcloud login 2021-03-10 12:20:48 +01:00
Benni Bärmann dccc85a5d1 use correct url with index.php for nextcloud in settings 2021-03-04 10:19:00 +01:00
Benni Bärmann cec488054e some more oauth settings, getting closer... 2021-03-03 15:05:27 +01:00
Benni Bärmann 132bb76ab5 more allauth-settings and a forgotten migration 2021-03-03 12:15:50 +01:00
Benni Bärmann d97d3f6ae0 settings for django-allauth added 2021-03-03 12:00:45 +01:00
38 changed files with 768 additions and 584 deletions

131
README.md
View File

@ -1,52 +1,79 @@
# eva
A simple tool for on- and offboarding people in a mid sized organisation.
"EVA" is an german acronym for "Eintritt, Veränderung, Austritt",
meaning "Onboarding, Change, Offboarding"
# development
- set up a virtual environment with virtualenvwrapper or some other
environment managing tool
- use this environment and do
pip install django django-multiselectfield django-formtools
- clone this repository
- initialise your database with
python manage.py migrate
- start your development server with
python manage.py runserver
# production
- you can use gunicorn as server for example instead of the django development server.
- we use whitenoise for serving static files
- we still use the development SQLITE database from django
do the following in the project main directory:
ln -sr eva/settings_production.py eva/settings.py
edit /secrets.json to contain something similar to
{
"SECRET_KEY": "THIS IS ANOTHER SECRET!"
}
run the following commands:
python3 manage.py migrate
python3 manage.py collectstatic
server starts with
nohup gunicorn --forwarded-allow-ips="*" -b '0:8000' eva.wsgi 2&> logfile &
# eva
A simple tool for on- and offboarding people in a mid sized organisation.
"EVA" is an german acronym for "Eintritt, Veränderung, Austritt",
meaning "Onboarding, Change, Offboarding"
# development
- install gettext for instance via `apt install gettext` for translations
- set up a virtual environment with virtualenvwrapper or some other environment managing tool
- use this environment and do
```
pip install django django-multiselectfield django-formtools django-allauth
```
- clone this repository
- `ln -sr eva/settings_development.py eva/settings.py`
- initialise your database with `python manage.py migrate`
- start your development server with `python manage.py runserver`
# oauth
- You need to add oauth information in the django backend via .../admin in "Social Accounts"
# production
- you can use gunicorn as server for example instead of the django development server.
- we use whitenoise for serving static files
- we still use the development SQLITE database from django
do the following in the project main directory:
```
ln -sr eva/settings_production.py eva/settings.py
```
edit /secrets.json to contain something similar to
```
{
"SECRET_KEY": "THIS IS ANOTHER SECRET!"
}
```
run the following commands:
```
python3 manage.py migrate
python3 manage.py collectstatic
django-admin compilemessages
```
As root create a file `/etc/systemd/system` (it's already deployed by puppet when the corresponding manifest is applied):
```
# /etc/systemd/system/eva.service
#
[Unit]
Description=gunicorn EVA daemon
After=network.target
[Service]
Type=simple
User=eva
Group=eva
RuntimeDirectory=eva
WorkingDirectory=/home/eva/eva
Environment=PYTHONUNBUFFERED=TRUE
ExecStart=/usr/bin/gunicorn --forwarded-allow-ips='*' -b '0:8000' eva.wsgi
ExecReload=/bin/kill -s HUP $MAINPID
KillMode=mixed
TimeoutStopSec=5
PrivateTmp=true
[Install]
WantedBy=multi-user.target
```
Adapt the paths in the file accordingly. Then, still as root, run:
```
systemctl enable --now eva.service
```
This enables the service to start at boot time and starts it immediately now. The daemon logs to the journal. You can see the last 10 lines by running `systemctl status eva.service` or the whole log by running `journalctl -u eva.service`. The usual switches to manipulate that output are available.

8
TODO
View File

@ -0,0 +1,8 @@
* switch to django 4
minor stuff:
* remove dot before "Nextcloud" at login page.
* add Testmode warning at login screen

View File

@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/3.1/ref/settings/
"""
from pathlib import Path
import os
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
@ -45,6 +46,11 @@ INSTALLED_APPS = [
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',
'allauth',
'allauth.account',
'allauth.socialaccount',
'allauth.socialaccount.providers.nextcloud',
'multiselectfield',
'formtools',
]
@ -53,6 +59,7 @@ 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',
@ -114,7 +121,7 @@ AUTH_PASSWORD_VALIDATORS = [
# Internationalization
# https://docs.djangoproject.com/en/3.1/topics/i18n/
LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'de'
TIME_ZONE = 'UTC'
@ -124,8 +131,31 @@ USE_L10N = True
USE_TZ = True
LOCALE_PATHS = ( os.path.join(BASE_DIR, 'locale'), )
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.1/howto/static-files/
STATIC_URL = '/static/'
# settings needed for allauth
SOCIALACCOUNT_PROVIDERS = {
'nextcloud': {
'SERVER': 'https://develwolke.wikimedia.de/',
#'SERVER': 'https://wolke.wikimedia.de',
#'SERVER': 'https://cloud.bucky.uber.space/'
}
}
AUTHENTICATION_BACKENDS = (
"django.contrib.auth.backends.ModelBackend",
"allauth.account.auth_backends.AuthenticationBackend",
)
SITE_ID = 1
ACCOUNT_EMAIL_VERIFICATION = 'none'
# ACCOUNT_EMAIL_REQUIRED = True
LOGIN_REDIRECT_URL = 'home'
ACCOUNT_LOGOUT_ON_GET = True

View File

@ -25,9 +25,6 @@ EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = '10.0.6.25'
EMAIL_PORT = '25'
# 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)
@ -50,14 +47,11 @@ SECRET_KEY = get_secret('SECRET_KEY')
DEBUG = False
# send mails only to debug mode adress even if in production
MAILTEST = True
MAILTEST = False
# 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 = 'g%+i6+gkwt3zz@+k-5x1dtstuw4)&qd$lxd^bt2oswy5e1#dul'
STATIC_ROOT = BASE_DIR / 'staticfiles'
ALLOWED_HOSTS = ['*']
@ -73,6 +67,11 @@ INSTALLED_APPS = [
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',
'allauth',
'allauth.account',
'allauth.socialaccount',
'allauth.socialaccount.providers.nextcloud',
'multiselectfield',
'formtools',
]
@ -82,6 +81,7 @@ MIDDLEWARE = [
'whitenoise.middleware.WhiteNoiseMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
@ -142,7 +142,7 @@ AUTH_PASSWORD_VALIDATORS = [
# Internationalization
# https://docs.djangoproject.com/en/3.1/topics/i18n/
LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'de'
TIME_ZONE = 'UTC'
@ -152,8 +152,29 @@ USE_L10N = True
USE_TZ = True
LOCALE_PATHS = ( os.path.join(BASE_DIR, 'locale'), )
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.1/howto/static-files/
STATIC_URL = '/static/'
# settings needed for allauth
SOCIALACCOUNT_PROVIDERS = {
'nextcloud': {
'SERVER': 'https://wolke.wikimedia.de/',
}
}
AUTHENTICATION_BACKENDS = (
"django.contrib.auth.backends.ModelBackend",
"allauth.account.auth_backends.AuthenticationBackend",
)
SITE_ID = 1
ACCOUNT_EMAIL_VERIFICATION = 'none'
# ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_LOGOUT_ON_GET = True
LOGIN_REDIRECT_URL = 'home'

View File

@ -19,5 +19,6 @@ from django.urls import path, include
urlpatterns = [
path('', include("evapp.urls")),
path('admin/', admin.site.urls),
path('accounts/', include('django.contrib.auth.urls')),
path('accounts/', include('allauth.urls')),
]

View File

@ -29,28 +29,35 @@ class PersonalForm(EvaForm):
class Meta:
model = Employee
fields = ['usermail', 'firstname', 'lastname', 'intern', 'department', 'team', ]
fields = ['firstname', 'lastname', 'department', 'team', ]
class WorkingForm(EvaForm):
def clean(self):
data = self.cleaned_data
if not data['remote'] and data['desk'] is None:
if data['works_in_gs'] and data['desk'] is None:
raise ValidationError('Wer nicht remote arbeitet braucht einen Schreibtisch!')
return data
class Meta:
model = Employee
fields = ['firstdate_employment', 'firstdate_presence', 'jobdescription_german',
'jobdescription_english', 'remote', 'desk',]
'jobdescription_english', 'works_in_gs', 'desk',]
widgets = {'firstdate_employment': DateInput(attrs={'type': 'date'}),
'firstdate_presence': DateInput(attrs={'type': 'date'}),}
class ITForm(EvaForm):
def clean(self):
data = self.cleaned_data
if data['vendor'] == 'MAC' and data['os'] != 'MOS':
raise ValidationError('Ein MAC sollte Mac OS installiert haben')
return data
class Meta:
model = Employee
fields = [
'vendor', 'os', 'keyboard', 'screen', 'mobile', 'sim', 'comment',
'vendor', 'os', 'keyboard', 'screen', 'mobile', 'comment',
'language', 'accounts', 'lists', 'rebu2go' ]
class OfficeForm(EvaForm):

View File

@ -1,4 +1,4 @@
# Generated by Django 3.1.4 on 2020-12-23 12:14
# Generated by Django 3.1.4 on 2021-09-13 12:41
from django.db import migrations, models
import multiselectfield.db.fields
@ -18,23 +18,27 @@ class Migration(migrations.Migration):
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('firstname', models.CharField(max_length=50, verbose_name='Vorname')),
('lastname', models.CharField(max_length=50, verbose_name='Nachname')),
('email', models.CharField(max_length=50, verbose_name='E-Mail-Adresse')),
('department', models.CharField(choices=[('PROG', 'Programme'), ('SOFT', 'Softwareentwicklung'), ('CENT', 'Central'), ('VOR', 'Vorstand')], max_length=5)),
('department', models.CharField(choices=[('PROG', 'Programme'), ('SOFT', 'Softwareentwicklung'), ('CENT', 'Central'), ('VOR', 'Vorstand')], max_length=5, verbose_name='Bereich')),
('team', models.CharField(blank=True, max_length=20, null=True)),
('firstdate_employment', models.DateField(null=True, verbose_name='erster Arbeitstag')),
('firstdate_presence', models.DateField(null=True, verbose_name='erster Tag der Anwesenheit in der Geschäftsstelle')),
('jobdescription_german', models.CharField(max_length=100, null=True, verbose_name='Stellenbeschreibung(deutsch)')),
('jobdescription_english', models.CharField(max_length=100, null=True, verbose_name='job description(english)')),
('desk', models.CharField(max_length=100, null=True, verbose_name='Wo soll der Arbeitsplatz sein?')),
('laptop', models.CharField(choices=[('14', '14", unser Standardgerät'), ('12', '12,5", geeignet für Vielreisende')], default='14', max_length=2)),
('os', models.CharField(choices=[('UBU', 'Ubuntu (Standard)'), ('WIN', 'Windows (bitte Begründung angeben)')], default='UBU', max_length=3)),
('screen', models.BooleanField(default=False, verbose_name='zusätzlicher Monitor? Einer ist standard.')),
('mobile', models.CharField(default='NO', max_length=6)),
('landline', models.BooleanField(default=True, verbose_name='Festnetztelefon')),
('firstdate_employment', models.DateField(null=True, verbose_name='Erster Arbeitstag')),
('firstdate_presence', models.DateField(null=True, verbose_name='Erster Tag der Anwesenheit in der Geschäftsstelle')),
('jobdescription_german', models.CharField(max_length=100, null=True, verbose_name='Stellenbezeichnung(deutsch)')),
('jobdescription_english', models.CharField(max_length=100, null=True, verbose_name='Job description(english)')),
('remote', models.BooleanField(default=True, verbose_name='Braucht Arbeitsplatz in der Geschäftsstelle?')),
('desk', models.CharField(blank=True, max_length=100, null=True, verbose_name='Wo soll der Arbeitsplatz sein?')),
('vendor', models.CharField(choices=[('STANDARD', 'Dell Latitude'), ('LENOVO', 'Lenovo Thinkpad'), ('MAC', 'Mac (nur für Grafiker_innen)')], default='STANDARD', max_length=8, verbose_name='Hersteller')),
('os', models.CharField(choices=[('UBU', 'Ubuntu (Standard)'), ('WIN', 'Windows (bitte Begründung angeben)'), ('MOS', 'Mac OS (nur wenn Mac gewählt)')], default='UBU', max_length=3, verbose_name='Betriebssystem')),
('screen', models.BooleanField(default=False, verbose_name='Zusätzlicher Monitor? Einer ist standard.')),
('mobile', models.BooleanField(default=False, max_length=6, verbose_name='Diensttelefon (Handy)')),
('keyboard', models.CharField(choices=[('DE', 'Deutsch'), ('US', 'USA'), ('OT', 'Anderes (Bitte unten angeben)')], default='DE', max_length=2, verbose_name='Tastaturlayout')),
('comment', models.TextField(blank=True, max_length=500, null=True, verbose_name='zusätzliche IT-Anforderungen')),
('language', models.CharField(choices=[('GER', 'deutsch'), ('ENG', 'english')], default='GER', max_length=3)),
('accounts', multiselectfield.db.fields.MultiSelectField(choices=[('OTRSWMDE', 'OTRS (WMDE)'), ('OTRSFUND', 'OTRS (Fundraising)'), ('CIVIC1', 'Civic CRM (allgemein)'), ('CIVIC2', 'Civic CRM (Mailings, impliziert allgemein)'), ('FUND', 'Fundraising Netzlaufwerk'), ('WEB', 'www.wikimedia.de (edit)'), ('BLOG', 'blog.wikimedia.de (edit)'), ('FORUM', 'forum.wikimedia.de')], max_length=51, null=True)),
('lists', models.CharField(max_length=100, null=True)),
('language', models.CharField(choices=[('GER', 'Deutsch'), ('ENG', 'English')], default='GER', max_length=3, verbose_name='Sprache')),
('accounts', multiselectfield.db.fields.MultiSelectField(blank=True, choices=[('OTRSWMDE', 'OTRS Ticketsystem'), ('CIVIC1', 'Civic CRM (allgemein)'), ('CIVIC2', 'Civic CRM (Mailings, impliziert allgemein)'), ('WEB', 'www.wikimedia.de (edit)'), ('BLOG', 'blog.wikimedia.de (edit)'), ('FORUM', 'forum.wikimedia.de')], max_length=37, null=True, verbose_name='Zusätzliche Accounts')),
('lists', models.CharField(blank=True, max_length=100, null=True, verbose_name='Zusätzliche Mailinglisten')),
('rebu2go', models.BooleanField(default=False, verbose_name='Rebu2Go-Zugang benötigt?')),
('transponder', models.CharField(choices=[('NORM', 'Allgemeiner Transponder'), ('SPECIAL', 'Besondere Schließungen (bitte angeben)'), ('NOTRANS', 'Kein Transponder')], default='NORM', max_length=7)),
('special', models.TextField(blank=True, max_length=500, null=True, verbose_name='Besondere Schließungen hier eintragen')),
('post_office_box', models.BooleanField(default=True, verbose_name='Postfach am Empfang benötigt?')),
],
),
]

View File

@ -1,23 +0,0 @@
# Generated by Django 3.1.4 on 2020-12-23 12:23
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('evapp', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='employee',
name='post_office_box',
field=models.BooleanField(default=True, verbose_name='Postfach am Empfang benötigt?'),
),
migrations.AddField(
model_name='employee',
name='transponder',
field=models.CharField(choices=[('NORM', 'allgemeiner Transponder'), ('SPECIAL', 'besondere Schließungen (bitte angeben)'), ('NO', 'Kein Transponder')], default='NORM', max_length=7),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 3.1.4 on 2021-09-14 10:55
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('evapp', '0001_initial'),
]
operations = [
migrations.RenameField(
model_name='employee',
old_name='remote',
new_name='works_in_gs',
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 3.1.4 on 2021-01-14 13:57
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('evapp', '0002_auto_20201223_1223'),
]
operations = [
migrations.AlterField(
model_name='employee',
name='transponder',
field=models.CharField(choices=[('NORM', 'allgemeiner Transponder'), ('SPECIAL', 'besondere Schließungen (bitte angeben)'), ('NOTRANS', 'Kein Transponder')], default='NORM', max_length=7),
),
]

View File

@ -0,0 +1,28 @@
# Generated by Django 3.1.4 on 2022-02-08 09:55
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('evapp', '0002_auto_20210914_1055'),
]
operations = [
migrations.AlterField(
model_name='employee',
name='department',
field=models.CharField(choices=[('PROG', 'Programme'), ('SOFT', 'Softwareentwicklung'), ('CENT', 'Central'), ('KOMEV', 'Kommunikation und Events'), ('VOR', 'Vorstand')], max_length=5, verbose_name='Bereich'),
),
migrations.AlterField(
model_name='employee',
name='team',
field=models.CharField(blank=True, max_length=50, null=True),
),
migrations.AlterField(
model_name='employee',
name='works_in_gs',
field=models.BooleanField(default=True, verbose_name='Braucht Arbeitsplatz in der Geschäftsstelle?)'),
),
]

View File

@ -0,0 +1,24 @@
# Generated by Django 4.2.4 on 2023-08-11 10:28
from django.db import migrations, models
import multiselectfield.db.fields
class Migration(migrations.Migration):
dependencies = [
('evapp', '0003_auto_20220208_0955'),
]
operations = [
migrations.AlterField(
model_name='employee',
name='accounts',
field=multiselectfield.db.fields.MultiSelectField(blank=True, choices=[('OTRSWMDE', 'OTRS Ticketsystem'), ('CIVIC1', 'Civic CRM (allgemein)'), ('CIVIC2', 'Civic CRM (Mailings, impliziert allgemein)'), ('WEB', 'www.wikimedia.de (edit)'), ('BLOG', 'blog.wikimedia.de (edit)'), ('FORUM', 'forum.wikimedia.de')], max_length=10, null=True, verbose_name='Zusätzliche Accounts'),
),
migrations.AlterField(
model_name='employee',
name='department',
field=models.CharField(choices=[('COENG', 'Communitys & Engagement'), ('SOFT', 'Softwareentwicklung'), ('CENT', 'Central'), ('KOMAD', 'Kommunikation & Advocacy'), ('VOR', 'Vorstand')], max_length=5, verbose_name='Bereich'),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 3.1.4 on 2021-02-08 11:19
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('evapp', '0003_auto_20210114_1357'),
]
operations = [
migrations.AddField(
model_name='employee',
name='intern',
field=models.BooleanField(default=True, verbose_name='Interne_r Mitarbeiter_in?'),
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 4.2.4 on 2023-08-17 11:08
from django.db import migrations
import multiselectfield.db.fields
class Migration(migrations.Migration):
dependencies = [
('evapp', '0004_alter_employee_accounts_alter_employee_department'),
]
operations = [
migrations.AlterField(
model_name='employee',
name='accounts',
field=multiselectfield.db.fields.MultiSelectField(blank=True, choices=[('OTRSWMDE', 'OTRS Ticketsystem'), ('CIVIC1', 'Civic CRM (allgemein)'), ('CIVIC2', 'Civic CRM (Mailings, impliziert allgemein)'), ('WEB', 'www.wikimedia.de (edit)'), ('BLOG', 'blog.wikimedia.de (edit)'), ('FORUM', 'forum.wikimedia.de')], max_length=40, null=True, verbose_name='Zusätzliche Accounts'),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 3.1.4 on 2021-02-08 13:45
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('evapp', '0004_employee_intern'),
]
operations = [
migrations.AddField(
model_name='employee',
name='vendor',
field=models.CharField(choices=[('STANDARD', 'Dell Latitude'), ('LENOVO', 'Lenovo Thinkpad'), ('MAC', 'Mac (nur in Ausnahmefällen)')], default='STANDARD', max_length=8),
),
]

View File

@ -1,24 +0,0 @@
# Generated by Django 3.1.4 on 2021-02-09 09:39
from django.db import migrations, models
import multiselectfield.db.fields
class Migration(migrations.Migration):
dependencies = [
('evapp', '0005_employee_vendor'),
]
operations = [
migrations.AddField(
model_name='employee',
name='rebu2go',
field=models.BooleanField(default=False, verbose_name='Rebu2Go-Zugang benötigt?'),
),
migrations.AlterField(
model_name='employee',
name='accounts',
field=multiselectfield.db.fields.MultiSelectField(choices=[('OTRSWMDE', 'OTRS Ticketsystem'), ('CIVIC1', 'Civic CRM (allgemein)'), ('CIVIC2', 'Civic CRM (Mailings, impliziert allgemein)'), ('ZEDA', 'Zeda Nextcloud'), ('WEB', 'www.wikimedia.de (edit)'), ('BLOG', 'blog.wikimedia.de (edit)'), ('FORUM', 'forum.wikimedia.de')], max_length=42, null=True),
),
]

View File

@ -1,23 +0,0 @@
# Generated by Django 3.1.4 on 2021-02-09 11:46
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('evapp', '0006_auto_20210209_0939'),
]
operations = [
migrations.AddField(
model_name='employee',
name='remote',
field=models.BooleanField(default=False, verbose_name='Braucht keinen Arbeitsplatz weil Home-Office'),
),
migrations.AlterField(
model_name='employee',
name='desk',
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Wo soll der Arbeitsplatz sein?'),
),
]

View File

@ -1,53 +0,0 @@
# Generated by Django 3.1.4 on 2021-03-01 10:53
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('evapp', '0007_auto_20210209_1146'),
]
operations = [
migrations.AddField(
model_name='employee',
name='special',
field=models.TextField(blank=True, max_length=500, null=True, verbose_name='Besondere Schließungen hier eintragen'),
),
migrations.AlterField(
model_name='employee',
name='firstdate_employment',
field=models.DateField(null=True, verbose_name='Erster Arbeitstag'),
),
migrations.AlterField(
model_name='employee',
name='firstdate_presence',
field=models.DateField(null=True, verbose_name='Erster Tag der Anwesenheit in der Geschäftsstelle'),
),
migrations.AlterField(
model_name='employee',
name='jobdescription_english',
field=models.CharField(max_length=100, null=True, verbose_name='Job description(english)'),
),
migrations.AlterField(
model_name='employee',
name='language',
field=models.CharField(choices=[('GER', 'Deutsch'), ('ENG', 'English')], default='GER', max_length=3),
),
migrations.AlterField(
model_name='employee',
name='laptop',
field=models.CharField(choices=[('14', '14", uUser Standardgerät'), ('12', '12,5", Geeignet für Vielreisende')], default='14', max_length=2),
),
migrations.AlterField(
model_name='employee',
name='screen',
field=models.BooleanField(default=False, verbose_name='Zusätzlicher Monitor? Einer ist standard.'),
),
migrations.AlterField(
model_name='employee',
name='transponder',
field=models.CharField(choices=[('NORM', 'Allgemeiner Transponder'), ('SPECIAL', 'Besondere Schließungen (bitte angeben)'), ('NOTRANS', 'Kein Transponder')], default='NORM', max_length=7),
),
]

View File

@ -1,28 +0,0 @@
# Generated by Django 3.1.4 on 2021-03-15 14:08
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('evapp', '0008_auto_20210301_1053'),
]
operations = [
migrations.AddField(
model_name='employee',
name='usermail',
field=models.EmailField(default='bestechefin@wikimedia.de', max_length=50, verbose_name='Deine Mailadresse'),
),
migrations.AlterField(
model_name='employee',
name='email',
field=models.EmailField(max_length=50, verbose_name='E-Mail-Adresse ders Mitarbeitenden'),
),
migrations.AlterField(
model_name='employee',
name='laptop',
field=models.CharField(choices=[('14', '14", Unser Standardgerät'), ('12', '12,5", Geeignet für Vielreisende')], default='14', max_length=2),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 3.1.4 on 2021-03-25 08:13
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('evapp', '0009_auto_20210315_1408'),
]
operations = [
migrations.AlterField(
model_name='employee',
name='jobdescription_german',
field=models.CharField(max_length=100, null=True, verbose_name='Stellenbezeichnung(deutsch)'),
),
]

View File

@ -1,23 +0,0 @@
# Generated by Django 3.1.4 on 2021-03-29 12:54
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('evapp', '0010_auto_20210325_0813'),
]
operations = [
migrations.AddField(
model_name='employee',
name='sim',
field=models.BooleanField(default=False, verbose_name='Mobilfunkvertrag'),
),
migrations.AddField(
model_name='employee',
name='sim2',
field=models.BooleanField(default=False, verbose_name='Zweite Sim (für Laptop zB)'),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 3.1.4 on 2021-03-30 08:25
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('evapp', '0011_auto_20210329_1254'),
]
operations = [
migrations.AddField(
model_name='employee',
name='bvg',
field=models.BooleanField(default=True, verbose_name='Bekommt eine BVG-Karte, weil in Berlin tätig'),
),
]

View File

@ -1,17 +0,0 @@
# Generated by Django 3.1.4 on 2021-04-01 08:30
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('evapp', '0012_employee_bvg'),
]
operations = [
migrations.RemoveField(
model_name='employee',
name='bvg',
),
]

View File

@ -1,38 +0,0 @@
# Generated by Django 3.1.4 on 2021-05-04 08:42
from django.db import migrations, models
import multiselectfield.db.fields
class Migration(migrations.Migration):
dependencies = [
('evapp', '0013_remove_employee_bvg'),
]
operations = [
migrations.RemoveField(
model_name='employee',
name='sim2',
),
migrations.AlterField(
model_name='employee',
name='accounts',
field=multiselectfield.db.fields.MultiSelectField(blank=True, choices=[('OTRSWMDE', 'OTRS Ticketsystem'), ('CIVIC1', 'Civic CRM (allgemein)'), ('CIVIC2', 'Civic CRM (Mailings, impliziert allgemein)'), ('WEB', 'www.wikimedia.de (edit)'), ('BLOG', 'blog.wikimedia.de (edit)'), ('FORUM', 'forum.wikimedia.de')], max_length=37, null=True, verbose_name='Zusätzliche Accounts'),
),
migrations.AlterField(
model_name='employee',
name='lists',
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Zusätzliche Mailinglisten'),
),
migrations.AlterField(
model_name='employee',
name='mobile',
field=models.BooleanField(default=False, max_length=6, verbose_name='Handy benötigt?'),
),
migrations.AlterField(
model_name='employee',
name='vendor',
field=models.CharField(choices=[('STANDARD', 'Dell Latitude'), ('LENOVO', 'Lenovo Thinkpad'), ('MAC', 'Mac (nur in Ausnahmefällen)')], default='STANDARD', max_length=8, verbose_name='Hersteller'),
),
]

View File

@ -1,17 +0,0 @@
# Generated by Django 3.1.4 on 2021-05-04 09:43
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('evapp', '0014_auto_20210504_0842'),
]
operations = [
migrations.RemoveField(
model_name='employee',
name='email',
),
]

View File

@ -1,27 +0,0 @@
# Generated by Django 3.1.4 on 2021-05-04 10:40
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('evapp', '0015_remove_employee_email'),
]
operations = [
migrations.RemoveField(
model_name='employee',
name='landline',
),
migrations.AddField(
model_name='employee',
name='keyboard',
field=models.CharField(choices=[('DE', 'Deutsch'), ('US', 'USA'), ('OT', 'Anderes (Bitte unten angeben)')], default='DE', max_length=2, verbose_name='Tastaturlayout'),
),
migrations.AlterField(
model_name='employee',
name='department',
field=models.CharField(choices=[('PROG', 'Programme'), ('SOFT', 'Softwareentwicklung'), ('CENT', 'Central'), ('VOR', 'Vorstand')], max_length=5, verbose_name='Bereich'),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 3.1.4 on 2021-05-04 12:24
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('evapp', '0016_auto_20210504_1040'),
]
operations = [
migrations.AlterField(
model_name='employee',
name='os',
field=models.CharField(choices=[('UBU', 'Ubuntu (Standard)'), ('WIN', 'Windows (bitte Begründung angeben)')], default='UBU', max_length=3, verbose_name='Betriebssystem'),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 3.1.4 on 2021-05-04 12:51
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('evapp', '0017_auto_20210504_1224'),
]
operations = [
migrations.AlterField(
model_name='employee',
name='usermail',
field=models.EmailField(default='bestechefin@wikimedia.de', max_length=50, verbose_name='Deine Mailadresse (Ansprechpartner_in)'),
),
]

View File

@ -1,22 +0,0 @@
# Generated by Django 3.1.4 on 2021-05-04 13:33
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('evapp', '0018_auto_20210504_1251'),
]
operations = [
migrations.RemoveField(
model_name='employee',
name='laptop',
),
migrations.AlterField(
model_name='employee',
name='vendor',
field=models.CharField(choices=[('STANDARD', 'Dell Latitude'), ('LENOVO', 'Lenovo Thinkpad'), ('MAC', 'Mac (nur für Grafiker_innen)')], default='STANDARD', max_length=8, verbose_name='Hersteller'),
),
]

View File

@ -1,22 +1,25 @@
from django.db import models
from multiselectfield import MultiSelectField
from django.utils.translation import gettext_lazy as _
# ATTENTION!!!
# No key should be used twice in any of these dicts because of the
# suboptimal implementation in views.EvaFormView.beautify_data()
#
DEPARTMENT_CHOICES = {'PROG': 'Programme',
'SOFT': 'Softwareentwicklung',
DEPARTMENT_CHOICES = {'COENG': _('Communitys & Engagement'),
'SOFT': _('Softwareentwicklung'),
'CENT': 'Central',
'VOR': 'Vorstand',}
'KOMAD': _('Kommunikation & Advocacy'),
'VOR': _('Vorstand'),}
VENDOR_CHOICES = {'STANDARD': 'Dell Latitude',
'LENOVO': 'Lenovo Thinkpad',
'MAC': 'Mac (nur für Grafiker_innen)'}
'MAC': _('Mac (nur für Grafiker_innen)')}
OS_CHOICES = {'UBU': 'Ubuntu (Standard)',
'WIN': 'Windows (bitte Begründung angeben)',}
'WIN': _('Windows (bitte Begründung angeben)'),
'MOS': _('Mac OS (nur wenn Mac gewählt)')}
LANG_CHOICES = {'GER': 'Deutsch',
@ -24,54 +27,54 @@ LANG_CHOICES = {'GER': 'Deutsch',
KEYBOARD_CHOICES = {'DE': 'Deutsch',
'US': 'USA',
'OT': 'Anderes (Bitte unten angeben)'}
'OT': _('Anderes (Bitte unten angeben)')}
ACCOUNT_CHOICES = {'OTRSWMDE': 'OTRS Ticketsystem',
'CIVIC1': 'Civic CRM (allgemein)',
'CIVIC2': "Civic CRM (Mailings, impliziert allgemein)",
'CIVIC1': _('Civic CRM (allgemein)'),
'CIVIC2': _("Civic CRM (Mailings, impliziert allgemein)"),
'WEB': 'www.wikimedia.de (edit)',
'BLOG': 'blog.wikimedia.de (edit)',
'FORUM': 'forum.wikimedia.de',
}
TRANSPONDER_CHOICES = {'NORM': 'Allgemeiner Transponder',
'SPECIAL': 'Besondere Schließungen (bitte angeben)',
'NOTRANS': 'Kein Transponder',}
TRANSPONDER_CHOICES = {'NORM': _('Allgemeiner Transponder'),
'SPECIAL': _('Besondere Schließungen (bitte angeben)'),
'NOTRANS': _('Kein Transponder'),}
class Employee(models.Model):
# email adress of user. should not be necessary if we use openauth one day
usermail = models.EmailField(max_length=50, verbose_name="Deine Mailadresse (Ansprechpartner_in)", default='bestechefin@wikimedia.de')
# usermail = models.EmailField(max_length=50, verbose_name="Deine Mailadresse (Ansprechpartner_in)", default='bestechefin@wikimedia.de')
# personal data
firstname = models.CharField(max_length=50, verbose_name="Vorname")
lastname = models.CharField(max_length=50, verbose_name="Nachname")
intern = models.BooleanField(verbose_name='Interne_r Mitarbeiter_in?', default=True)
department = models.CharField(max_length=5, choices=DEPARTMENT_CHOICES.items(), verbose_name='Bereich')
team = models.CharField(max_length=20, null=True, blank=True) # TODO? better with choices?
firstname = models.CharField(max_length=50, verbose_name=_("Vorname"))
lastname = models.CharField(max_length=50, verbose_name=_("Nachname"))
# intern = models.BooleanField(verbose_name='Interne_r Mitarbeiter_in?', default=True)
department = models.CharField(max_length=5, choices=DEPARTMENT_CHOICES.items(), verbose_name=_('Bereich'))
team = models.CharField(max_length=50, null=True, blank=True) # TODO? better with choices?
# general work related stuff
firstdate_employment = models.DateField(null=True, verbose_name="Erster Arbeitstag")
firstdate_presence = models.DateField(null=True, verbose_name="Erster Tag der Anwesenheit in der Geschäftsstelle")
firstdate_employment = models.DateField(null=True, verbose_name=_("Erster Arbeitstag"))
firstdate_presence = models.DateField(null=True, verbose_name=_("Erster Tag der Anwesenheit in der Geschäftsstelle"))
jobdescription_german = models.CharField(null=True, max_length=100, verbose_name="Stellenbezeichnung(deutsch)")
jobdescription_english = models.CharField(null=True, max_length=100, verbose_name="Job description(english)")
remote = models.BooleanField(verbose_name='Braucht keinen Arbeitsplatz weil Home-Office', default=False)
desk = models.CharField(max_length=100, null=True, blank=True, verbose_name="Wo soll der Arbeitsplatz sein?")
works_in_gs = models.BooleanField(verbose_name=_('Braucht Arbeitsplatz in der Geschäftsstelle?)'), default=True)
desk = models.CharField(max_length=100, null=True, blank=True, verbose_name=_("Wo soll der Arbeitsplatz sein?"))
# IT related stuff
vendor = models.CharField(max_length=8, choices=VENDOR_CHOICES.items(), default='STANDARD', verbose_name='Hersteller')
os = models.CharField(max_length=3, choices=OS_CHOICES.items(), default='UBU', verbose_name='Betriebssystem')
screen = models.BooleanField(default=False, verbose_name='Zusätzlicher Monitor? Einer ist standard.')
mobile = models.BooleanField(max_length=6, default=False, verbose_name='Handy benötigt?')
sim = models.BooleanField(default=False, verbose_name="Mobilfunkvertrag")
keyboard = models.CharField(max_length=2, choices=KEYBOARD_CHOICES.items(), default='DE', verbose_name="Tastaturlayout")
comment = models.TextField(max_length=500, null=True, blank=True, verbose_name="zusätzliche IT-Anforderungen")
language = models.CharField(max_length=3, choices=LANG_CHOICES.items(), default="GER")
accounts = MultiSelectField(choices=ACCOUNT_CHOICES.items(), null=True, blank=True, verbose_name="Zusätzliche Accounts")
lists = models.CharField(max_length=100, null=True, blank=True, verbose_name="Zusätzliche Mailinglisten")
rebu2go = models.BooleanField(verbose_name="Rebu2Go-Zugang benötigt?", default=False)
vendor = models.CharField(max_length=8, choices=VENDOR_CHOICES.items(), default='STANDARD', verbose_name=_('Hersteller'))
os = models.CharField(max_length=3, choices=OS_CHOICES.items(), default='UBU', verbose_name=_('Betriebssystem'))
screen = models.BooleanField(default=False, verbose_name=_('Zusätzlicher Monitor? Einer ist standard.'))
mobile = models.BooleanField(max_length=6, default=False, verbose_name=_('Diensttelefon (Handy)'))
# sim = models.BooleanField(default=False, verbose_name="Mobilfunkvertrag")
keyboard = models.CharField(max_length=2, choices=KEYBOARD_CHOICES.items(), default='DE', verbose_name=_("Tastaturlayout"))
comment = models.TextField(max_length=500, null=True, blank=True, verbose_name=_("zusätzliche IT-Anforderungen"))
language = models.CharField(max_length=3, choices=LANG_CHOICES.items(), default="GER", verbose_name=_("Sprache"))
accounts = MultiSelectField(choices=ACCOUNT_CHOICES.items(), max_length=40, null=True, blank=True, verbose_name=_("Zusätzliche Accounts"))
lists = models.CharField(max_length=100, null=True, blank=True, verbose_name=_("Zusätzliche Mailinglisten"))
rebu2go = models.BooleanField(verbose_name=_("Rebu2Go-Zugang benötigt?"), default=False)
# office related stuff
transponder = models.CharField(max_length=7, choices=TRANSPONDER_CHOICES.items(), default='NORM')
special = models.TextField(max_length=500, null=True, blank=True, verbose_name="Besondere Schließungen hier eintragen")
post_office_box = models.BooleanField(default=True, verbose_name='Postfach am Empfang benötigt?')
special = models.TextField(max_length=500, null=True, blank=True, verbose_name=_("Besondere Schließungen hier eintragen"))
post_office_box = models.BooleanField(default=True, verbose_name=_('Postfach am Empfang benötigt?'))

View File

@ -2,10 +2,11 @@
ONLY_ONBOARDING = True
# sender mail adress also used for MAILTEST mode
EVA_MAIL = 'benni.baermann@wikimedia.de'
EVA_MAIL = 'it-support@wikimedia.de'
# these Fields should be included in every mail
BASIC_DATA = ['usermail', 'firstname', 'lastname', 'firstdate_employment', 'firstdate_presence',]
BASIC_DATA = ['firstname', 'lastname', 'firstdate_employment', 'firstdate_presence',
'jobdescription_german', 'jobdescription_english',]
# for every department: 'MAIL' => mail adress, 'DATA': additional fields to include
MAILS = {
@ -13,31 +14,31 @@ MAILS = {
'MAIL': 'wmde-it@wikimedia.de',
'DATA': [
'laptop', 'os', 'comment', 'email', 'landline', 'lists', 'mobile',
'department', 'accounts', 'language', 'screen', 'remote', 'desk',
'department', 'accounts', 'language', 'screen', 'works_in_gs', 'desk',
'keyboard',
],
},
'OFFICE': {
'MAIL': 'office@wikimedia.de',
'DATA': [
'transponder', 'special', 'post_office_box', 'sim', 'sim2',
'remote', 'desk',
'transponder', 'special', 'post_office_box', 'mobile',
'works_in_gs', 'desk',
],
},
'KOMM': {
'MAIL': 'presse@wikimedia.de',
'DATA': [
'department', 'team',
'jobdescription_german', 'jobdescription_english',
],
},
'CENTRAL': {
'MAIL': 'eileen.miedtank@wikimedia.de',
'MAIL': 'anna.noelte@wikimedia.de',
'DATA': [
'department', 'team', 'language', 'sim', 'sim2', 'rebu2go'
'department', 'team', 'language', 'mobile', 'rebu2go'
],
},
'HR': {
'MAIL': 'personal@wikimedia.de, eileen.miedtank@wikimedia.de',
'MAIL': 'personal@wikimedia.de',
'DATA': [
'department', 'team', 'language',
]
@ -47,6 +48,11 @@ MAILS = {
'DATA': [
'team', 'department', 'language',
]
},
'FINANCE': {
'MAIL': 'claudia.langrock@wikimedia.de',
'DATA': [
'rebu2go'
]
}
}

View File

@ -0,0 +1,27 @@
{% load i18n %}
{% load static %}
<script type="text/javascript" src="{% static 'admin/js/core.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/vendor/jquery/jquery.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/jquery.init.js' %}"></script>
{{ form.media }}
<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 account socialaccount %}
{% block content %}
<center>
<img src="{% static 'evapp/logo.png' %}" />
<h1>
E (V A) - Eintritt, (Veränderung, Austritt)<p>
</h1>
Bitte via Wolke einloggen:
{% include "socialaccount/snippets/provider_list.html" with process="login" %}
</center>
{% endblock %}

View File

@ -1,4 +1,5 @@
{% load i18n %}
{% autoescape off %}
{% for key, value in data.items %}{% if key == 'laptop' %} {{ key }}: {{ value | safe}}{% else %}
{{ key }}: {{ value }}{% endif %}{% endfor %}
{% trans key %}: {{ value }}{% endif %}{% endfor %}
{% endautoescape %}

View File

@ -1,3 +1,7 @@
{% load i18n %}
(english below)
Hallo!
Es gibt einen Neuzugang bei Wikimedia! Hier ( https://wiki.wikimedia.de/wiki/Onboarding ) kannst Du nachsehen,
@ -6,4 +10,22 @@ die Du dafür brauchst:
{% include 'evapp/dataloop.txt' %}
Wenn Du Fragen hast, melde Dich bei {{contact}}.
Grüße, Deine E.V.A.
-------------------------
{% language 'en' %}
Hi!
There is a new employee at Wikimedia! Here ( https://wiki.wikimedia.de/wiki/Onboarding ) you can see, which
steps are now necessary for your department.
All Data you need for this:
{% include 'evapp/dataloop.txt' %}
If you have any questions please write to {{contact}}.
Regards, Your E.V.A.
{% endlanguage %}

View File

@ -11,7 +11,12 @@
<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 socialaccount %}
{% if user.is_authenticated %}
{% block content %}
{% get_current_language as LANGUAGE_CODE %}
<!-- Current language: {{ LANGUAGE_CODE }} -->
<center>
<style>
ul > li {
@ -27,20 +32,23 @@
</style>
<img src="{% static 'evapp/logo.png' %}" />
{% if TESTMODE %}
<h1 style="background-color:red;color:white">{% translate "WARNUNG! Test-MODUS aktiviert. Es werden keine Mails verschickt!" %}</h1>
{% endif %}
<h1>
E (V A) - Eintritt, (Veränderung, Austritt)<p>
</h1>
</h1>{% translate "Du bist eingeloggt als" %} {{ user.email }}
<h2>
<p>Schritt {{ wizard.steps.step1 }} von {{ wizard.steps.count }}</p>
<p> {% translate "Schritt" %} {{ wizard.steps.step1 }} {% translate "von" %} {{ wizard.steps.count }}</p>
<p>{% if wizard.steps.step1 == 1 %}
Angaben zur Person {% endif %}
{% translate "Angaben zur Person" %} {% endif %}
{% if choice == 'IN' %}
{% if wizard.steps.step1 == 2 %}
Angaben zum neuen Arbeitsverhältnis
{% translate "Angaben zum neuen Arbeitsverhältnis" %}
{% elif wizard.steps.step1 == 3 %}
IT-relevante Angaben
{% translate "IT-relevante Angaben" %}
{% elif wizard.steps.step1 == 4 %}
Office-relevante Angaben
{% translate "Office-relevante Angaben" %}
{% endif %}
{% else %}
{% if wizard.steps.step1 == 2 %}
@ -48,7 +56,7 @@
{% endif %}
{% endif %}
{% if datatable == True %}
Bestätigungsschritt
{% translate "Bestätigungsschritt" %}
{% endif %}
</p>
</h2>
@ -79,17 +87,21 @@
{% endif %}
</table>
<p>
<span style="color: red">*</span> Pflichtfeld
<span style="color: red">*</span> {% translate "Pflichtfeld" %}
<p>
{% if wizard.steps.prev %}
<button formnovalidate="formnovalidate" name="wizard_goto_step" type="submit" value="{{ wizard.steps.prev }}">Zurück</button>
<button formnovalidate="formnovalidate" name="wizard_goto_step" type="submit" value="{{ wizard.steps.prev }}">{% translate "Zurück" %}</button>
{% endif %}
{% if datatable == True %}
<button type="submit" value="{% trans "Weiter" %}">Abschicken</button>
<button type="submit" value="{% trans "Weiter" %}">{% translate "Abschicken" %}</button>
{% else %}
<button type="submit" value="{% trans "Weiter" %}">Weiter</button>
<button type="submit" value="{% trans "Weiter" %}">{% translate "Weiter" %}</button>
{% endif %}
</form>
<p>
<a href="{% url 'account_logout' %}">{% translate "logout" %}</a>
</center>
{% endblock %}
{% else %}
<a href="{% provider_login_url 'nextcloud' %}">{% translate "Bitte einloggen!" %}</a>
{% endif %}

View File

@ -1,3 +1,127 @@
from django.test import TestCase
from django.test import Client
from django.contrib.auth.models import User
from django.conf import settings
from django.http import HttpResponse
from django.core import mail
from django.utils import translation
# Create your tests here.
from .forms import ITForm, WorkingForm, OfficeForm, DummyForm
class LoginTestCase(TestCase):
def setUp(self):
self.client = Client()
self.user = User.objects.create_user('vladimir', 'vladimir@reiherzehe.com', 'reiherzehe')
self.client.login(username='vladimir', password='reiherzehe')
self.response = self.client.get('/')
def testLogin(self):
self.assertContains(self.response, 'Du bist eingeloggt als vladimir@reiherzehe.com', status_code=200)
response_en = self.client.get('/', HTTP_ACCEPT_LANGUAGE='en-us')
self.assertContains(response_en, 'You are logged in as vladimir@reiherzehe.com', status_code=200)
self.assertContains(response_en, 'Firstname', status_code=200)
response_en = self.client.get('/', HTTP_ACCEPT_LANGUAGE='en')
self.assertContains(response_en, 'You are logged in as vladimir@reiherzehe.com', status_code=200)
self.assertContains(response_en, 'Firstname', status_code=200)
def testDebugWarning(self):
with self.settings(DEBUG=True):
self.response = self.client.get('/') # we need to do it again with DEBUG = True
self.assertContains(self.response, "WARNUNG! Test-MODUS aktiviert. Es werden keine Mails verschickt!", status_code=200)
with self.settings(DEBUG=False) and self.settings(MAILTEST=False):
self.response = self.client.get('/') # we need to do it again with DEBUG = False
self.assertNotContains(self.response, "WARNUNG! Test-MODUS aktiviert. Es werden keine Mails verschickt!", status_code=200)
def _postform(self, data, expected_form):
'''helper function to manage the Wizzard'''
response = self.client.post('/', data, follow=True)
# print(type(response))
self.assertEqual(200, self.response.status_code)
if not type(response) == HttpResponse:
if 'form' in response.context:
self.assertFalse(response.context['form'].errors)
else:
raise "NO FORM FOUND"
self.assertEqual(
type(response.context['wizard']['form']),
expected_form
)
return response
def test_department(self):
self.assertContains(self.response, 'Programme', status_code=200)
self.assertContains(self.response, 'Kommunikation und Events', status_code=200)
def test_wizzard_in(self):
''' this test goes through the whole onboarding process of the EvaFormView from start to end '''
self.assertEqual(200, self.response.status_code)
response = self._postform({
'eva_form_view-current_step': '0',
'0-firstname': 'Ara',
'0-lastname': 'Seva',
'0-department': 'CENT',
'0-team': 'Community Communications',
'0-choice': 'IN',
}, WorkingForm)
response = self._postform({
'eva_form_view-current_step': '1',
'1-firstdate_employment': '2021-01-01',
'1-firstdate_presence': '2021-01-01',
'1-jobdescription_german': 'hau drauf',
'1-jobdescription_english': 'und schluss',
'1-works_in_gs': False
}, ITForm)
response = self._postform({
'eva_form_view-current_step': '2',
'2-vendor': 'STANDARD',
'2-os': 'UBU',
'2-keyboard': 'DE',
'2-language': 'GER'
}, OfficeForm)
response = self._postform({
'eva_form_view-current_step': '3',
'3-transponder': 'NORM'
}, DummyForm)
response = self._postform({
'eva_form_view-current_step': '5',
}, DummyForm)
def test_mail(self):
self.test_wizzard_in()
# print(mail.outbox[0].body)
self.assertGreater(len(mail.outbox), 2)
self.assertIn("Vorname", mail.outbox[0].body)
self.assertIn("Firstname", mail.outbox[0].body)
for i in (0,1,3):
self.assertIn("Handy", mail.outbox[i].body)
self.assertIn("Ara Seva", mail.outbox[0].subject)
class NoLoginTestCase(TestCase):
def setUp(self):
self.client = Client()
def test_details(self):
response = self.client.get('/')
self.assertEqual(response.status_code, 302)
response2 = self.client.get(response.url)
self.assertContains( response2, 'Bitte via Wolke einloggen:', status_code=200)
class ITFORMTestCase(TestCase):
def test_mac(self):
form = ITForm(data={"vendor": 'MAC', 'os': 'UBU'})
#print (form.errors)
self.assertEqual(form.non_field_errors(), ['Ein MAC sollte Mac OS installiert haben'])
def test_ubu(self):
form = ITForm(data={"vendor": 'STANDARD', 'os': 'UBU'})
#print (form.errors)
self.assertNotEqual(form.non_field_errors(), ['Ein MAC sollte Mac OS installiert haben'])

View File

@ -10,6 +10,7 @@ from formtools.wizard.views import CookieWizardView
from django.shortcuts import render
from django.conf import settings
from django.contrib.auth.mixins import LoginRequiredMixin
from django.utils.translation import gettext_lazy as _
from .models import Employee, DEPARTMENT_CHOICES, OS_CHOICES, VENDOR_CHOICES, \
LANG_CHOICES, ACCOUNT_CHOICES, TRANSPONDER_CHOICES, KEYBOARD_CHOICES
@ -18,7 +19,7 @@ from .forms import PersonalForm, WorkingForm, ITForm, OfficeForm, DummyForm,\
from .settings import MAILS, EVA_MAIL, BASIC_DATA, ONLY_ONBOARDING
def success(request):
return HttpResponse("Vielen Dank! Du hast E.V.A. erfolgreich ausgefüllt. Die Mails an die Abteilungen wurden versendet.")
return HttpResponse(f"Vielen Dank! Du hast E.V.A. erfolgreich ausgefüllt. Die Mails an die Abteilungen wurden versendet. Kopien gehen an {request.user.email}.")
def long_process(wizard):
'''this method is called via urls.py to determine if a form is part of the IN-Process'''
@ -28,19 +29,19 @@ def long_process(wizard):
return True
else:
data = wizard.get_cleaned_data_for_step('0') or {}
print(data)
# print(data)
if data.get('choice') != 'CHANGE':
wizard.set_choice('IN')
print('PROZESS IN')
# print('PROZESS IN')
return True
else:
wizard.set_choice('CHANGE')
print('PROZESS NOT IN')
# print('PROZESS NOT IN')
return False
def change_process(wizard):
''' this method is called via urls.py to determine if the form is part of the change process'''
print('CHANGE PROZESS')
# print('CHANGE PROZESS')
return not long_process(wizard)
@ -59,10 +60,10 @@ class EvaFormView(LoginRequiredMixin, CookieWizardView):
(first, *_) = data['firstname'].split(maxsplit=1)
(last, *_) = data['lastname'].split(maxsplit=1)
name = first + '.' + last
if not data['intern']:
mail = name + '_ext@wikimedia.de'
else:
mail = name + '@wikimedia.de'
#if not data['intern']:
# mail = name + '_ext@wikimedia.de'
#else:
mail = name + '@wikimedia.de'
data['email'] = mail
def get_all_cleaned_data(self):
@ -72,7 +73,7 @@ class EvaFormView(LoginRequiredMixin, CookieWizardView):
data = super().get_all_cleaned_data()
self.generate_email(data)
print("delete CHOICE FROM DATA")
# print("delete CHOICE FROM DATA")
if 'choice' in data:
del data['choice']
return data
@ -83,8 +84,10 @@ class EvaFormView(LoginRequiredMixin, CookieWizardView):
#print('GETCONTEXT')
context = super().get_context_data(form=form, **kwargs)
testmode = settings.DEBUG or settings.MAILTEST
context.update({'choice': self.choice,
'choice_string': TYPE_CHOICES[self.choice]})
'choice_string': TYPE_CHOICES[self.choice],
'TESTMODE': testmode})
# deliver context for forms if we are in the last step
if (self.steps.step1 == 5 or (self.choice != 'IN' and self.steps.step1 == 3)):
@ -93,7 +96,7 @@ class EvaFormView(LoginRequiredMixin, CookieWizardView):
return context
def get_form_instance(self,step):
''' this method makes shure, that we use the same model instance for all steps'''
''' this method assures, that we use the same model instance for all steps'''
if self.instance == None:
self.instance = Employee()
@ -112,12 +115,15 @@ class EvaFormView(LoginRequiredMixin, CookieWizardView):
# send data to departments
for dep in MAILS:
self.send_mail_to_department(dep)
response = self.send_mail_to_department(dep)
if not settings.DEBUG:
self.instance.delete()
return HttpResponseRedirect('success')
if response:
return response
else:
return HttpResponseRedirect('success')
def send_mail_to_department(self, department):
@ -125,36 +131,45 @@ class EvaFormView(LoginRequiredMixin, CookieWizardView):
print(f'send mail to department {department}...')
contact = self.request.user.email
data = self.get_all_cleaned_data()
# some data should be in every mail
newdata = {k: v for k, v in data.items() if (k in BASIC_DATA)}
# only the relevant data should be in the context
newdata.update({k: v for k, v in data.items() if (k in MAILS[department]['DATA'])})
context = {'data': self.beautify_data(newdata)}
context = {'data': self.beautify_data(newdata), 'contact': contact}
firstname = data['firstname']
lastname = data['lastname']
try:
mail_template = get_template(f'evapp/department_mail.txt')
if settings.MAILTEST:
send_mail(
'EVA: Neuzugang',
f'EVA: Neuzugang {firstname} {lastname} (MAILTEST)',
mail_template.render(context),
EVA_MAIL,
[EVA_MAIL, self.instance.usermail],
[EVA_MAIL, contact],
fail_silently=False)
else:
send_mail(
'EVA: Neuzugang',
f'EVA: Neuzugang {firstname} {lastname}',
mail_template.render(context),
EVA_MAIL,
[MAILS[department]['MAIL'], self.instance.usermail],
[MAILS[department]['MAIL'], contact],
fail_silently=False)
except BadHeaderError:
except BadHeaderError as error:
print(error)
self.instance.delete()
return HttpResponse('Invalid header found. Data not saved!')
except SMTPException:
return HttpResponse(f'{error}<p>Invalid header found. Data not saved!')
except SMTPException as error:
print(error)
self.instance.delete()
return HttpResponse('Error in sending mails (propably wrong adress?). Data not saved!')
return HttpResponse(f'{error}<p>Error in sending mails (propably wrong adress?). Data not saved!')
except Exception as error:
print(error)
# self.instance.delete()
return HttpResponse(f'{error}<p>Error in sending mails. Data not saved! Please contact ' + EVA_MAIL)
return False
def beautify_data(self, data):
''' # use long form for contextdata instead of short form if available

View File

@ -0,0 +1,208 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-02-07 14:44+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: evapp/models.py:10
msgid "Programme"
msgstr "Programs"
#: evapp/models.py:11
msgid "Softwareentwicklung"
msgstr "Software development"
#: evapp/models.py:13
msgid "Kommunikation und Events"
msgstr "Communication and events"
#: evapp/models.py:14
msgid "Vorstand"
msgstr "Board"
#: evapp/models.py:18
msgid "Mac (nur für Grafiker_innen)"
msgstr "Mac (for graphic designer only)"
#: evapp/models.py:21
msgid "Windows (bitte Begründung angeben)"
msgstr "Windows (please give justification)"
#: evapp/models.py:22
msgid "Mac OS (nur wenn Mac gewählt)"
msgstr "Mac OS (only if you choose Mac)"
#: evapp/models.py:30
msgid "Anderes (Bitte unten angeben)"
msgstr "Others (please note below)"
#: evapp/models.py:33
msgid "Civic CRM (allgemein)"
msgstr "Civic CRM (regular)"
#: evapp/models.py:34
msgid "Civic CRM (Mailings, impliziert allgemein)"
msgstr "Civic CRM (mailings, regular implied)"
#: evapp/models.py:40
msgid "Allgemeiner Transponder"
msgstr "Regular Transponder"
#: evapp/models.py:41
msgid "Besondere Schließungen (bitte angeben)"
msgstr "Special Doors (please note below)"
#: evapp/models.py:42
msgid "Kein Transponder"
msgstr "No transponder"
#: evapp/models.py:50 evapp/templates/evapp/department_mail.txt:26
msgid "Vorname"
msgstr "Firstname"
#: evapp/models.py:51
msgid "Nachname"
msgstr "Lastname"
#: evapp/models.py:53
msgid "Bereich"
msgstr "Department"
#: evapp/models.py:57
msgid "Erster Arbeitstag"
msgstr "First workday"
#: evapp/models.py:58
msgid "Erster Tag der Anwesenheit in der Geschäftsstelle"
msgstr "First day in the office"
#: evapp/models.py:61
msgid "Braucht Arbeitsplatz in der Geschäftsstelle?)"
msgstr "Needs a working place in the office"
#: evapp/models.py:62
msgid "Wo soll der Arbeitsplatz sein?"
msgstr "Where should the desk be?"
#: evapp/models.py:65
msgid "Hersteller"
msgstr "Manufacterer"
#: evapp/models.py:66
msgid "Betriebssystem"
msgstr "Operating system"
#: evapp/models.py:67
msgid "Zusätzlicher Monitor? Einer ist standard."
msgstr "Additional monitor. One is standard."
#: evapp/models.py:68
msgid "Diensttelefon (Handy)"
msgstr "work phone (mobile)"
#: evapp/models.py:70
msgid "Tastaturlayout"
msgstr "Keyboard layout"
#: evapp/models.py:71
msgid "zusätzliche IT-Anforderungen"
msgstr "Additional IT requirements"
#: evapp/models.py:72
msgid "Sprache"
msgstr "Language"
#: evapp/models.py:73
msgid "Zusätzliche Accounts"
msgstr "Additional accounts"
#: evapp/models.py:74
msgid "Zusätzliche Mailinglisten"
msgstr "additional mailing lists"
#: evapp/models.py:75
msgid "Rebu2Go-Zugang benötigt?"
msgstr "Needs Rebu2Go account"
#: evapp/models.py:79
msgid "Besondere Schließungen hier eintragen"
msgstr "Special access for doors"
#: evapp/models.py:80
msgid "Postfach am Empfang benötigt?"
msgstr "Needs mailbox at reception"
#: evapp/templates/evapp/employee_form.html:36
msgid "WARNUNG! Test-MODUS aktiviert. Es werden keine Mails verschickt!"
msgstr "ATTENTION! Test mode activated. No mails will be send."
#: evapp/templates/evapp/employee_form.html:40
msgid "Du bist eingeloggt als"
msgstr "You are logged in as"
#: evapp/templates/evapp/employee_form.html:42
msgid "Schritt"
msgstr "Step"
#: evapp/templates/evapp/employee_form.html:42
msgid "von"
msgstr "from"
#: evapp/templates/evapp/employee_form.html:44
msgid "Angaben zur Person"
msgstr "Personal Data"
#: evapp/templates/evapp/employee_form.html:47
msgid "Angaben zum neuen Arbeitsverhältnis"
msgstr "Details of the employment"
#: evapp/templates/evapp/employee_form.html:49
msgid "IT-relevante Angaben"
msgstr "IT-relevant details"
#: evapp/templates/evapp/employee_form.html:51
msgid "Office-relevante Angaben"
msgstr "Office relevant details"
#: evapp/templates/evapp/employee_form.html:59
msgid "Bestätigungsschritt"
msgstr "Confirmation step"
#: evapp/templates/evapp/employee_form.html:91
msgid "Pflichtfeld"
msgstr "Required field"
#: evapp/templates/evapp/employee_form.html:94
msgid "Zurück"
msgstr "Back"
#: evapp/templates/evapp/employee_form.html:97
#: evapp/templates/evapp/employee_form.html:99
msgid "Weiter"
msgstr "Next"
#: evapp/templates/evapp/employee_form.html:97
msgid "Abschicken"
msgstr "Send"
#: evapp/templates/evapp/employee_form.html:103
msgid "logout"
msgstr "logout"
#: evapp/templates/evapp/employee_form.html:107
msgid "Bitte einloggen!"
msgstr "Please log in!"