foerderbarometer/input/views.py

257 lines
7.8 KiB
Python
Executable File

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<br>"
"Wikimedia-Projekten zugute kommen sollen."
)
},
"MAIL": {
"domain": (
"Mit welcher Domain, bzw. für welches Wikimedia-Projekt,<br>"
"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,<br>"
"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"