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 %} + +
+ + {% csrf_token %} + {{form}} +
+

+ + {% trans "I agree that my data is stored and processed on the server of the JDAV Ludwigsburg." %}

+ + +

+
+ + + +{% 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)