2020-11-16 14:53:43 +00:00
from smtplib import SMTPException
2025-10-14 09:39:58 +00:00
from typing import NamedTuple
2020-10-26 11:34:09 +00:00
2020-09-21 12:27:16 +00:00
from django . shortcuts import render
2025-10-14 09:39:58 +00:00
from django . http import HttpResponse , Http404
from django . utils . functional import cached_property
2025-08-19 14:08:48 +00:00
from django . utils . safestring import mark_safe
from django . core . mail import BadHeaderError , EmailMultiAlternatives
2020-10-07 13:07:02 +00:00
from django . template . loader import get_template
2025-08-19 07:45:14 +00:00
from django . conf import settings
2020-10-28 14:49:18 +00:00
from django . contrib . auth . decorators import login_required
2025-10-14 09:39:58 +00:00
from django . views . generic import TemplateView
2025-08-31 21:41:11 +00:00
from django . views . generic . edit import FormView
2020-09-22 10:21:05 +00:00
2025-08-20 10:06:43 +00:00
from . forms import (
2025-10-14 09:39:58 +00:00
BaseApplicationForm ,
2025-08-20 10:06:43 +00:00
LibraryForm ,
ELiteratureForm ,
SoftwareForm ,
IFGForm ,
LiteratureForm ,
TravelForm ,
EmailForm ,
ListForm ,
BusinessCardForm ,
)
2025-10-14 09:39:58 +00:00
from . models import (
MODELS ,
LIBRARY_TYPES ,
TYPE_CHOICES ,
TYPE_BIB ,
TYPE_ELIT ,
TYPE_IFG ,
TYPE_LIT ,
TYPE_LIST ,
TYPE_MAIL ,
TYPE_SOFT ,
TYPE_TRAV ,
TYPE_VIS ,
)
2025-08-20 10:06:43 +00:00
2025-08-31 21:41:11 +00:00
HELP_TEXTS = {
2025-10-14 09:39:58 +00:00
TYPE_IFG : {
2025-09-01 11:24:59 +00:00
' notes ' : (
' Bitte gib an, wie die gewonnenen Informationen den<br> '
' Wikimedia-Projekten zugute kommen sollen. '
2025-08-31 21:41:11 +00:00
)
} ,
2025-10-14 09:39:58 +00:00
TYPE_MAIL : {
2025-09-01 11:24:59 +00:00
' domain ' : (
' Mit welcher Domain, bzw. für welches Wikimedia-Projekt,<br> '
' möchtest du eine Mailadresse beantragen? '
2025-08-31 21:41:11 +00:00
)
} ,
2025-10-14 09:39:58 +00:00
TYPE_LIT : {
2025-09-01 11:24:59 +00:00
' notes ' : ' Bitte gib an, wofür du die Literatur verwenden möchtest. '
2025-08-31 21:41:11 +00:00
} ,
2025-10-14 09:39:58 +00:00
TYPE_LIST : {
2025-09-01 11:24:59 +00:00
' domain ' : (
' Mit welcher Domain, bzw. für welches Wikimedia-Projekt,<br> '
' möchtest du eine Mailingliste beantragen? '
2025-08-31 21:41:11 +00:00
)
} ,
}
2025-08-20 10:06:43 +00:00
2025-10-14 09:39:58 +00:00
class ApplicationType ( NamedTuple ) :
code : str
path : str
form_class : type [ BaseApplicationForm ]
@property
def label ( self ) :
return TYPE_CHOICES [ self . code ]
@property
def help_texts ( self ) :
return HELP_TEXTS . get ( self . code )
TYPES = [
ApplicationType ( TYPE_BIB , ' bibliotheksstipendium ' , LibraryForm ) ,
ApplicationType ( TYPE_ELIT , ' eliteraturstipendium ' , ELiteratureForm ) ,
ApplicationType ( TYPE_MAIL , ' email ' , EmailForm ) ,
ApplicationType ( TYPE_IFG , ' ifg ' , IFGForm ) ,
ApplicationType ( TYPE_LIT , ' literaturstipendium ' , LiteratureForm ) ,
ApplicationType ( TYPE_LIST , ' mailingliste ' , ListForm ) ,
ApplicationType ( TYPE_TRAV , ' reisekosten ' , TravelForm ) ,
ApplicationType ( TYPE_SOFT , ' softwarestipendium ' , SoftwareForm ) ,
ApplicationType ( TYPE_VIS , ' visitenkarten ' , BusinessCardForm ) ,
]
2025-08-20 10:06:43 +00:00
def auth_deny ( choice , pk , auth ) :
if choice not in MODELS :
2021-01-04 10:24:20 +00:00
return HttpResponse ( f ' ERROR! UNKNOWN CHOICE TYPE! { choice } ' )
2025-08-20 10:06:43 +00:00
MODELS [ choice ] . set_granted ( pk , auth )
2025-08-21 08:08:38 +00:00
2020-11-19 14:55:10 +00:00
@login_required
def export ( request ) :
''' export the project database to a csv '''
return HttpResponse ( ' WE WANT CSV! ' )
2021-01-04 09:44:03 +00:00
2025-08-21 08:08:38 +00:00
2020-10-28 14:49:18 +00:00
@login_required
2020-10-20 06:39:00 +00:00
def authorize ( request , choice , pk ) :
2020-10-21 07:54:12 +00:00
''' 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 . '''
2025-08-21 08:42:55 +00:00
if ret := auth_deny ( choice , pk , True ) :
2020-10-27 12:47:46 +00:00
return ret
2020-10-20 07:35:04 +00:00
else :
2025-09-01 11:24:59 +00:00
return HttpResponse ( f ' AUTHORIZED! choice: { choice } , pk: { pk } ' )
2020-10-20 07:35:04 +00:00
2025-08-21 08:08:38 +00:00
2020-10-28 14:49:18 +00:00
@login_required
2020-10-20 06:39:00 +00:00
def deny ( request , choice , pk ) :
2020-10-21 07:54:12 +00:00
''' If IF denies a support they click a link in a mail which leads here
We write the granted field in the database here . '''
2020-10-21 07:22:53 +00:00
2025-08-21 08:42:55 +00:00
if ret := auth_deny ( choice , pk , False ) :
2020-10-27 12:47:46 +00:00
return ret
2020-10-20 07:35:04 +00:00
else :
2025-09-01 11:24:59 +00:00
return HttpResponse ( f ' DENIED! choice: { choice } , pk: { pk } ' )
2020-10-20 07:35:04 +00:00
2020-10-20 06:06:36 +00:00
2020-09-29 09:08:16 +00:00
def done ( request ) :
2025-08-31 21:41:11 +00:00
return HttpResponse (
2025-09-01 11:24:59 +00:00
' 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. ' )
2020-09-30 12:26:08 +00:00
2025-08-21 08:02:19 +00:00
2024-01-07 14:13:21 +00:00
def index ( request ) :
return render ( request , ' input/index.html ' )
2020-10-28 14:49:18 +00:00
2020-11-18 15:03:27 +00:00
2025-10-14 09:39:58 +00:00
class ApplicationStartView ( TemplateView ) :
template_name = ' input/forms/extern.html '
extra_context = { ' types ' : TYPES }
class ProjectInfoView ( TemplateView ) :
template_name = ' input/info_project_funding_gt_1000.html '
class ApplicationView ( FormView ) :
2025-08-31 21:41:11 +00:00
"""
2025-10-14 09:39:58 +00:00
View for all application types .
2025-08-31 21:41:11 +00:00
- 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 .
"""
2025-10-14 09:39:58 +00:00
2025-09-01 11:24:59 +00:00
template_name = ' input/forms/form_generic.html '
2025-10-14 09:39:58 +00:00
@cached_property
def type_info ( self ) - > ApplicationType :
type_path = self . kwargs [ ' type ' ]
for type_info in TYPES :
if type_path == type_info . path :
return type_info
raise Http404 ( f ' " { type_path } " existiert nicht. ' )
@property
def type_code ( self ) :
return self . type_info . code
@property
def form_class ( self ) :
return self . type_info . form_class
2020-10-05 13:10:23 +00:00
2020-11-18 11:05:18 +00:00
def get_context_data ( self , * * kwargs ) :
2025-10-14 09:39:58 +00:00
return super ( ) . get_context_data ( * * kwargs , type_label = self . type_info . label )
2025-08-18 14:32:31 +00:00
2025-08-31 21:41:11 +00:00
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 )
2023-02-27 17:09:29 +00:00
2025-08-31 21:41:11 +00:00
# Apply help_text overrides if defined for this type_code
2025-10-14 09:39:58 +00:00
if help_texts := self . type_info . help_texts :
for field , text in help_texts . items ( ) :
2025-08-31 21:41:11 +00:00
if field in form . fields :
form . fields [ field ] . help_text = mark_safe ( text )
2025-08-18 14:33:04 +00:00
2025-08-31 21:41:11 +00:00
return form
2023-02-27 17:09:29 +00:00
2025-08-31 21:41:11 +00:00
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 .
"""
2020-10-05 11:35:28 +00:00
2025-08-31 21:41:11 +00:00
# Collect cleaned data and mark the current type
data = form . cleaned_data . copy ( )
2025-09-01 11:24:59 +00:00
data [ ' choice ' ] = self . type_code
2020-10-20 06:06:36 +00:00
2025-08-31 21:41:11 +00:00
# Special rule for literature applications
2025-10-14 09:39:58 +00:00
if self . type_code == TYPE_LIT and data . get ( ' selfbuy ' ) == ' TRUE ' :
2025-09-01 11:24:59 +00:00
data [ ' selfbuy_give_data ' ] = ' False '
2025-08-31 21:41:11 +00:00
# Save model instance
modell = form . save ( commit = False )
2025-08-18 14:32:31 +00:00
2025-08-31 21:41:11 +00:00
# Username from session if present
2025-09-01 11:33:17 +00:00
if user := self . request . session . get ( ' user ' ) :
2025-09-01 11:24:59 +00:00
modell . username = user . get ( ' username ' )
2025-08-18 14:32:31 +00:00
2025-08-31 21:41:11 +00:00
# Copy common fields if provided by the form
2025-09-01 11:24:59 +00:00
if ' realname ' in data :
modell . realname = data [ ' realname ' ]
if ' email ' in data :
modell . email = data [ ' email ' ]
2025-08-31 21:41:11 +00:00
# Set model.type for specific request types
2025-10-14 09:39:58 +00:00
if self . type_code in LIBRARY_TYPES :
2025-08-31 21:41:11 +00:00
modell . type = self . type_code
# Literature-specific extra field
2025-10-14 09:39:58 +00:00
if self . type_code == TYPE_LIT and ' selfbuy_give_data ' in data :
2025-09-01 11:24:59 +00:00
modell . selfbuy_give_data = data [ ' selfbuy_give_data ' ]
2025-08-31 21:41:11 +00:00
modell . save ( )
2025-09-01 11:24:59 +00:00
if hasattr ( form , ' save_m2m ' ) :
2025-08-31 21:41:11 +00:00
form . save_m2m ( )
# Prepare minimal mail context and send mails
2025-09-01 11:24:59 +00:00
data [ ' pk ' ] = modell . pk
data [ ' url_prefix ' ] = settings . EMAIL_URL_PREFIX
2025-10-14 09:39:58 +00:00
data [ ' type_label ' ] = self . type_info . label
2025-09-01 11:24:59 +00:00
context = { ' data ' : data }
2025-08-31 21:41:11 +00:00
try :
# Mail to applicant
2025-09-01 11:24:59 +00:00
txt1 = get_template ( ' input/ifg_volunteer_mail.txt ' ) . render ( context )
html1 = get_template ( ' input/ifg_volunteer_mail.html ' ) . render ( context )
2025-08-31 21:41:11 +00:00
msg1 = EmailMultiAlternatives (
2025-09-01 11:24:59 +00:00
' Formular ausgefüllt ' , txt1 , settings . IF_EMAIL , [ data [ ' email ' ] ]
2025-08-31 21:41:11 +00:00
)
2025-09-01 11:24:59 +00:00
msg1 . attach_alternative ( html1 , ' text/html ' )
2023-02-27 17:09:29 +00:00
msg1 . send ( )
2025-08-31 21:41:11 +00:00
# Mail to IF
2025-09-01 11:24:59 +00:00
txt2 = get_template ( ' input/if_mail.txt ' ) . render ( context )
html2 = get_template ( ' input/if_mail.html ' ) . render ( context )
2025-08-31 21:41:11 +00:00
msg2 = EmailMultiAlternatives (
2025-09-01 11:24:59 +00:00
' Formular ausgefüllt ' , txt2 , settings . IF_EMAIL , [ settings . IF_EMAIL ]
2025-08-31 21:41:11 +00:00
)
2025-09-01 11:24:59 +00:00
msg2 . attach_alternative ( html2 , ' text/html ' )
2023-02-27 17:09:29 +00:00
msg2 . send ( )
2025-08-18 14:32:31 +00:00
2020-10-08 10:38:49 +00:00
except BadHeaderError :
2020-11-16 15:10:31 +00:00
modell . delete ( )
2025-09-01 11:24:59 +00:00
return HttpResponse ( ' Invalid header found. Data not saved! ' )
2020-11-16 14:53:43 +00:00
except SMTPException :
2020-11-16 15:10:31 +00:00
modell . delete ( )
2025-09-01 11:24:59 +00:00
return HttpResponse ( ' Error in sending mails (probably wrong adress?). Data not saved! ' )
2020-10-07 11:15:00 +00:00
2020-10-01 12:45:04 +00:00
return done ( self . request )