from smtplib import SMTPException from django.shortcuts import render from django.http import HttpResponse from django.utils.safestring import mark_safe from formtools.wizard.views import CookieWizardView from django.core.mail import BadHeaderError, EmailMultiAlternatives from django.template.loader import get_template from django.conf import settings from django.contrib.auth.decorators import login_required from django.views.generic.edit import FormView 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 LIBRARY_FORMS = { TYPE_BIB: LibraryForm, TYPE_ELIT: ELiteratureForm, TYPE_SOFT: SoftwareForm, } HELP_TEXTS = { 'IFG': { 'notes': ( 'Bitte gib an, wie die gewonnenen Informationen den
' 'Wikimedia-Projekten zugute kommen sollen.' ) }, 'MAIL': { 'domain': ( 'Mit welcher Domain, bzw. für welches Wikimedia-Projekt,
' 'möchtest du eine Mailadresse beantragen?' ) }, 'LIT': { 'notes': 'Bitte gib an, wofür du die Literatur verwenden möchtest.' }, 'LIST': { 'domain': ( 'Mit welcher Domain, bzw. für welches Wikimedia-Projekt,
' 'möchtest du eine Mailingliste beantragen?' ) }, } def auth_deny(choice, pk, auth): if choice not in MODELS: return HttpResponse(f'ERROR! UNKNOWN CHOICE TYPE! {choice}') 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.''' 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.''' if ret := auth_deny(choice, pk, False): return ret else: return HttpResponse(f'DENIED! choice: {choice}, pk: {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 BaseApplicationView(FormView): """ Base view for all application types. - Each application type (travel, literature, email, etc.) gets its own subclass. - Renders the generic form template. - Handles saving the submitted form to the database. - Adds extra fields from the session or request type if needed. - Applies optional help_text overrides for certain fields. - Sends confirmation mail to the applicant. - Sends notification mail to the internal IF address. - Returns the "done" response after successful processing. """ template_name = 'input/forms/form_generic.html' type_code: str = '' def get_context_data(self, **kwargs): """Add the human-readable type string (from TYPE_CHOICES) to the template context.""" ctx = super().get_context_data(**kwargs) ctx['typestring'] = TYPE_CHOICES.get(self.type_code, self.type_code) return ctx def get_form(self, form_class=None): """Return the form instance and inject custom help_texts if defined for this type.""" form = super().get_form(form_class) # Apply help_text overrides if defined for this type_code if self.type_code in HELP_TEXTS: for field, text in HELP_TEXTS[self.type_code].items(): if field in form.fields: form.fields[field].help_text = mark_safe(text) return form def form_valid(self, form): """ Process a valid form submission: - Enrich form data (e.g., set type_code, handle special rules). - Save the model instance and related data. - Send confirmation and notification mails. - Return the "done" response. """ # Collect cleaned data and mark the current type data = form.cleaned_data.copy() data['choice'] = self.type_code # Special rule for literature applications if self.type_code == 'LIT' and data.get('selfbuy') == 'TRUE': data['selfbuy_give_data'] = 'False' # Save model instance modell = form.save(commit=False) # Username from session if present user = self.request.session.get('user') if user: modell.username = user.get('username') # Copy common fields if provided by the form if 'realname' in data: modell.realname = data['realname'] if 'email' in data: modell.email = data['email'] # Set model.type for specific request types if self.type_code in ('BIB', 'ELIT', 'SOFT'): modell.type = self.type_code # Literature-specific extra field if self.type_code == 'LIT' and 'selfbuy_give_data' in data: modell.selfbuy_give_data = data['selfbuy_give_data'] modell.save() if hasattr(form, 'save_m2m'): form.save_m2m() # Prepare minimal mail context and send mails data['pk'] = modell.pk data['url_prefix'] = settings.EMAIL_URL_PREFIX data['typestring'] = TYPE_CHOICES.get(self.type_code, self.type_code) context = {'data': data} try: # Mail to applicant txt1 = get_template('input/ifg_volunteer_mail.txt').render(context) html1 = get_template('input/ifg_volunteer_mail.html').render(context) msg1 = EmailMultiAlternatives( 'Formular ausgefüllt', txt1, settings.IF_EMAIL, [data['email']] ) msg1.attach_alternative(html1, 'text/html') msg1.send() # Mail to IF txt2 = get_template('input/if_mail.txt').render(context) html2 = get_template('input/if_mail.html').render(context) msg2 = EmailMultiAlternatives( 'Formular ausgefüllt', txt2, settings.IF_EMAIL, [settings.IF_EMAIL] ) msg2.attach_alternative(html2, 'text/html') msg2.send() except BadHeaderError: modell.delete() return HttpResponse('Invalid header found. Data not saved!') except SMTPException: modell.delete() return HttpResponse('Error in sending mails (probably wrong adress?). Data not saved!') return done(self.request) class TravelApplicationView(BaseApplicationView): form_class = TravelForm type_code = 'TRAV' class LibraryApplicationView(BaseApplicationView): form_class = LibraryForm type_code = 'BIB' class ELiteratureApplicationView(BaseApplicationView): form_class = ELiteratureForm type_code = 'ELIT' class SoftwareApplicationView(BaseApplicationView): form_class = SoftwareForm type_code = 'SOFT' class IFGApplicationView(BaseApplicationView): form_class = IFGForm type_code = 'IFG' class EmailApplicationView(BaseApplicationView): form_class = EmailForm type_code = 'MAIL' class LiteratureApplicationView(BaseApplicationView): form_class = LiteratureForm type_code = 'LIT' class ListApplicationView(BaseApplicationView): form_class = ListForm type_code = 'LIST' class BusinessCardApplicationView(BaseApplicationView): form_class = BusinessCardForm type_code = 'VIS'