from django.conf import settings from django.forms import ModelForm, ChoiceField, RadioSelect, BooleanField, CharField, EmailField 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 django import forms from .models import ( TYPE_CHOICES, Project, ConcreteVolunteer, ConcreteExtern, IFG, Library, ELiterature, Software, HonoraryCertificate, Travel, Email, Literature, List, BusinessCard, ) class TableFormRenderer(DjangoTemplates): form_template_name = 'django/forms/table.html' class FdbForm(ModelForm): '''this base class provides the required css class for all forms''' required_css_class = 'required' class ProjectForm(FdbForm): # start = DateField(widget=AdminDateWidget()) class Meta: model = Project exclude = ('pid', 'project_of_year', 'finance_id', 'granted', 'granted_date', 'realname', 'email', \ 'end_mail_send', 'status', 'persons', 'survey_mail_date', 'mail_state') widgets = {'start': AdminDateWidget(), 'end': AdminDateWidget(), } class Media: js = ('dropdown/js/otrs_link.js',) class CommonOrderMixin(forms.Form): """ Ensures a consistent field order for all forms that inherit from this mixin. The goal is to always render: - "realname" and "email" fields at the top, - all other fields in the middle (in the order Django provides), - "check" (terms/privacy checkbox) at the bottom. This keeps the UX consistent across all forms without repeating field_order logic. """ # Fields that should always appear first in the form field_order_head = ('realname', 'email') # Fields that should always appear last in the form field_order_tail = ('check',) # rename if your checkbox field is called differently def __init__(self, *args, **kwargs): """ Override the default form initialization to reorder fields. The method: 1. Collects all existing field names. 2. Puts the 'head' fields first (if they exist in this form). 3. Keeps all other fields in the middle. 4. Puts the 'tail' fields last (if they exist in this form). """ super().__init__(*args, **kwargs) existing = list(self.fields.keys()) # Select only fields that actually exist in this form head = [f for f in self.field_order_head if f in self.fields] tail = [f for f in self.field_order_tail if f in self.fields] # All other fields that are not explicitly in head or tail middle = [f for f in existing if f not in (*head, *tail)] # Apply the new order to the form fields self.order_fields(head + middle + tail) class ExternForm(FdbForm): choice = ChoiceField(choices=TYPE_CHOICES.items(), widget=RadioSelect, label='Was möchtest Du beantragen?') check = BooleanField(required=True, label=format_html("Ich stimme den Datenschutzbestimmungen und der
Richtlinie zur Förderung der Communitys zu", settings.DATAPROTECTION, settings.FOERDERRICHTLINIEN)) class Meta: model = ConcreteExtern exclude = ('username', 'granted', 'granted_date', 'survey_mail_send', 'service_id', 'survey_mail_date', 'mail_state') INTERN_CHOICES = {'PRO': 'Projektsteckbrief', 'HON': 'Ehrenamtsbescheinigung, Akkreditierung oder Redaktionsbestätigung', 'TRAV': 'Reisekostenerstattung'} class InternForm(FdbForm): choice = ChoiceField(choices = INTERN_CHOICES.items(), widget=RadioSelect, label = 'Was möchtest Du eingeben?') class Meta: model = ConcreteVolunteer exclude = ('granted', 'granted_date', 'survey_mail_send', 'survey_mail_date', 'mail_state') HOTEL_CHOICES = {'TRUE': mark_safe('Hotelzimmer benötigt'), 'FALSE': mark_safe('Kein Hotelzimmer benötigt') } class BaseApplicationForm(FdbForm): """ Base form for all external applications. - Adds standard fields that must appear in every form: * realname (applicant's full name) * email (contact address for notifications) * check (confirmation of data protection and funding policy) - Ensures consistency across all application types. """ realname = CharField( label="Realname", required=True, help_text="Bitte gib deinen Vor- und Nachnamen ein." ) email = EmailField( label="E-Mail-Adresse", required=True, help_text="Bitte gib deine E-Mail-Adresse ein, damit dich
Wikimedia Deutschland bei Rückfragen oder für
die Zusage kontaktieren kann." ) check = BooleanField(required=True, label=format_html( "Ich stimme den Datenschutzbestimmungen und der
Richtlinie zur Förderung der Communitys zu", settings.DATAPROTECTION, settings.FOERDERRICHTLINIEN)) class TravelForm(BaseApplicationForm, CommonOrderMixin): # TODO: add some javascript to show/hide other-field # 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 self.fields['hotel'].required = True class Meta: model = Travel exclude = ('granted', 'granted_date', 'survey_mail_send', 'realname', 'email', 'survey_mail_date', 'project', 'request_url', 'payed_for_hotel_by', 'payed_for_travel_by', 'intern_notes', 'mail_state' ) widgets = {'checkin': AdminDateWidget(), 'checkout': AdminDateWidget(),} fields = ['project_name', 'transport', 'travelcost', 'checkin', 'checkout', 'hotel', 'notes'] hotel = ChoiceField(label='Hotelzimmer benötigt:', choices=HOTEL_CHOICES.items(), widget=RadioSelect()) class Media: js = ('dropdown/js/otrs_link.js',) css = { 'all': ('css/dateFieldNoNowShortcutInTravels.css',) } class LibraryForm(BaseApplicationForm, CommonOrderMixin): class Meta: model = Library 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: model = HonoraryCertificate fields = ['request_url', 'project'] exclude = ['intern_notes'] class Media: js = ('dropdown/js/otrs_link.js',) class IFGForm(BaseApplicationForm, CommonOrderMixin): class Meta: model = IFG fields = ['cost', 'url', 'notes'] exclude = ['intern_notes', 'survey_mail_send', 'mail_state'] class CheckForm(FdbForm): termstoaccept = settings.NUTZUNGSBEDINGUNGEN def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields['check'] = BooleanField( required=True, label=format_html( "Ich stimme den Nutzungsbedingungen 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 Nutzungsbedingungen zu", # termstoaccept)) # NUTZUNGSBEDINGUNGEN)) class LiteratureForm(BaseApplicationForm, CommonOrderMixin): termstoaccept = settings.NUTZUNGSBEDINGUNGEN_LITERATURSTIPENDIUM def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields['selfbuy_give_data'].required = True class Meta: model = Literature fields = ['cost', 'info', 'source', 'notes', 'selfbuy', 'selfbuy_data', 'selfbuy_give_data'] exclude = ['intern_notes', 'survey_mail_send', 'mail_state'] class Media: js = ('dropdown/js/literature.js',) ADULT_CHOICES = {'TRUE': mark_safe('Ich bin volljährig.'), 'FALSE': mark_safe('Ich bin noch nicht volljährig.') } class EmailForm(BaseApplicationForm, CommonOrderMixin): termstoaccept = settings.NUTZUNGSBEDINGUNGEN_EMAIL_SERVICE # 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 self.fields['other'].required = True adult = ChoiceField(label='Volljährigkeit', choices=ADULT_CHOICES.items(), widget=RadioSelect()) # TODO: add some javascript to show/hide other-field class Meta: model = Email fields = ['domain', 'address', 'other', 'adult'] exclude = ['intern_notes', 'survey_mail_send', 'mail_state'] class Media: js = ('dropdown/js/mail.js',) class BusinessCardForm(BaseApplicationForm, CommonOrderMixin): termstoaccept = settings.NUTZUNGSBEDINGUNGEN_VISITENKARTEN # this is the code, to change required to false if needed def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields['url_of_pic'].required = True self.fields['send_data_to_print'].required = True 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'] class Media: js = ('dropdown/js/businessCard.js',) class ListForm(BaseApplicationForm, CommonOrderMixin): termstoaccept = settings.NUTZUNGSBEDINGUNGEN_MAILINGLISTEN class Meta: model = List fields = ['domain', 'address'] exclude = ['intern_notes', 'survey_mail_send','mail_state']