diff --git a/input/forms.py b/input/forms.py index cd9e281..4b32d60 100755 --- a/input/forms.py +++ b/input/forms.py @@ -5,6 +5,7 @@ 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 ProjectRequest, PROJECT_CATEGORIES, WIKIMEDIA_CHOICES from .models import ( TYPE_CHOICES, @@ -306,3 +307,117 @@ class ListForm(BaseApplicationForm, CommonOrderMixin): model = List fields = ['domain', 'address'] exclude = ['intern_notes', 'survey_mail_send','mail_state'] + + +class ProjectRequestForm(CommonOrderMixin, forms.ModelForm): + """ + Public-facing form for < 1000 EUR project requests. + + Key points: + - JSONField-backed multi-selects are exposed as MultipleChoiceField with checkbox widgets. + - We return `list(...)` in clean_* so the JSONField gets a native list. + - Extra UX tweaks: textareas for long text, number inputs with min/max/step, help_texts with links via format_html. + """ + + # Expose JSON-backed categories as a checkbox multi-select + categories = forms.MultipleChoiceField( + choices=[(c, c) for c in PROJECT_CATEGORIES], + widget=forms.CheckboxSelectMultiple, + label='Projektkategorie', + help_text='In welche dieser Kategorien lässt sich dein Projekt einordnen?' + ) + + # Expose JSON-backed wikimedia_projects as a checkbox multi-select + wikimedia_projects = forms.MultipleChoiceField( + choices=[(w, w) for w in WIKIMEDIA_CHOICES], + widget=forms.CheckboxSelectMultiple, + label='Wikimedia Projekt(e)', + help_text='Auf welches Wikimedia-Projekt bezieht sich dein Vorhaben?', + ) + + class Meta: + model = ProjectRequest + fields = [ + 'realname', 'email', + 'name', 'description', + 'categories', 'categories_other', + 'wikimedia_projects', 'wikimedia_other', + 'start', 'end', 'participants_estimated', + 'page', 'group', 'location', + 'cost', 'insurance', 'notes', + ] + + # Widgets are chosen for better UX and to gently guide valid inputs in the browser + widgets = { + 'start': AdminDateWidget(), + 'end': AdminDateWidget(), + + # Long-text fields as textareas with sensible row counts + 'description': forms.Textarea(attrs={'rows': 5}), + 'notes': forms.Textarea(attrs={'rows': 6}), + + # Integer-like fields: browser-side constraints (server still validates in the model) + 'participants_estimated': forms.NumberInput(attrs={'min': 0, 'step': 1}), + 'cost': forms.NumberInput(attrs={'min': 0, 'max': 1000, 'step': 1}), + } + + # Human-readable help_texts; use format_html for safe HTML (links) + help_texts = { + 'name': 'Bitte gib einen Namen für das Projekt an.', + 'description': 'Bitte beschreibe kurz, was die Ziele deines Projekts sind.', + 'participants_estimated': 'Wie viele Personen werden ungefähr an diesem Projekt teilnehmen?', + 'page': 'Bitte gib einen Link zur Projektseite in den Wikimedia-Projekten an, wenn vorhanden.', + 'group': 'Sofern zutreffend: Bitte gib an, welche Personen das Projekt gemeinsam mit dir organisieren.', + 'location': 'Sofern zutreffend: Bitte gib hier den Ort an, an welchem das Projekt stattfinden wird.', + 'cost': 'Wie hoch werden die Projektkosten voraussichtlich sein? Bitte gib diese auf volle Euro gerundet an.', + 'insurance': format_html( + 'Möchtest du die Unfall- und Haftpflichtversicherung von Wikimedia Deutschland in Anspruch nehmen?'), + 'notes': format_html( + 'Falls du noch weitere Informationen hast, teile sie gern an dieser Stelle mit uns. Für umfangreichere Informationen, schreibe uns eine E-Mail an community@wikimedia.de.'), + } + + # Persist multi-selects as Python lists so JSONField stores a JSON array + def clean_categories(self): + return list(self.cleaned_data.get('categories', [])) + + def clean_wikimedia_projects(self): + return list(self.cleaned_data.get('wikimedia_projects', [])) + + +class ProjectRequestAdminForm(forms.ModelForm): + """ + Admin form for ProjectRequest. + + Key points: + - Same checkbox multi-selects for JSON-backed fields to improve admin UX. + - Keep fields="__all__" so admin users can inspect/set workflow fields if needed. + - Do NOT add extra business logic here; validation lives in the model's clean(). + """ + + categories = forms.MultipleChoiceField( + choices=[(c, c) for c in PROJECT_CATEGORIES], + widget=forms.CheckboxSelectMultiple, + label='Projektkategorie' + ) + wikimedia_projects = forms.MultipleChoiceField( + choices=[(w, w) for w in WIKIMEDIA_CHOICES], + widget=forms.CheckboxSelectMultiple, + label='Wikimedia Projekt(e)' + ) + + class Meta: + model = ProjectRequest + fields = "__all__" + + # Make longer texts easier to edit in the admin UI + widgets = { + 'description': forms.Textarea(attrs={'rows': 5}), + 'notes': forms.Textarea(attrs={'rows': 6}), + } + + # Ensure JSONField receives a list + def clean_categories(self): + return list(self.cleaned_data.get('categories', [])) + + def clean_wikimedia_projects(self): + return list(self.cleaned_data.get('wikimedia_projects', []))