2025-10-15 12:46:28 +00:00
|
|
|
from django import forms
|
2025-08-19 07:45:14 +00:00
|
|
|
from django.conf import settings
|
2020-09-29 10:16:10 +00:00
|
|
|
from django.contrib.admin.widgets import AdminDateWidget
|
2025-10-20 13:36:21 +00:00
|
|
|
from django.forms import ModelForm
|
2025-08-20 12:28:46 +00:00
|
|
|
from django.forms.renderers import DjangoTemplates
|
2020-10-20 12:12:12 +00:00
|
|
|
from django.utils.html import format_html
|
2025-08-19 14:08:48 +00:00
|
|
|
from django.utils.safestring import mark_safe
|
2025-10-15 12:46:28 +00:00
|
|
|
|
2025-08-20 10:06:43 +00:00
|
|
|
from .models import (
|
|
|
|
|
Project,
|
2025-10-16 10:16:08 +00:00
|
|
|
ProjectCategory,
|
|
|
|
|
WikimediaProject,
|
2025-08-20 10:06:43 +00:00
|
|
|
IFG,
|
|
|
|
|
Library,
|
|
|
|
|
ELiterature,
|
|
|
|
|
Software,
|
|
|
|
|
Travel,
|
|
|
|
|
Email,
|
|
|
|
|
Literature,
|
|
|
|
|
List,
|
|
|
|
|
BusinessCard,
|
|
|
|
|
)
|
2020-09-29 07:54:31 +00:00
|
|
|
|
2020-11-17 15:11:10 +00:00
|
|
|
|
2025-08-20 12:28:46 +00:00
|
|
|
class TableFormRenderer(DjangoTemplates):
|
2025-08-31 21:38:22 +00:00
|
|
|
"""
|
2025-10-20 13:36:21 +00:00
|
|
|
Set in settings as the default form renderer.
|
2025-08-31 21:38:22 +00:00
|
|
|
"""
|
|
|
|
|
|
2025-10-20 13:36:21 +00:00
|
|
|
form_template_name = 'django/forms/table.html'
|
2020-10-21 07:54:12 +00:00
|
|
|
|
|
|
|
|
|
2025-10-20 13:36:21 +00:00
|
|
|
class RadioField(forms.ChoiceField):
|
|
|
|
|
widget = forms.RadioSelect
|
2020-10-21 07:54:12 +00:00
|
|
|
|
2023-02-27 17:09:29 +00:00
|
|
|
|
2025-10-20 13:36:21 +00:00
|
|
|
class BaseApplicationForm(ModelForm):
|
2025-08-31 21:38:22 +00:00
|
|
|
"""
|
|
|
|
|
Base form for all external applications.
|
|
|
|
|
"""
|
2025-10-20 13:36:21 +00:00
|
|
|
|
|
|
|
|
required_css_class = 'required'
|
|
|
|
|
|
|
|
|
|
check = forms.BooleanField(
|
2025-08-31 21:38:22 +00:00
|
|
|
required=True,
|
2025-10-20 13:36:21 +00:00
|
|
|
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.""",
|
|
|
|
|
settings.DATAPROTECTION,
|
|
|
|
|
settings.FOERDERRICHTLINIEN
|
|
|
|
|
),
|
2025-08-31 21:38:22 +00:00
|
|
|
)
|
2023-02-27 17:09:29 +00:00
|
|
|
|
|
|
|
|
|
2025-10-16 13:38:41 +00:00
|
|
|
PROJECT_COST_GT_1000_MESSAGE = format_html(
|
|
|
|
|
"""Bitte beachte, dass für Projektkosten über 1.000 € ein öffentlicher Projektplan erforderlich
|
|
|
|
|
ist (siehe <a href="{0}" target="blank_">Wikipedia:Förderung/Projektplanung)</a>.""",
|
|
|
|
|
'https://de.wikipedia.org/wiki/Wikipedia:F%C3%B6rderung/Projektplanung'
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
2025-10-16 10:16:08 +00:00
|
|
|
class BaseProjectForm(ModelForm):
|
|
|
|
|
categories = {
|
|
|
|
|
'categories': ProjectCategory,
|
|
|
|
|
'wikimedia_projects': WikimediaProject,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class Media:
|
|
|
|
|
js = ('dropdown/js/otrs_link.js', 'js/project-categories.js')
|
|
|
|
|
|
|
|
|
|
def clean(self):
|
|
|
|
|
cleaned_data = ModelForm.clean(self)
|
|
|
|
|
|
|
|
|
|
if self.errors:
|
|
|
|
|
return cleaned_data
|
|
|
|
|
|
|
|
|
|
for field, model in self.categories.items():
|
|
|
|
|
field_other = f'{field}_other'
|
|
|
|
|
values = cleaned_data[field]
|
|
|
|
|
|
|
|
|
|
if model.other in values:
|
|
|
|
|
if not cleaned_data[field_other]:
|
2025-10-16 15:00:40 +00:00
|
|
|
self.add_error(field_other, f'Bitte gib einen Wert an oder deselektiere "{model.OTHER}".')
|
2025-10-16 10:16:08 +00:00
|
|
|
else:
|
|
|
|
|
cleaned_data[field_other] = ''
|
|
|
|
|
|
|
|
|
|
return cleaned_data
|
|
|
|
|
|
|
|
|
|
|
2025-10-20 13:36:21 +00:00
|
|
|
class ProjectForm(BaseProjectForm, BaseApplicationForm):
|
2025-10-16 10:16:08 +00:00
|
|
|
OPTIONAL_FIELDS = {
|
|
|
|
|
'categories_other',
|
|
|
|
|
'wikimedia_projects_other',
|
|
|
|
|
'page',
|
|
|
|
|
'group',
|
|
|
|
|
'location',
|
|
|
|
|
'insurance',
|
|
|
|
|
'notes',
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
|
|
|
|
|
|
for field in set(self.fields) - self.OPTIONAL_FIELDS:
|
|
|
|
|
self.fields[field].required = True
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
model = Project
|
|
|
|
|
fields = [
|
2025-10-20 13:36:21 +00:00
|
|
|
'realname',
|
|
|
|
|
'email',
|
2025-10-16 10:16:08 +00:00
|
|
|
'name',
|
|
|
|
|
'description',
|
|
|
|
|
'categories',
|
|
|
|
|
'categories_other',
|
|
|
|
|
'wikimedia_projects',
|
|
|
|
|
'wikimedia_projects_other',
|
|
|
|
|
'start',
|
|
|
|
|
'end',
|
|
|
|
|
'participants_estimated',
|
|
|
|
|
'page',
|
|
|
|
|
'group',
|
|
|
|
|
'location',
|
|
|
|
|
'cost',
|
|
|
|
|
'insurance',
|
|
|
|
|
'notes',
|
|
|
|
|
]
|
|
|
|
|
widgets = {
|
|
|
|
|
'start': AdminDateWidget,
|
|
|
|
|
'end': AdminDateWidget,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class Media:
|
|
|
|
|
css = {
|
|
|
|
|
'all': ('css/dateFieldNoNowShortcutInTravels.css',)
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-16 13:38:41 +00:00
|
|
|
def clean_cost(self):
|
|
|
|
|
cost = self.cleaned_data['cost']
|
|
|
|
|
|
|
|
|
|
if cost > 1000:
|
|
|
|
|
raise forms.ValidationError(PROJECT_COST_GT_1000_MESSAGE, code='cost-gt-1000')
|
|
|
|
|
|
|
|
|
|
return cost
|
|
|
|
|
|
2025-10-16 10:16:08 +00:00
|
|
|
|
2025-10-15 12:46:28 +00:00
|
|
|
HOTEL_CHOICES = {
|
|
|
|
|
'TRUE': mark_safe('Hotelzimmer benötigt'),
|
|
|
|
|
'FALSE': mark_safe('Kein Hotelzimmer benötigt'),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2025-10-20 13:36:21 +00:00
|
|
|
class TravelForm(BaseApplicationForm):
|
2020-11-03 11:56:40 +00:00
|
|
|
# TODO: add some javascript to show/hide other-field
|
2025-08-19 12:10:15 +00:00
|
|
|
|
2025-10-20 13:36:21 +00:00
|
|
|
hotel = RadioField(label='Hotelzimmer benötigt', choices=HOTEL_CHOICES)
|
2025-10-15 12:46:28 +00:00
|
|
|
|
2023-02-27 17:09:29 +00:00
|
|
|
# this is the code, to change required to false if needed
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
|
self.fields['project_name'].required = True
|
|
|
|
|
self.fields['transport'].required = True
|
|
|
|
|
self.fields['travelcost'].required = True
|
|
|
|
|
self.fields['checkin'].required = True
|
|
|
|
|
self.fields['checkout'].required = True
|
2023-02-27 17:09:29 +00:00
|
|
|
self.fields['hotel'].required = True
|
2023-02-27 17:09:29 +00:00
|
|
|
|
2020-10-26 10:38:56 +00:00
|
|
|
class Meta:
|
|
|
|
|
model = Travel
|
2025-10-20 13:36:21 +00:00
|
|
|
fields = [
|
|
|
|
|
'realname',
|
|
|
|
|
'email',
|
|
|
|
|
'project_name',
|
|
|
|
|
'transport',
|
|
|
|
|
'travelcost',
|
|
|
|
|
'checkin',
|
|
|
|
|
'checkout',
|
|
|
|
|
'hotel',
|
|
|
|
|
'notes',
|
|
|
|
|
]
|
2025-10-15 12:46:28 +00:00
|
|
|
widgets = {
|
|
|
|
|
'checkin': AdminDateWidget,
|
|
|
|
|
'checkout': AdminDateWidget,
|
|
|
|
|
}
|
2020-10-21 07:54:12 +00:00
|
|
|
|
2023-02-27 17:09:29 +00:00
|
|
|
class Media:
|
2025-02-26 12:13:46 +00:00
|
|
|
js = ('dropdown/js/otrs_link.js',)
|
2023-02-27 17:09:29 +00:00
|
|
|
css = {
|
2025-10-15 12:46:28 +00:00
|
|
|
'all': ('css/dateFieldNoNowShortcutInTravels.css',)
|
2023-02-27 17:09:29 +00:00
|
|
|
}
|
|
|
|
|
|
2025-08-20 10:06:43 +00:00
|
|
|
|
2025-10-20 13:36:21 +00:00
|
|
|
class LibraryForm(BaseApplicationForm):
|
2020-10-19 11:29:36 +00:00
|
|
|
|
2020-10-01 08:51:19 +00:00
|
|
|
class Meta:
|
|
|
|
|
model = Library
|
2025-10-20 13:36:21 +00:00
|
|
|
fields = [
|
|
|
|
|
'realname',
|
|
|
|
|
'email',
|
|
|
|
|
'cost',
|
|
|
|
|
'library',
|
|
|
|
|
'duration',
|
|
|
|
|
'notes',
|
|
|
|
|
]
|
2020-10-01 08:51:19 +00:00
|
|
|
|
2025-08-20 10:06:43 +00:00
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
2025-10-20 13:36:21 +00:00
|
|
|
class IFGForm(BaseApplicationForm):
|
2020-11-18 17:02:23 +00:00
|
|
|
|
2020-10-01 08:51:19 +00:00
|
|
|
class Meta:
|
2020-10-01 10:08:02 +00:00
|
|
|
model = IFG
|
2025-10-20 13:36:21 +00:00
|
|
|
fields = [
|
|
|
|
|
'realname',
|
|
|
|
|
'email',
|
|
|
|
|
'cost',
|
|
|
|
|
'url',
|
|
|
|
|
'notes',
|
|
|
|
|
]
|
2020-10-21 07:54:12 +00:00
|
|
|
|
2020-10-27 10:00:58 +00:00
|
|
|
|
2025-10-20 13:36:21 +00:00
|
|
|
class TermsForm(BaseApplicationForm):
|
|
|
|
|
terms_accepted_label = 'Ich stimme den <a href="{}">Nutzungsbedingungen</a> zu.'
|
|
|
|
|
terms_accepted_url = settings.NUTZUNGSBEDINGUNGEN
|
2025-06-16 09:43:08 +00:00
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
|
super().__init__(*args, **kwargs)
|
2025-08-26 20:48:13 +00:00
|
|
|
|
2025-10-20 13:36:21 +00:00
|
|
|
self.fields['terms_accepted'].required = True
|
|
|
|
|
self.fields['terms_accepted'].label = format_html(self.terms_accepted_label, self.terms_accepted_url)
|
2020-11-18 17:02:23 +00:00
|
|
|
|
2023-02-27 17:09:29 +00:00
|
|
|
|
2025-10-20 13:36:21 +00:00
|
|
|
class LiteratureForm(TermsForm):
|
|
|
|
|
terms_accepted_url = settings.NUTZUNGSBEDINGUNGEN_LITERATURSTIPENDIUM
|
2025-06-16 09:43:08 +00:00
|
|
|
|
2023-02-27 17:09:28 +00:00
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
|
super().__init__(*args, **kwargs)
|
2023-02-27 17:09:29 +00:00
|
|
|
self.fields['selfbuy_give_data'].required = True
|
2025-10-15 12:46:28 +00:00
|
|
|
|
2020-10-27 12:47:46 +00:00
|
|
|
class Meta:
|
|
|
|
|
model = Literature
|
2025-10-20 13:36:21 +00:00
|
|
|
fields = [
|
|
|
|
|
'realname',
|
|
|
|
|
'email',
|
|
|
|
|
'cost',
|
|
|
|
|
'info',
|
|
|
|
|
'source',
|
|
|
|
|
'notes',
|
|
|
|
|
'selfbuy',
|
|
|
|
|
'selfbuy_data',
|
|
|
|
|
'selfbuy_give_data',
|
|
|
|
|
'terms_accepted',
|
|
|
|
|
]
|
2025-10-15 12:46:28 +00:00
|
|
|
|
2023-02-27 17:09:28 +00:00
|
|
|
class Media:
|
2023-02-27 17:09:29 +00:00
|
|
|
js = ('dropdown/js/literature.js',)
|
2020-10-27 12:47:46 +00:00
|
|
|
|
2023-02-27 17:09:29 +00:00
|
|
|
|
2025-10-15 12:46:28 +00:00
|
|
|
ADULT_CHOICES = {
|
|
|
|
|
'TRUE': mark_safe('Ich bin volljährig.'),
|
|
|
|
|
'FALSE': mark_safe('Ich bin noch nicht volljährig.'),
|
|
|
|
|
}
|
2023-02-27 17:09:29 +00:00
|
|
|
|
2025-06-16 09:43:08 +00:00
|
|
|
|
2025-10-20 13:36:21 +00:00
|
|
|
class EmailForm(TermsForm):
|
|
|
|
|
terms_accepted_url = settings.NUTZUNGSBEDINGUNGEN_EMAIL_SERVICE
|
2025-08-19 12:10:15 +00:00
|
|
|
|
2023-02-27 17:09:29 +00:00
|
|
|
# this is the code, to change required to false if needed
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
|
self.fields['adult'].required = True
|
2023-02-27 17:09:29 +00:00
|
|
|
self.fields['other'].required = True
|
2023-02-27 17:09:29 +00:00
|
|
|
|
2025-10-20 13:36:21 +00:00
|
|
|
adult = RadioField(label='Volljährigkeit', choices=ADULT_CHOICES)
|
2023-02-27 17:09:29 +00:00
|
|
|
|
2020-10-27 10:00:58 +00:00
|
|
|
# TODO: add some javascript to show/hide other-field
|
|
|
|
|
class Meta:
|
|
|
|
|
model = Email
|
2025-10-20 13:36:21 +00:00
|
|
|
fields = [
|
|
|
|
|
'realname',
|
|
|
|
|
'email',
|
|
|
|
|
'domain',
|
|
|
|
|
'address',
|
|
|
|
|
'other',
|
|
|
|
|
'adult',
|
|
|
|
|
'terms_accepted',
|
|
|
|
|
]
|
2025-10-15 12:46:28 +00:00
|
|
|
|
2023-02-27 17:09:28 +00:00
|
|
|
class Media:
|
2023-02-27 17:09:29 +00:00
|
|
|
js = ('dropdown/js/mail.js',)
|
2023-02-27 17:09:28 +00:00
|
|
|
|
|
|
|
|
|
2025-10-20 13:36:21 +00:00
|
|
|
class BusinessCardForm(TermsForm):
|
|
|
|
|
terms_accepted_url = settings.NUTZUNGSBEDINGUNGEN_VISITENKARTEN
|
2025-10-15 12:46:28 +00:00
|
|
|
|
2025-06-16 09:43:08 +00:00
|
|
|
# this is the code, to change required to false if needed
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
2023-02-27 17:09:28 +00:00
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
|
self.fields['url_of_pic'].required = True
|
2023-02-27 17:09:29 +00:00
|
|
|
self.fields['send_data_to_print'].required = True
|
2023-02-27 17:09:28 +00:00
|
|
|
|
2025-06-16 09:43:08 +00:00
|
|
|
class Meta:
|
2020-10-27 12:47:46 +00:00
|
|
|
model = BusinessCard
|
2025-10-20 13:36:21 +00:00
|
|
|
fields = [
|
|
|
|
|
'realname',
|
|
|
|
|
'email',
|
|
|
|
|
'project',
|
|
|
|
|
'data',
|
|
|
|
|
'variant',
|
|
|
|
|
'url_of_pic',
|
|
|
|
|
'send_data_to_print',
|
|
|
|
|
'sent_to',
|
|
|
|
|
'terms_accepted',
|
|
|
|
|
]
|
2025-10-15 12:46:28 +00:00
|
|
|
|
2025-06-16 09:43:08 +00:00
|
|
|
class Media:
|
2023-02-27 17:09:29 +00:00
|
|
|
js = ('dropdown/js/businessCard.js',)
|
2020-10-27 12:47:46 +00:00
|
|
|
|
2023-02-27 17:09:29 +00:00
|
|
|
|
2025-10-20 13:36:21 +00:00
|
|
|
class ListForm(TermsForm):
|
|
|
|
|
terms_accepted_url = settings.NUTZUNGSBEDINGUNGEN_MAILINGLISTEN
|
2025-10-15 12:46:28 +00:00
|
|
|
|
2020-10-27 12:47:46 +00:00
|
|
|
class Meta:
|
|
|
|
|
model = List
|
2025-10-20 13:36:21 +00:00
|
|
|
fields = [
|
|
|
|
|
'realname',
|
|
|
|
|
'email',
|
|
|
|
|
'domain',
|
|
|
|
|
'address',
|
|
|
|
|
'terms_accepted',
|
|
|
|
|
]
|
2025-10-14 09:16:13 +00:00
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
|
|
|
|
|
|
self.fields['address'].initial = ''
|