From 7390459ad8baa214583c4e039d158ac20abce4cc Mon Sep 17 00:00:00 2001
From: Christian Merten
Date: Fri, 10 Mar 2023 23:33:45 +0100
Subject: [PATCH] waiting list: add basic functionality, i.e. models, forms,
views
---
jdav_web/jdav_web/settings.py | 1 +
jdav_web/mailer/mailutils.py | 5 +
jdav_web/members/admin.py | 81 +++-
.../members/locale/de/LC_MESSAGES/django.po | 357 +++++++++++-------
jdav_web/members/models.py | 224 +++++++----
.../members/invited_registration_failed.html | 17 +
.../members/templates/members/register.html | 1 +
.../templates/members/register_failed.html | 17 +
.../templates/members/register_success.html | 9 +-
.../members/register_waiting_list.html | 52 +++
.../register_waiting_list_success.html | 17 +
jdav_web/members/urls.py | 2 +
jdav_web/members/views.py | 166 ++++++--
13 files changed, 711 insertions(+), 238 deletions(-)
create mode 100644 jdav_web/members/templates/members/invited_registration_failed.html
create mode 100644 jdav_web/members/templates/members/register_failed.html
create mode 100644 jdav_web/members/templates/members/register_waiting_list.html
create mode 100644 jdav_web/members/templates/members/register_waiting_list_success.html
diff --git a/jdav_web/jdav_web/settings.py b/jdav_web/jdav_web/settings.py
index a155edd..5218abc 100644
--- a/jdav_web/jdav_web/settings.py
+++ b/jdav_web/jdav_web/settings.py
@@ -219,6 +219,7 @@ JET_SIDE_MENU_ITEMS = [
{'name': 'klettertreff'},
{'name': 'activitycategory', 'permissions': ['members.view_activitycategory']},
{'name': 'memberunconfirmedproxy', 'permissions': ['members.view_memberunconfirmedproxy']},
+ {'name': 'memberwaitinglist', 'permissions': ['members.view_memberwaitinglist']},
]},
{'app_label': 'material', 'items': [
{'name': 'materialcategory', 'permissions': ['material.view_materialcategory']},
diff --git a/jdav_web/mailer/mailutils.py b/jdav_web/mailer/mailutils.py
index ac4ea64..943c02e 100644
--- a/jdav_web/mailer/mailutils.py
+++ b/jdav_web/mailer/mailutils.py
@@ -72,6 +72,11 @@ def get_echo_link(member):
return prepend_base_url("/members/echo?key={}".format(key))
+def get_registration_link(waiter):
+ key = waiter.generate_registration_key()
+ return prepend_base_url("/members/registration?key={}".format(key))
+
+
def get_mail_confirmation_link(key):
return prepend_base_url("/members/mail/confirm?key={}".format(key))
diff --git a/jdav_web/members/admin.py b/jdav_web/members/admin.py
index 883afc8..7ef0568 100644
--- a/jdav_web/members/admin.py
+++ b/jdav_web/members/admin.py
@@ -22,9 +22,10 @@ from django.forms import Textarea, RadioSelect, TypedChoiceField
from django.shortcuts import render
from .models import (Member, Group, Freizeit, MemberNoteList, NewMemberOnList, Klettertreff,
+ MemberWaitingList,
KlettertreffAttendee, ActivityCategory, OldMemberOnList, MemberList,
annotate_activity_score, RegistrationPassword, MemberUnconfirmedProxy)
-from mailer.mailutils import send as send_mail, get_echo_link, mail_root
+from mailer.mailutils import send as send_mail, get_echo_link, mail_root, get_registration_link
from django.conf import settings
#from easy_select2 import apply_select2
@@ -72,13 +73,11 @@ class RegistrationFilter(admin.SimpleListFilter):
class MemberAdmin(admin.ModelAdmin):
fields = ['prename', 'lastname', 'email', 'email_parents', 'cc_email_parents', 'street', 'plz',
'town', 'phone_number', 'phone_number_parents', 'birth_date', 'group',
- 'gets_newsletter', 'registered', 'registration_form', 'active',
- 'not_waiting', 'echoed', 'comments']
+ 'gets_newsletter', 'registered', 'registration_form', 'active', 'echoed', 'comments']
list_display = ('name', 'birth_date', 'age', 'get_group', 'gets_newsletter',
- 'registered', 'active', 'not_waiting', 'echoed', 'comments', 'activity_score')
+ 'registered', 'active', 'echoed', 'comments', 'activity_score')
search_fields = ('prename', 'lastname', 'email')
- list_filter = ('group', 'gets_newsletter', RegistrationFilter, 'active',
- 'not_waiting')
+ list_filter = ('group', 'gets_newsletter', RegistrationFilter, 'active')
#formfield_overrides = {
# ManyToManyField: {'widget': forms.CheckboxSelectMultiple},
# ForeignKey: {'widget': apply_select2(forms.Select)}
@@ -163,12 +162,11 @@ Deine JDAV Ludwigsburg""".format(name=member.prename, link=get_echo_link(member)
class MemberUnconfirmedAdmin(admin.ModelAdmin):
fields = ['prename', 'lastname', 'email', 'email_parents', 'cc_email_parents', 'street', 'plz',
'town', 'phone_number', 'phone_number_parents', 'birth_date', 'group',
- 'registered', 'registration_form', 'active',
- 'not_waiting', 'comments']
+ 'registered', 'registration_form', 'active', 'comments']
list_display = ('name', 'birth_date', 'age', 'get_group', 'confirmed_mail', 'confirmed_mail_parents')
search_fields = ('prename', 'lastname', 'email')
list_filter = ('group', 'confirmed_mail', 'confirmed_mail_parents')
- actions = ['request_mail_confirmation', 'confirm']
+ actions = ['request_mail_confirmation', 'confirm', 'demote_to_waiter']
change_form_template = "members/change_member_unconfirmed.html"
def has_add_permission(self, request, obj=None):
@@ -209,6 +207,27 @@ class MemberUnconfirmedAdmin(admin.ModelAdmin):
messages.error(request, _("Failed to confirm some registrations because of unconfirmed email addresses."))
confirm.short_description = _('Confirm selected registrations')
+ def demote_to_waiter(self, request, queryset):
+ for member in queryset:
+ #mem_as_dict = member.__dict__
+ #del mem_as_dict['_state']
+ #del mem_as_dict['id']
+ waiter = MemberWaitingList(prename=member.prename,
+ lastname=member.lastname,
+ email=member.email,
+ email_parents=member.email_parents,
+ cc_email_parents=member.cc_email_parents,
+ birth_date=member.birth_date,
+ comments=member.comments,
+ confirmed_mail=member.confirmed_mail,
+ confirmed_mail_parents=member.confirmed_mail_parents,
+ confirm_mail_key=member.confirm_mail_key,
+ confirm_mail_parents_key=member.confirm_mail_parents_key)
+ waiter.save()
+ member.delete()
+ messages.success(request, _("Successfully demoted %(name)s to waiter.") % {'name': waiter.name})
+ demote_to_waiter.short_description = _('Demote selected registrations to waiters.')
+
def response_change(self, request, member):
if "_confirm" in request.POST:
if member.confirm():
@@ -219,6 +238,49 @@ class MemberUnconfirmedAdmin(admin.ModelAdmin):
return super(MemberUnconfirmedAdmin, self).response_change(request, member)
+class MemberWaitingListAdmin(admin.ModelAdmin):
+ fields = ['prename', 'lastname', 'email', 'email_parents', 'birth_date', 'comments', 'invited_for_group']
+ list_display = ('name', 'birth_date', 'age', 'confirmed_mail', 'confirmed_mail_parents')
+ search_fields = ('prename', 'lastname', 'email')
+ list_filter = ('confirmed_mail', 'confirmed_mail_parents')
+ actions = ['request_mail_confirmation', 'ask_for_registration']
+
+ def has_add_permission(self, request, obj=None):
+ return False
+
+ def ask_for_registration(self, request, queryset):
+ """Asks the waiting person to register with all required data."""
+ for waiter in queryset:
+ if not waiter.invited_for_group:
+ messages.error(request,
+ _("Can't invite %(name)s. No group was specified.") % {'name': waiter.name})
+ continue
+ send_mail("Gute Neuigkeiten von der JDAV",
+ """Hallo {name},
+
+wir haben gute Neuigkeiten für dich. Es ist ein Platz in der Jugendgruppe freigeworden. Wir brauchen
+jetzt noch ein paar Informationen von dir und deine Anmeldebestätigung. Das kannst du alles über folgenden
+Link erledigen:
+
+{link}
+
+Du siehst dort auch die Daten, die du bei deiner Eintragung auf die Warteliste angegeben hast. Bitte
+überprüfe, ob die Daten noch stimmen und ändere sie bei Bedarf ab.
+
+Bei Fragen, wende dich gerne an jugendreferent@jdav-ludwigsburg.de.
+
+Viele Grüße
+Deine JDAV Ludwigsburg""".format(name=waiter.prename,
+ link=get_registration_link(waiter)),
+ mail_root,
+ [waiter.email, waiter.email_parents] if waiter.email_parents and waiter.cc_email_parents
+ else waiter.email)
+ messages.success(request,
+ _("Successfully invited %(name)s to %(group)s.") % {'name': waiter.name, 'group': waiter.invited_for_group.name})
+ return None
+ ask_for_registration.short_description = _('Offer waiter a place in a group.')
+
+
class RegistrationPasswordInline(admin.TabularInline):
model = RegistrationPassword
extra = 0
@@ -830,6 +892,7 @@ class KlettertreffAdmin(admin.ModelAdmin):
admin.site.register(Member, MemberAdmin)
admin.site.register(MemberUnconfirmedProxy, MemberUnconfirmedAdmin)
+admin.site.register(MemberWaitingList, MemberWaitingListAdmin)
admin.site.register(Group, GroupAdmin)
admin.site.register(Freizeit, FreizeitAdmin)
admin.site.register(MemberNoteList, MemberNoteListAdmin)
diff --git a/jdav_web/members/locale/de/LC_MESSAGES/django.po b/jdav_web/members/locale/de/LC_MESSAGES/django.po
index 536c394..a90b890 100644
--- a/jdav_web/members/locale/de/LC_MESSAGES/django.po
+++ b/jdav_web/members/locale/de/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2022-10-06 11:38+0200\n"
+"POT-Creation-Date: 2023-03-10 23:28+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -18,333 +18,368 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: members/admin.py:33 members/models.py:89
+#: members/admin.py:34 members/models.py:161
msgid "Registration complete"
msgstr "Anmeldung vollständig"
-#: members/admin.py:39
+#: members/admin.py:40
msgid "True"
msgstr "Ja"
-#: members/admin.py:40
+#: members/admin.py:41
msgid "False"
msgstr "Nein"
-#: members/admin.py:41
+#: members/admin.py:42
msgid "All"
msgstr "Alle"
-#: members/admin.py:117
+#: members/admin.py:116
msgid "Compose new mail to selected members"
msgstr "Neue Nachricht an ausgewählte Teilnehmer verfassen"
-#: members/admin.py:142
+#: members/admin.py:141
msgid "Successfully requested echo from selected members."
msgstr ""
"Rückmeldungsaufforderung erfolgreich an ausgewählte Teilnehmer verschickt."
-#: members/admin.py:143
+#: members/admin.py:142
msgid "Request echo from selected members"
msgstr "Rückmeldungsaufforderung an ausgewählte Teilnehmer verschicken"
-#: members/admin.py:160
+#: members/admin.py:159
msgid "activity"
msgstr "Aktivität"
-#: members/admin.py:190
+#: members/admin.py:188
msgid "Successfully requested mail confirmation from selected registrations."
msgstr "Aufforderung zur Bestätigung der Email Adresse versendet."
-#: members/admin.py:191
+#: members/admin.py:189
msgid "Request mail confirmation from selected registrations"
msgstr "Aufforderung zur Bestätigung der Email Adresse versenden"
-#: members/admin.py:198 members/admin.py:215
+#: members/admin.py:196 members/admin.py:234
#, python-format
msgid "Successfully confirmed %(name)s."
msgstr "Registrierung von %(name)s erfolgreich bestätigt."
-#: members/admin.py:202 members/admin.py:218
+#: members/admin.py:200 members/admin.py:237
#, python-format
msgid "Can't confirm. %(name)s has unconfirmed email addresses."
msgstr "Bestätigung nicht möglich. %(name)s hat unbestätigte Emailadressen."
-#: members/admin.py:207
+#: members/admin.py:205
msgid "Successfully confirmed multiple registrations."
msgstr "Erfolgreich mehrere Registrierungen bestätigt."
-#: members/admin.py:209
+#: members/admin.py:207
msgid ""
"Failed to confirm some registrations because of unconfirmed email addresses."
msgstr ""
"Einige Bestätigungen fehlgeschlagen, weil Emailadressen noch nicht bestätigt "
"sind."
-#: members/admin.py:210
+#: members/admin.py:208
msgid "Confirm selected registrations"
msgstr "Ausgewählte Registrierungen bestätigen"
-#: members/admin.py:252
+#: members/admin.py:228
+#, python-format
+msgid "Successfully demoted %(name)s to waiter."
+msgstr "%(name)s zurück auf die Warteliste gesetzt."
+
+#: members/admin.py:229
+msgid "Demote selected registrations to waiters."
+msgstr "Ausgewählte Registrierungen zurück auf die Warteliste setzen."
+
+#: members/admin.py:256
+#, python-format
+msgid "Can't invite %(name)s. No group was specified."
+msgstr "Einladen von %(name)s nicht möglich. Es wurde keine Gruppe angegeben."
+
+#: members/admin.py:279
+#, python-format
+msgid "Successfully invited %(name)s to %(group)s."
+msgstr "Erfolgreich %(name)s zu Gruppe %(group)s eingeladen."
+
+#: members/admin.py:281
+msgid "Offer waiter a place in a group."
+msgstr "Personen auf der Warteliste einen Gruppenplatz anbieten."
+
+#: members/admin.py:314
msgid "Difficulty"
msgstr "Schwierigkeit"
-#: members/admin.py:255 members/admin.py:258
+#: members/admin.py:317 members/admin.py:320
msgid "Tour type"
msgstr "Art der Tour"
-#: members/admin.py:556
+#: members/admin.py:618
msgid "Convert to PDF"
msgstr "Kriseninterventionsliste erstellen"
-#: members/admin.py:665
+#: members/admin.py:727
msgid "Generate overview"
msgstr "Hinweise für Jugendleiter erstellen"
-#: members/admin.py:762
+#: members/admin.py:824
msgid "Generate list for LJP"
msgstr "LJP Liste erstellen"
-#: members/apps.py:7 members/models.py:256
+#: members/apps.py:7 members/models.py:260
msgid "members"
msgstr "Teilnehmer"
-#: members/models.py:28
+#: members/models.py:33
msgid "Name"
msgstr "Name"
-#: members/models.py:29
+#: members/models.py:34
msgid "Description"
msgstr "Beschreibung"
-#: members/models.py:35 members/models.py:301 members/models.py:380
+#: members/models.py:40 members/models.py:365 members/models.py:444
#: members/templates/members/change_member.html:17
msgid "Activity"
msgstr "Aktivität"
-#: members/models.py:36
+#: members/models.py:41
msgid "Activities"
msgstr "Aktivitäten"
-#: members/models.py:44
+#: members/models.py:49
msgid "name"
msgstr "Name"
-#: members/models.py:45
+#: members/models.py:50
msgid "lowest year"
msgstr "Ab Jahrgang"
-#: members/models.py:46
+#: members/models.py:51
msgid "highest year"
msgstr "Bis Jahrgang"
-#: members/models.py:47
+#: members/models.py:52
msgid "youth leaders"
msgstr "Jugendleiter"
-#: members/models.py:55 members/models.py:82
+#: members/models.py:61 members/models.py:154
msgid "group"
msgstr "Gruppe"
-#: members/models.py:56
+#: members/models.py:62
msgid "groups"
msgstr "Gruppen"
-#: members/models.py:69
+#: members/models.py:74
msgid "prename"
msgstr "Vorname"
-#: members/models.py:70
+#: members/models.py:75
msgid "last name"
msgstr "Nachname"
-#: members/models.py:71
+#: members/models.py:78
+msgid "Parents' Email"
+msgstr "Email der Eltern"
+
+#: members/models.py:79
+msgid "Also send mails to parents"
+msgstr "Emails auch an Eltern schicken"
+
+#: members/models.py:81
+msgid "birth date"
+msgstr "Geburtsdatum"
+
+#: members/models.py:83
+msgid "comments"
+msgstr "Kommentare"
+
+#: members/models.py:85
+msgid "Email confirmed"
+msgstr "Emailadresse bestätigt"
+
+#: members/models.py:86
+msgid "Parents email confirmed"
+msgstr "Emailadresse der Eltern bestätigt"
+
+#: members/models.py:110 members/models.py:119
+msgid "Email confirmation needed"
+msgstr "Email Bestätigung erforderlich"
+
+#: members/models.py:147
msgid "street and house number"
msgstr "Straße und Hausnummer"
-#: members/models.py:72
+#: members/models.py:148
msgid "Postcode"
msgstr "PLZ"
-#: members/models.py:74
+#: members/models.py:150
msgid "town"
msgstr "Stadt"
-#: members/models.py:75
+#: members/models.py:152
msgid "phone number"
msgstr "Telefonnummer"
-#: members/models.py:76
+#: members/models.py:153
msgid "parents phone number"
msgstr "Telefonnummer der Eltern"
-#: members/models.py:79
-msgid "Parents' Email"
-msgstr "Email der Eltern"
-
-#: members/models.py:80
-msgid "Also send mails to parents"
-msgstr "Emails auch an Eltern schicken"
-
-#: members/models.py:81
-msgid "birth date"
-msgstr "Geburtsdatum"
-
-#: members/models.py:83
+#: members/models.py:156
msgid "receives newsletter"
msgstr "Erhält den Newsletter"
-#: members/models.py:87
-msgid "comments"
-msgstr "Kommentare"
-
-#: members/models.py:88
+#: members/models.py:160
msgid "created"
msgstr "erstellt"
-#: members/models.py:90
+#: members/models.py:162
msgid "Active"
msgstr "Aktiv"
-#: members/models.py:91
-msgid "Not waiting"
-msgstr "NICHT Warteliste"
-
-#: members/models.py:92
+#: members/models.py:164
msgid "registration form"
msgstr "Anmeldeformular"
-#: members/models.py:102
+#: members/models.py:174
msgid "Echoed"
msgstr "Rückgemeldet"
-#: members/models.py:103
+#: members/models.py:175
msgid "Confirmed"
msgstr "Bestätigt"
-#: members/models.py:104
-msgid "Email confirmed"
-msgstr "Emailadresse bestätigt"
-
-#: members/models.py:105
-msgid "Parents email confirmed"
-msgstr "Emailadresse der Eltern bestätigt"
-
-#: members/models.py:138 members/models.py:148
-msgid "Email confirmation needed"
-msgstr "Email Bestätigung erforderlich"
-
-#: members/models.py:176
-#, python-format
-msgid "New unconfirmed registration for group %(group)s"
-msgstr "Neue unbestätigte Registrierung für Gruppe %(group)s"
-
-#: members/models.py:252 members/models.py:462
+#: members/models.py:256 members/models.py:526
msgid "Group"
msgstr "Gruppe"
-#: members/models.py:255
+#: members/models.py:259
msgid "member"
msgstr "Teilnehmer"
-#: members/models.py:286
+#: members/models.py:291
+#, python-format
+msgid "New unconfirmed registration for group %(group)s"
+msgstr "Neue unbestätigte Registrierung für Gruppe %(group)s"
+
+#: members/models.py:309
msgid "Unconfirmed registration"
msgstr "Unbestätigte Registrierung"
-#: members/models.py:287
+#: members/models.py:310
msgid "Unconfirmed registrations"
msgstr "Unbestätigte Registrierungen"
-#: members/models.py:303 members/models.py:382
+#: members/models.py:321
+msgid "Last wait confirmation"
+msgstr "Letzte Wartebestätigung"
+
+#: members/models.py:331
+msgid "Invited for group"
+msgstr "Einladung zu Gruppe austehend"
+
+#: members/models.py:335
+msgid "Waiter"
+msgstr "Wartende Person"
+
+#: members/models.py:336
+msgid "Waiters"
+msgstr "Warteliste"
+
+#: members/models.py:367 members/models.py:446
msgid "Place"
msgstr "Ort"
-#: members/models.py:304 members/models.py:383
+#: members/models.py:368 members/models.py:447
msgid "Destination (optional)"
msgstr "Ziel (optional)"
-#: members/models.py:306 members/models.py:385 members/models.py:440
-#: members/models.py:458
+#: members/models.py:370 members/models.py:449 members/models.py:504
+#: members/models.py:522
msgid "Date"
msgstr "Datum"
-#: members/models.py:307 members/models.py:386
+#: members/models.py:371 members/models.py:450
msgid "End (optional)"
msgstr "Ende"
-#: members/models.py:309 members/models.py:388
+#: members/models.py:373 members/models.py:452
msgid "Groups"
msgstr "Gruppen"
-#: members/models.py:317 members/models.py:401
+#: members/models.py:381 members/models.py:465
msgid "Categories"
msgstr "Kategorien"
-#: members/models.py:318 members/models.py:402
+#: members/models.py:382 members/models.py:466
msgid "easy"
msgstr "leicht"
-#: members/models.py:318 members/models.py:402
+#: members/models.py:382 members/models.py:466
msgid "medium"
msgstr "mittel"
-#: members/models.py:318 members/models.py:402
+#: members/models.py:382 members/models.py:466
msgid "hard"
msgstr "schwer"
-#: members/models.py:327
+#: members/models.py:391
msgid "Memberlist"
msgstr "Teilnehmerliste"
-#: members/models.py:328
+#: members/models.py:392
msgid "Memberlists"
msgstr "Teilnehmerlisten"
-#: members/models.py:346 members/models.py:354 members/models.py:362
-#: members/models.py:373 members/models.py:493 members/models.py:500
+#: members/models.py:410 members/models.py:418 members/models.py:426
+#: members/models.py:437 members/models.py:557 members/models.py:564
msgid "Member"
msgstr "Teilnehmer"
-#: members/models.py:348 members/models.py:367
+#: members/models.py:412 members/models.py:431
msgid "Comment"
msgstr "Kommentar"
-#: members/models.py:355 members/models.py:374 members/models.py:501
+#: members/models.py:419 members/models.py:438 members/models.py:565
msgid "Members"
msgstr "Teilnehmer"
-#: members/models.py:439
+#: members/models.py:503
msgid "Title"
msgstr "Titel"
-#: members/models.py:459
+#: members/models.py:523
msgid "Location"
msgstr "Ort"
-#: members/models.py:460
+#: members/models.py:524
msgid "Topic"
msgstr "Thema"
-#: members/models.py:484
+#: members/models.py:548
msgid "Jugendleiter"
msgstr "Jugendleiter"
-#: members/models.py:487
+#: members/models.py:551
msgid "Klettertreff"
msgstr "Klettertreff"
-#: members/models.py:488
+#: members/models.py:552
msgid "Klettertreffs"
msgstr "Klettertreffs"
-#: members/models.py:506
+#: members/models.py:570
msgid "Password"
msgstr "Passwort"
-#: members/models.py:509
+#: members/models.py:573
msgid "registration password"
msgstr "Registrierungspassort"
-#: members/models.py:510
+#: members/models.py:574
msgid "registration passwords"
msgstr "Registrierungspasswörter"
@@ -381,8 +416,9 @@ msgstr ""
"Falls sich etwas geändert hat, trage das bitte hier ein."
#: members/templates/members/echo.html:27
-#: members/templates/members/register.html:33
+#: members/templates/members/register.html:34
#: members/templates/members/register_password.html:22
+#: members/templates/members/register_waiting_list.html:31
msgid "submit"
msgstr "Bestätigen"
@@ -391,14 +427,19 @@ msgid "Echo failed"
msgstr "Rückmeldung fehlgeschlagen"
#: members/templates/members/echo_failed.html:13
+#: members/templates/members/invited_registration_failed.html:13
msgid "Something went wrong. The key you supplied is"
msgstr "Etwas ist schief gegangen. Der verwendete Code ist"
#: members/templates/members/echo_failed.html:15
+#: members/templates/members/invited_registration_failed.html:15
+#: members/templates/members/register_failed.html:15
msgid "If you think this is a mistake, please"
msgstr "Wenn du denkst, dass das ein Fehler ist, "
#: members/templates/members/echo_failed.html:15
+#: members/templates/members/invited_registration_failed.html:15
+#: members/templates/members/register_failed.html:15
msgid "contact us."
msgstr "kontaktiere uns."
@@ -414,6 +455,20 @@ msgstr "Danke"
msgid "Your data was successfully updated."
msgstr "Deine Daten wurden erfolgreich aktualisiert."
+#: members/templates/members/invited_registration_failed.html:6
+#: members/templates/members/register_failed.html:6
+msgid "Registration failed"
+msgstr "Registrierung fehlgeschlagen"
+
+#: members/templates/members/invited_registration_failed.html:11
+#: members/templates/members/register.html:6
+#: members/templates/members/register_failed.html:11
+#: members/templates/members/register_password.html:6
+#: members/templates/members/register_success.html:6
+#: members/templates/members/register_wrong_password.html:6
+msgid "Registration"
+msgstr "Registrierung"
+
#: members/templates/members/mail_confirmation_invalid.html:6
#: members/templates/members/mail_confirmation_invalid.html:11
msgid "Mail confirmation failed"
@@ -446,13 +501,6 @@ msgstr ""
"Die Emailadresse %(email)s wurde erfolgreich als persönliche Emailadresse "
"von %(name)s bestätigt."
-#: members/templates/members/register.html:6
-#: members/templates/members/register_password.html:6
-#: members/templates/members/register_success.html:6
-#: members/templates/members/register_wrong_password.html:6
-msgid "Registration"
-msgstr "Registrierung"
-
#: members/templates/members/register.html:13
#: members/templates/members/register_password.html:11
#: members/templates/members/register_success.html:11
@@ -469,6 +517,7 @@ msgid "I am member of the DAV Ludwigsburg."
msgstr "Ich bin Mitglied des DAV Ludwigsburg."
#: members/templates/members/register.html:30
+#: members/templates/members/register_waiting_list.html:28
msgid ""
"I agree that my data is stored and processed on the server of the JDAV "
"Ludwigsburg."
@@ -476,6 +525,10 @@ msgstr ""
"Ich bin einverstanden, dass meine Daten auf dem Server der JDAV Ludwigsburg "
"gespeichert und verarbeitet werden."
+#: members/templates/members/register_failed.html:13
+msgid "Something went wrong while processing your registration."
+msgstr "Etwas ist schief gelaufen, bei der Verarbeitung deiner Registrierung."
+
#: members/templates/members/register_password.html:13
msgid ""
"Thanks for your interest in participating. Please enter the registration "
@@ -485,14 +538,58 @@ msgstr ""
"das Passwort ein, das du von deinem Jugendleiter erhalten hast."
#: members/templates/members/register_success.html:13
+msgid "Your registration succeeded."
+msgstr "Deine Registrierung war erfolgreich."
+
+#: members/templates/members/register_success.html:16
+msgid "Please remember to confirm your email address."
+msgstr "Bitte denk daran, deine E-Mail Adresse(n) zu bestätigen."
+
+#: members/templates/members/register_success.html:17
msgid ""
-"Your registration succeeded. Please remember to confirm your email address. "
"The coordinating team will process your registration when your email address "
"is confirmed."
msgstr ""
-"Deine Registrierung war erfolgreich. Eine Bestätigungsmail wurde an die von "
-"dir angegebenen Emailadressen verschickt. Unser Jugendleiterteam wird deine "
-"Registrierung bearbeiten, wenn deine Emailadressen bestätigt sind."
+"Unser Jugendleiterteam wird deine Registrierung bearbeiten, wenn deine "
+"Emailadressen bestätigt sind."
+
+#: members/templates/members/register_success.html:19
+msgid ""
+"The coordinating team will process your registration as soon as possible."
+msgstr ""
+"Unser Jugendleiterteam wird deine Registrierung so schnell wie möglich "
+"bearbeiten."
+
+#: members/templates/members/register_waiting_list.html:6
+msgid "Registration for waiting list"
+msgstr "Registrierung für die Warteliste"
+
+#: members/templates/members/register_waiting_list.html:13
+msgid "Register for waiting list"
+msgstr "Für die Warteliste registrieren"
+
+#: members/templates/members/register_waiting_list.html:15
+msgid "Here you can register for the waiting list."
+msgstr "Hier kannst du dich auf die Warteliste eintragen."
+
+#: members/templates/members/register_waiting_list_success.html:6
+#: members/templates/members/register_waiting_list_success.html:11
+msgid "Registration for waiting list."
+msgstr "Registrierung für die Warteliste."
+
+#: members/templates/members/register_waiting_list_success.html:13
+msgid "Your registration for the waiting list was successful."
+msgstr "Du wurdest auf die Warteliste gesetzt."
+
+#: members/templates/members/register_waiting_list_success.html:14
+msgid "Please remember to confirm all email addresses that you entered."
+msgstr "Bitte denk daran, deine E-Mail Adresse(n) zu bestätigen."
+
+#: members/templates/members/register_waiting_list_success.html:15
+msgid "We will notify you if there is a vacant place in one of our groups."
+msgstr ""
+"Wir werden dich umgehend benachrichtigen, wenn es einen freien Platz in "
+"einer unserer Gruppen gibt."
#: members/templates/members/register_wrong_password.html:13
msgid ""
@@ -501,18 +598,26 @@ msgstr ""
"Du hast zu oft ein falsches Passwort eingegeben. Bitte frage deinen "
"Jugendleiter nach einem korrekten Passwort."
-#: members/views.py:62 members/views.py:83
+#: members/views.py:83 members/views.py:104 members/views.py:268
msgid "invalid"
msgstr "ungültig"
-#: members/views.py:64
+#: members/views.py:85 members/views.py:270
msgid "expired"
msgstr "abgelaufen"
-#: members/views.py:93
+#: members/views.py:114
msgid "The entered password is wrong."
msgstr "Das eingegebene Passwort ist falsch."
+#~ msgid "Successfully asked for registration from selected waiting persons."
+#~ msgstr ""
+#~ "Erfolgreich Einladung zur Registrierung an die ausgewählten Wartenden "
+#~ "verschickt."
+
+#~ msgid "Not waiting"
+#~ msgstr "NICHT Warteliste"
+
#~ msgid "street"
#~ msgstr "Straße"
diff --git a/jdav_web/members/models.py b/jdav_web/members/models.py
index 5aca41b..d39235c 100644
--- a/jdav_web/members/models.py
+++ b/jdav_web/members/models.py
@@ -16,6 +16,11 @@ from django.contrib.auth.models import User
from dateutil.relativedelta import relativedelta
+
+def generate_random_key():
+ return uuid.uuid4().hex
+
+
GEMEINSCHAFTS_TOUR = MUSKELKRAFT_ANREISE = 0
FUEHRUNGS_TOUR = OEFFENTLICHE_ANREISE = 1
AUSBILDUNGS_TOUR = FAHRGEMEINSCHAFT_ANREISE = 2
@@ -46,6 +51,7 @@ class Group(models.Model):
year_to = models.IntegerField(verbose_name=_('highest year'), default=2011)
leiters = models.ManyToManyField('members.Member', verbose_name=_('youth leaders'),
related_name='leited_groups', blank=True)
+ secret = models.CharField(max_length=32, default=generate_random_key)
def __str__(self):
"""String representation"""
@@ -61,83 +67,48 @@ class MemberManager(models.Manager):
return super().get_queryset().filter(confirmed=True)
-class Member(models.Model):
+class Person(models.Model):
"""
- Represents a member of the association
- Might be a member of different groups: e.g. J1, J2, Jugendleiter, etc.
+ Represents an abstract person. Not necessarily a member of any group.
"""
prename = models.CharField(max_length=20, verbose_name=_('prename'))
lastname = models.CharField(max_length=20, verbose_name=_('last name'))
- street = models.CharField(max_length=30, verbose_name=_('street and house number'), default='', blank=True)
- plz = models.CharField(max_length=10, verbose_name=_('Postcode'),
- default='', blank=True)
- town = models.CharField(max_length=30, verbose_name=_('town'), default='', blank=True)
- phone_number = models.CharField(max_length=18, verbose_name=_('phone number'), default='', blank=True)
- phone_number_parents = models.CharField(max_length=18, verbose_name=_('parents phone number'), default='', blank=True)
email = models.EmailField(max_length=100, default="")
email_parents = models.EmailField(max_length=100, default="", blank=True,
verbose_name=_("Parents' Email"))
cc_email_parents = models.BooleanField(default=True, verbose_name=_('Also send mails to parents'))
+
birth_date = models.DateField(_('birth date')) # to determine the age
- group = models.ManyToManyField(Group, verbose_name=_('group'))
- gets_newsletter = models.BooleanField(_('receives newsletter'),
- default=True)
- unsubscribe_key = models.CharField(max_length=32, default="")
- unsubscribe_expire = models.DateTimeField(default=timezone.now)
+
comments = models.TextField(_('comments'), default='', blank=True)
- created = models.DateField(auto_now=True, verbose_name=_('created'))
- registered = models.BooleanField(default=False, verbose_name=_('Registration complete'))
- active = models.BooleanField(default=True, verbose_name=_('Active'))
- not_waiting = models.BooleanField(default=True, verbose_name=_('Not waiting'))
- registration_form = RestrictedFileField(verbose_name=_('registration form'),
- upload_to='registration_forms',
- blank=True,
- max_upload_size=5242880,
- content_types=['application/pdf',
- 'image/jpeg',
- 'image/png',
- 'image/gif'])
- echo_key = models.CharField(max_length=32, default="")
- echo_expire = models.DateTimeField(default=timezone.now)
- echoed = models.BooleanField(default=True, verbose_name=_('Echoed'))
- confirmed = models.BooleanField(default=True, verbose_name=_('Confirmed'))
+
confirmed_mail = models.BooleanField(default=True, verbose_name=_('Email confirmed'))
confirmed_mail_parents = models.BooleanField(default=True, verbose_name=_('Parents email confirmed'))
confirm_mail_key = models.CharField(max_length=32, default="")
confirm_mail_parents_key = models.CharField(max_length=32, default="")
- user = models.OneToOneField(User, blank=True, null=True, on_delete=models.SET_NULL)
- objects = MemberManager()
+ class Meta:
+ abstract = True
def __str__(self):
"""String representation"""
return self.name
+ @property
+ def name(self):
+ """Returning whole name (prename + lastname)"""
+ return "{0} {1}".format(self.prename, self.lastname)
+
@property
def age(self):
"""Age of member"""
return relativedelta(datetime.today(), self.birth_date).years
- def generate_key(self):
- self.unsubscribe_key = uuid.uuid4().hex
- self.unsubscribe_expire = timezone.now() + timezone.timedelta(days=1)
- self.save()
- return self.unsubscribe_key
-
- def generate_echo_key(self):
- self.echo_key = uuid.uuid4().hex
- self.echo_expire = timezone.now() + timezone.timedelta(days=30)
- self.echoed = False
- self.save()
- return self.echo_key
-
def request_mail_confirmation(self):
self.confirmed_mail = False
self.confirm_mail_key = uuid.uuid4().hex
- group = ", ".join([g.name for g in self.group.all()])
send_mail(_('Email confirmation needed'),
CONFIRM_MAIL_TEXT.format(name=self.prename,
- group=group,
link=get_mail_confirmation_link(self.confirm_mail_key),
whattoconfirm='deiner Emailadresse'),
mail_root,
@@ -147,7 +118,6 @@ class Member(models.Model):
self.confirm_mail_parents_key = uuid.uuid4().hex
send_mail(_('Email confirmation needed'),
CONFIRM_MAIL_TEXT.format(name=self.prename,
- group=group,
link=get_mail_confirmation_link(self.confirm_mail_parents_key),
whattoconfirm='der Emailadresse deiner Eltern'),
mail_root,
@@ -166,21 +136,73 @@ class Member(models.Model):
self.confirm_mail_parents_key, self.confirmed_mail_parents = "", True
email, parents = self.email_parents, True
self.save()
- if self.confirmed_mail_parents and self.confirmed_mail and not self.confirmed:
- group = ", ".join([g.name for g in self.group.all()])
- # notify jugendleiters of group of registration
- jls = [jl for group in self.group.all() for jl in group.leiters.all()]
- for jl in jls:
- link = prepend_base_url(reverse('admin:members_memberunconfirmedproxy_change',
- args=[str(self.id)]))
- send_mail(_('New unconfirmed registration for group %(group)s') % {'group': group},
- NEW_UNCONFIRMED_REGISTRATION.format(name=jl.prename,
- group=group,
- link=link),
- mail_root,
- jl.email)
return (email, parents)
+
+class Member(Person):
+ """
+ Represents a member of the association
+ Might be a member of different groups: e.g. J1, J2, Jugendleiter, etc.
+ """
+ street = models.CharField(max_length=30, verbose_name=_('street and house number'), default='', blank=True)
+ plz = models.CharField(max_length=10, verbose_name=_('Postcode'),
+ default='', blank=True)
+ town = models.CharField(max_length=30, verbose_name=_('town'), default='', blank=True)
+
+ phone_number = models.CharField(max_length=18, verbose_name=_('phone number'), default='', blank=True)
+ phone_number_parents = models.CharField(max_length=18, verbose_name=_('parents phone number'), default='', blank=True)
+ group = models.ManyToManyField(Group, verbose_name=_('group'))
+
+ gets_newsletter = models.BooleanField(_('receives newsletter'),
+ default=True)
+ unsubscribe_key = models.CharField(max_length=32, default="")
+ unsubscribe_expire = models.DateTimeField(default=timezone.now)
+ created = models.DateField(auto_now=True, verbose_name=_('created'))
+ registered = models.BooleanField(default=False, verbose_name=_('Registration complete'))
+ active = models.BooleanField(default=True, verbose_name=_('Active'))
+ #not_waiting = models.BooleanField(default=True, verbose_name=_('Not waiting'))
+ registration_form = RestrictedFileField(verbose_name=_('registration form'),
+ upload_to='registration_forms',
+ blank=True,
+ max_upload_size=5242880,
+ content_types=['application/pdf',
+ 'image/jpeg',
+ 'image/png',
+ 'image/gif'])
+ echo_key = models.CharField(max_length=32, default="")
+ echo_expire = models.DateTimeField(default=timezone.now)
+ echoed = models.BooleanField(default=True, verbose_name=_('Echoed'))
+ confirmed = models.BooleanField(default=True, verbose_name=_('Confirmed'))
+ user = models.OneToOneField(User, blank=True, null=True, on_delete=models.SET_NULL)
+
+ objects = MemberManager()
+
+ @property
+ def place(self):
+ """Returning the whole place (plz + town)"""
+ return "{0} {1}".format(self.plz, self.town)
+
+ @property
+ def address(self):
+ """Returning the whole address"""
+ if not self.street and not self.town and not self.plz:
+ return "---"
+ else:
+ return "{0}, {1}".format(self.street, self.place)
+
+ def generate_key(self):
+ self.unsubscribe_key = uuid.uuid4().hex
+ self.unsubscribe_expire = timezone.now() + timezone.timedelta(days=1)
+ self.save()
+ return self.unsubscribe_key
+
+ def generate_echo_key(self):
+ self.echo_key = uuid.uuid4().hex
+ self.echo_expire = timezone.now() + timezone.timedelta(days=30)
+ self.echoed = False
+ self.save()
+ return self.echo_key
+
def confirm(self):
if not self.confirmed_mail or not self.confirmed_mail_parents:
return False
@@ -202,24 +224,6 @@ class Member(models.Model):
def may_echo(self, key):
return self.echo_key == key and timezone.now() < self.echo_expire
- @property
- def name(self):
- """Returning whole name (prename + lastname)"""
- return "{0} {1}".format(self.prename, self.lastname)
-
- @property
- def place(self):
- """Returning the whole place (plz + town)"""
- return "{0} {1}".format(self.plz, self.town)
-
- @property
- def address(self):
- """Returning the whole address"""
- if not self.street and not self.town and not self.plz:
- return "---"
- else:
- return "{0}, {1}".format(self.street, self.place)
-
@property
def contact_phone_number(self):
"""Returning, if available phone number of parents, else member's phone number"""
@@ -271,6 +275,25 @@ class Member(models.Model):
# get activity overview
return Freizeit.objects.filter(membersonlist__member=self)
+ def confirm_mail(self, key):
+ ret = super().confirm_mail(key)
+ if self.confirmed_mail_parents and self.confirmed_mail and not self.confirmed:
+ self.notify_jugendleiters_about_confirmed_mail()
+ return ret
+
+ def notify_jugendleiters_about_confirmed_mail(self):
+ group = ", ".join([g.name for g in self.group.all()])
+ # notify jugendleiters of group of registration
+ jls = [jl for group in self.group.all() for jl in group.leiters.all()]
+ for jl in jls:
+ link = prepend_base_url(reverse('admin:members_memberunconfirmedproxy_change',
+ args=[str(self.id)]))
+ send_mail(_('New unconfirmed registration for group %(group)s') % {'group': group},
+ NEW_UNCONFIRMED_REGISTRATION.format(name=jl.prename,
+ group=group,
+ link=link),
+ mail_root,
+ jl.email)
class MemberUnconfirmedManager(models.Manager):
def get_queryset(self):
@@ -292,6 +315,47 @@ class MemberUnconfirmedProxy(Member):
return self.name
+class MemberWaitingList(Person):
+ """A participant on the waiting list"""
+
+ last_wait_confirmation = models.DateField(auto_now=True, verbose_name=_('Last wait confirmation'))
+ wait_confirmation_key = models.CharField(max_length=32, default="")
+ wait_confirmation_key_expiry = models.DateTimeField(default=timezone.now)
+
+ registration_key = models.CharField(max_length=32, default="")
+ registration_expire = models.DateTimeField(default=timezone.now)
+
+ invited_for_group = models.ForeignKey(Group,
+ null=True,
+ default=None,
+ verbose_name=_('Invited for group'),
+ on_delete=models.SET_NULL)
+
+ class Meta:
+ verbose_name = _('Waiter')
+ verbose_name_plural = _('Waiters')
+ permissions = (('may_manage_waiting_list', 'Can view and manage the waiting list.'),)
+
+ @property
+ def waiting_confirmation_needed(self):
+ """Returns if person should be asked to confirm waiting status."""
+ return wait_confirmation_key is None \
+ and last_wait_confirmation < timezone.now - timezone.timedelta(days=90)
+
+ @property
+ def waiting_confirmed(self):
+ """Returns if person is still confirmed to be waiting."""
+ return last_wait_confirmation < timezone.now() - timezone.timedelta(days=100)
+
+ def generate_registration_key(self):
+ self.registration_key = uuid.uuid4().hex
+ self.registration_expire = timezone.now() + timezone.timedelta(days=30)
+ self.save()
+ return self.registration_key
+
+ def may_register(self, key):
+ return self.registration_key == key and timezone.now() < self.registration_expire
+
class MemberList(models.Model):
"""Lets the user create a list of members in pdf format.
@@ -601,7 +665,7 @@ def annotate_activity_score(queryset):
CONFIRM_MAIL_TEXT = """Hallo {name},
-du hast dich bei der JDAV Ludwigsburg für die Gruppe {group} registriert. Da bei uns alle Kommunikation
+du hast bei der JDAV Ludwigsburg eine E-Mail Adresse hinterlegt. Da bei uns alle Kommunikation
per Email funktioniert, brauchen wir eine Bestätigung {whattoconfirm}. Dazu klicke bitte einfach auf
folgenden Link:
diff --git a/jdav_web/members/templates/members/invited_registration_failed.html b/jdav_web/members/templates/members/invited_registration_failed.html
new file mode 100644
index 0000000..619f534
--- /dev/null
+++ b/jdav_web/members/templates/members/invited_registration_failed.html
@@ -0,0 +1,17 @@
+{% extends "members/base.html" %}
+{% load i18n %}
+{% load static %}
+
+{% block title %}
+{% trans "Registration failed" %}
+{% endblock %}
+
+{% block content %}
+
+{% trans "Registration" %}
+
+{% trans "Something went wrong. The key you supplied is" %} {{ reason }}.
+
+{% trans "If you think this is a mistake, please" %} {% trans "contact us." %}
+
+{% endblock %}
diff --git a/jdav_web/members/templates/members/register.html b/jdav_web/members/templates/members/register.html
index 763fa6e..4d724ca 100644
--- a/jdav_web/members/templates/members/register.html
+++ b/jdav_web/members/templates/members/register.html
@@ -29,6 +29,7 @@
{% trans "I agree that my data is stored and processed on the server of the JDAV Ludwigsburg." %}
+
diff --git a/jdav_web/members/templates/members/register_failed.html b/jdav_web/members/templates/members/register_failed.html
new file mode 100644
index 0000000..49af016
--- /dev/null
+++ b/jdav_web/members/templates/members/register_failed.html
@@ -0,0 +1,17 @@
+{% extends "members/base.html" %}
+{% load i18n %}
+{% load static %}
+
+{% block title %}
+{% trans "Registration failed" %}
+{% endblock %}
+
+{% block content %}
+
+{% trans "Registration" %}
+
+{% trans "Something went wrong while processing your registration." %}
+
+{% trans "If you think this is a mistake, please" %} {% trans "contact us." %}
+
+{% endblock %}
diff --git a/jdav_web/members/templates/members/register_success.html b/jdav_web/members/templates/members/register_success.html
index 3e35c47..dcadbf4 100644
--- a/jdav_web/members/templates/members/register_success.html
+++ b/jdav_web/members/templates/members/register_success.html
@@ -10,6 +10,13 @@
{% trans "Register" %}
-{% trans "Your registration succeeded. Please remember to confirm your email address. The coordinating team will process your registration when your email address is confirmed." %}
+{% trans "Your registration succeeded." %}
+
+{% if needs_mail_confirmation %}
+ {% trans "Please remember to confirm your email address." %}
+ {% trans "The coordinating team will process your registration when your email address is confirmed." %}
+{% else %}
+ {% trans "The coordinating team will process your registration as soon as possible." %}
+{% endif %}
{% endblock %}
diff --git a/jdav_web/members/templates/members/register_waiting_list.html b/jdav_web/members/templates/members/register_waiting_list.html
new file mode 100644
index 0000000..223c16e
--- /dev/null
+++ b/jdav_web/members/templates/members/register_waiting_list.html
@@ -0,0 +1,52 @@
+{% extends "members/base.html" %}
+{% load i18n %}
+{% load static %}
+
+{% block title %}
+{% trans "Registration for waiting list" %}
+{% endblock %}
+
+{% block content %}
+
+
+
+{% trans "Register for waiting list" %}
+
+{% trans "Here you can register for the waiting list." %}
+
+{% if error_message %}
+ {{ error_message }}
+{% endif %}
+
+
+
+
+
+{% endblock %}
diff --git a/jdav_web/members/templates/members/register_waiting_list_success.html b/jdav_web/members/templates/members/register_waiting_list_success.html
new file mode 100644
index 0000000..53b8cb7
--- /dev/null
+++ b/jdav_web/members/templates/members/register_waiting_list_success.html
@@ -0,0 +1,17 @@
+{% extends "members/base.html" %}
+{% load i18n %}
+{% load static %}
+
+{% block title %}
+{% trans "Registration for waiting list." %}
+{% endblock %}
+
+{% block content %}
+
+{% trans "Registration for waiting list." %}
+
+{% trans "Your registration for the waiting list was successful." %}
+{% trans "Please remember to confirm all email addresses that you entered." %}
+{% trans "We will notify you if there is a vacant place in one of our groups." %}
+
+{% endblock %}
diff --git a/jdav_web/members/urls.py b/jdav_web/members/urls.py
index ee6540d..f128c6a 100644
--- a/jdav_web/members/urls.py
+++ b/jdav_web/members/urls.py
@@ -5,6 +5,8 @@ from . import views
app_name = "mailer"
urlpatterns = [
re_path(r'^echo', views.echo , name='echo'),
+ re_path(r'^registration', views.invited_registration , name='registration'),
re_path(r'^register', views.register , name='register'),
+ re_path(r'^waitinglist', views.register_waiting_list , name='register_waiting_list'),
re_path(r'^mail/confirm', views.confirm_mail , name='confirm_mail'),
]
diff --git a/jdav_web/members/views.py b/jdav_web/members/views.py
index 99972e5..73e55bf 100644
--- a/jdav_web/members/views.py
+++ b/jdav_web/members/views.py
@@ -2,7 +2,7 @@ from django.shortcuts import render
from django.utils.translation import gettext_lazy as _
from django.http import HttpResponseRedirect
from django.forms import ModelForm, TextInput, DateInput
-from members.models import Member, RegistrationPassword, MemberUnconfirmedProxy
+from members.models import Member, RegistrationPassword, MemberUnconfirmedProxy, MemberWaitingList, Group
from django.urls import reverse
from django.utils import timezone
@@ -35,6 +35,25 @@ class MemberRegistrationForm(ModelForm):
}
required = ['registration_form', 'street', 'plz', 'town']
+
+class MemberRegistrationWaitingListForm(ModelForm):
+ def __init__(self, *args, **kwargs):
+ super(MemberRegistrationWaitingListForm, self).__init__(*args, **kwargs)
+
+ for field in self.Meta.required:
+ self.fields[field].required = True
+
+ self.fields['cc_email_parents'].initial = False
+
+ class Meta:
+ model = MemberWaitingList
+ fields = ['prename', 'lastname', 'birth_date', 'email', 'email_parents', 'cc_email_parents']
+ widgets = {
+ 'birth_date': DateInput(format='%d.%m.%Y', attrs={'class': 'datepicker'})
+ }
+ required = []
+
+
def render_echo_failed(request, reason=""):
context = {}
if reason:
@@ -95,57 +114,100 @@ def render_register_wrong_password(request):
{'error_message': _("The entered password is wrong.")})
-def render_register_success(request, groupname, membername):
+def render_register_success(request, groupname, membername, needs_mail_confirmation):
return render(request,
'members/register_success.html',
{'groupname': groupname,
- 'membername': membername})
+ 'membername': membername,
+ 'needs_mail_confirmation': needs_mail_confirmation})
-def render_register(request, pwd, form=None):
+def render_register(request, group, form=None, pwd=None, waiter_key=''):
if form is None:
form = MemberRegistrationForm()
return render(request,
'members/register.html',
- {'form': form, 'pwd': pwd})
+ {'form': form,
+ 'group': group,
+ 'waiter_key': waiter_key,
+ 'pwd': pwd,
+ })
+
+
+def render_register_failed(request, reason=""):
+ context = {}
+ if reason:
+ context['reason'] = reason
+ return render(request, 'members/register_failed.html', context)
def register(request):
- if request.method == 'GET' or not "password" in request.POST:
+ if request.method == 'GET' or ("password" not in request.POST and "waiter_key" not in request.POST):
# show password
return render_register_password(request)
- # confirm password
- try:
- pwd = RegistrationPassword.objects.get(password=request.POST['password'])
- except RegistrationPassword.DoesNotExist:
- return render_register_wrong_password(request)
+
+ # find group and potential waiter
+ group = None
+ waiter = None
+ pwd = None
+ waiter_key = request.POST['waiter_key'] if 'waiter_key' in request.POST else ''
+ if "password" in request.POST and request.POST['password']:
+ # confirm password
+ try:
+ pwd = RegistrationPassword.objects.get(password=request.POST['password'])
+ group = pwd.group
+ except RegistrationPassword.DoesNotExist:
+ return render_register_wrong_password(request)
+ elif waiter_key:
+ try:
+ waiter = MemberWaitingList.objects.get(registration_key=waiter_key)
+ group = waiter.invited_for_group
+ except MemberWaitingList.DoesNotExist:
+ return render_register_failed(request)
+
+ # group must not be None
+ if group is None:
+ return render_register_failed(request)
+
if "save" in request.POST:
# process registration
form = MemberRegistrationForm(request.POST, request.FILES)
try:
new_member = form.save()
- new_member.group.add(pwd.group)
+ new_member.group.add(group)
new_member.confirmed = False
+ needs_mail_confirmation = True
+ if waiter:
+ if new_member.email == waiter.email and new_member.email_parents == waiter.email_parents:
+ new_member.confirmed_mail = True
+ new_member.confirmed_mail_parents = True
+ needs_mail_confirmation = False
+ new_member.notify_jugendleiters_about_confirmed_mail()
+ waiter.delete()
+
new_member.save()
- new_member.request_mail_confirmation()
- return render_register_success(request, pwd.group.name, new_member.prename)
+ if needs_mail_confirmation:
+ new_member.request_mail_confirmation()
+ return render_register_success(request, group.name, new_member.prename, needs_mail_confirmation)
except ValueError:
# when input is invalid
- return render_register(request, pwd, form)
+ return render_register(request, group, form, pwd=pwd, waiter_key=waiter_key)
# we are not saving yet
- return render_register(request, pwd, form=None)
+ return render_register(request, group, form=None, pwd=pwd, waiter_key=waiter_key)
def confirm_mail(request):
if request.method == 'GET' and 'key' in request.GET:
key = request.GET['key']
- res = MemberUnconfirmedProxy.objects.filter(confirm_mail_key=key) \
- | MemberUnconfirmedProxy.objects.filter(confirm_mail_parents_key=key)
- if len(res) != 1:
+ matching_unconfirmed = MemberUnconfirmedProxy.objects.filter(confirm_mail_key=key) \
+ | MemberUnconfirmedProxy.objects.filter(confirm_mail_parents_key=key)
+ matching_waiter = MemberWaitingList.objects.filter(confirm_mail_key=key) \
+ | MemberWaitingList.objects.filter(confirm_mail_parents_key=key)
+ if len(matching_unconfirmed) + len(matching_waiter) != 1:
return render_mail_confirmation_invalid(request)
- member = res[0]
- email, parents = member.confirm_mail(key)
- return render_mail_confirmation_success(request, email, member.prename, parents)
+ person = matching_unconfirmed[0] if len(matching_unconfirmed) == 1 else matching_waiter[0]
+ email, parents = person.confirm_mail(key)
+ return render_mail_confirmation_success(request, email, person.prename, parents)
return HttpResponseRedirect(reverse('startpage:index'))
@@ -156,3 +218,63 @@ def render_mail_confirmation_invalid(request):
def render_mail_confirmation_success(request, email, name, parents=False):
return render(request, 'members/mail_confirmation_success.html',
{'email': email, 'name': name, 'parents': parents})
+
+
+def render_register_waiting_list(request, form=None):
+ if form is None:
+ form = MemberRegistrationWaitingListForm()
+ return render(request,
+ 'members/register_waiting_list.html',
+ {'form': form})
+
+
+def render_register_waiting_list_success(request, membername):
+ return render(request,
+ 'members/register_waiting_list_success.html',
+ {'membername': membername})
+
+
+def register_waiting_list(request):
+ if request.method == 'GET':
+ # ask to fill in form
+ return render_register_waiting_list(request)
+ if "save" in request.POST:
+ # process registration for waiting list
+ form = MemberRegistrationWaitingListForm(request.POST, request.FILES)
+ try:
+ new_waiter = form.save()
+ new_waiter.save()
+ new_waiter.request_mail_confirmation()
+ return render_register_waiting_list_success(request, new_waiter.prename)
+ except ValueError:
+ # when input is invalid
+ return render_register_waiting_list(request, form)
+ # we are not saving yet
+ return render_register_waiting_list(request, form=None)
+
+
+def invited_registration(request):
+ if request.method == 'GET' and 'key' in request.GET:
+ try:
+ key = request.GET['key']
+ waiter = MemberWaitingList.objects.get(registration_key=key)
+ if not waiter.may_register(key):
+ raise KeyError
+ if not waiter.invited_for_group:
+ raise KeyError
+ form = MemberRegistrationForm(instance=waiter)
+ return render_register(request, group=waiter.invited_for_group, form=form, waiter_key=key)
+ except MemberWaitingList.DoesNotExist:
+ return render_invited_registration_failed(request, _("invalid"))
+ except KeyError:
+ return render_invited_registration_failed(request, _("expired"))
+
+ # if its a POST request
+ return register(request)
+
+
+def render_invited_registration_failed(request, reason=""):
+ context = {}
+ if reason:
+ context['reason'] = reason
+ return render(request, 'members/invited_registration_failed.html', context)