diff --git a/jdav_web/jdav_web/settings.py b/jdav_web/jdav_web/settings.py index 29e5538..a12df59 100644 --- a/jdav_web/jdav_web/settings.py +++ b/jdav_web/jdav_web/settings.py @@ -217,7 +217,8 @@ JET_SIDE_MENU_ITEMS = [ {'name': 'membernotelist'}, {'name': 'freizeit'}, {'name': 'klettertreff'}, - {'name': 'activitycategory', 'permissions': ['members.activitycategory'] }, + {'name': 'activitycategory', 'permissions': ['members.activitycategory']}, + {'name': 'memberunconfirmedproxy', 'permissions': ['members.memberunconfirmedproxy']}, ]}, {'app_label': 'material', 'items': [ {'name': 'materialcategory', 'permissions': ['material.materialcategory']}, diff --git a/jdav_web/mailer/mailutils.py b/jdav_web/mailer/mailutils.py index cb70e52..94e804c 100644 --- a/jdav_web/mailer/mailutils.py +++ b/jdav_web/mailer/mailutils.py @@ -5,6 +5,7 @@ import os NOT_SENT, SENT, PARTLY_SENT = 0, 1, 2 HOST = os.environ.get('DJANGO_ALLOWED_HOST', 'localhost:8000').split(",")[0] +HOST = 'localhost:8008' def send(subject, content, sender, recipients, message_id=None, reply_to=None, @@ -70,4 +71,8 @@ def get_echo_link(member): return "https://{}/members/echo?key={}".format(HOST, key) +def get_mail_confirmation_link(key): + return "https://{}/members/mail/confirm?key={}".format(HOST, key) + + mail_root = os.environ.get('EMAIL_SENDING_ADDRESS', 'christian@localhost') diff --git a/jdav_web/members/admin.py b/jdav_web/members/admin.py index 6bf6b6d..e2d6d22 100644 --- a/jdav_web/members/admin.py +++ b/jdav_web/members/admin.py @@ -23,7 +23,7 @@ from django.shortcuts import render from .models import (Member, Group, Freizeit, MemberNoteList, NewMemberOnList, Klettertreff, KlettertreffAttendee, ActivityCategory, OldMemberOnList, MemberList, - annotate_activity_score) + annotate_activity_score, RegistrationPassword, MemberUnconfirmedProxy) from mailer.mailutils import send as send_mail, get_echo_link, mail_root from django.conf import settings #from easy_select2 import apply_select2 @@ -89,7 +89,7 @@ class MemberAdmin(admin.ModelAdmin): def get_queryset(self, request): queryset = super().get_queryset(request) - return annotate_activity_score(queryset) + return annotate_activity_score(queryset.filter(confirmed=True)) def change_view(self, request, object_id, form_url="", extra_context=None): extra_context = extra_context or {} @@ -151,9 +151,68 @@ Deine JDAV Ludwigsburg""".format(name=member.prename, link=get_echo_link(member) activity_score.short_description = _('activity') +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'] + 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'] + change_form_template = "members/change_member_unconfirmed.html" + + def has_add_permission(self, request, obj=None): + return False + + def get_queryset(self, request): + queryset = super().get_queryset(request) + return queryset.filter(confirmed=False) + + def request_mail_confirmation(self, request, queryset): + for member in queryset: + member.request_mail_confirmation() + messages.success(request, _("Successfully requested mail confirmation from selected registrations.")) + request_mail_confirmation.short_description = _('Request mail confirmation from selected registrations') + + def confirm(self, request, queryset): + notify_individual = len(queryset.all()) < 10 + success = True + for member in queryset: + if member.confirm() and notify_individual: + messages.success(request, _("Successfully confirmed %(name)s.") % {'name': member.name}) + else: + if notify_individual: + messages.error(request, + _("Can't confirm. %(name)s has unconfirmed email addresses.") % {'name': member.name}) + success = False + if notify_individual: + return + if success: + messages.success(request, _("Successfully confirmed multiple registrations.")) + else: + messages.error(request, _("Failed to confirm some registrations because of unconfirmed email addresses.")) + confirm.short_description = _('Confirm selected registrations') + + def response_change(self, request, member): + if "_confirm" in request.POST: + if member.confirm(): + messages.success(request, _("Successfully confirmed %(name)s.") % {'name': member.name}) + else: + messages.error(request, + _("Can't confirm. %(name)s has unconfirmed email addresses.") % {'name': member.name}) + return super(MemberUnconfirmedAdmin, self).response_change(request, member) + + +class RegistrationPasswordInline(admin.TabularInline): + model = RegistrationPassword + extra = 0 + + class GroupAdmin(admin.ModelAdmin): fields = ['name', 'year_from', 'year_to'] list_display = ('name', 'year_from', 'year_to') + inlines = [RegistrationPasswordInline] class ActivityCategoryAdmin(admin.ModelAdmin): @@ -743,6 +802,7 @@ class KlettertreffAdmin(admin.ModelAdmin): admin.site.register(Member, MemberAdmin) +admin.site.register(MemberUnconfirmedProxy, MemberUnconfirmedAdmin) 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 88168f8..b572d75 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-02 12:55+0200\n" +"POT-Creation-Date: 2022-10-03 18:21+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,7 +18,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: members/admin.py:33 members/models.py:79 +#: members/admin.py:33 members/models.py:80 msgid "Registration complete" msgstr "Anmeldung vollständig" @@ -38,237 +38,307 @@ msgstr "Alle" msgid "Compose new mail to selected members" msgstr "Neue Nachricht an ausgewählte Teilnehmer verfassen" -#: members/admin.py:131 +#: members/admin.py:133 msgid "Successfully requested echo from selected members." -msgstr "Rückmeldungsaufforderung erfolgreich an ausgewählte Teilnehmer verschickt." +msgstr "" +"Rückmeldungsaufforderung erfolgreich an ausgewählte Teilnehmer verschickt." -#: members/admin.py:132 +#: members/admin.py:134 msgid "Request echo from selected members" msgstr "Rückmeldungsaufforderung an ausgewählte Teilnehmer verschicken" -#: members/admin.py:149 +#: members/admin.py:151 msgid "activity" msgstr "Aktivität" -#: members/admin.py:164 +#: members/admin.py:175 +msgid "Successfully requested mail confirmation from selected registrations." +msgstr "Aufforderung zur Bestätigung der Email Adresse versendet" + +#: members/admin.py:176 +msgid "Request mail confirmation from selected registrations" +msgstr "Aufforderung zur Bestätigung der Email Adresse versenden" + +#: members/admin.py:183 members/admin.py:200 +#, python-format +msgid "Successfully confirmed %(name)s." +msgstr "Registrierung von %(name)s erfolgreich bestätigt." + +#: members/admin.py:187 members/admin.py:203 +#, 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:192 +msgid "Successfully confirmed multiple registrations." +msgstr "Erfolgreich mehrere Registrierungen bestätigt." + +#: members/admin.py:194 +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:195 +msgid "Confirm selected registrations" +msgstr "Ausgewählte Registrierungen bestätigen" + +#: members/admin.py:225 msgid "Difficulty" msgstr "Schwierigkeit" -#: members/admin.py:167 members/admin.py:170 +#: members/admin.py:228 members/admin.py:231 msgid "Tour type" msgstr "Art der Tour" -#: members/admin.py:468 +#: members/admin.py:529 msgid "Convert to PDF" msgstr "Kriseninterventionsliste erstellen" -#: members/admin.py:577 +#: members/admin.py:638 msgid "Generate overview" msgstr "Hinweise für Jugendleiter erstellen" -#: members/admin.py:674 +#: members/admin.py:735 msgid "Generate list for LJP" msgstr "LJP Liste erstellen" -#: members/apps.py:7 members/models.py:181 +#: members/apps.py:7 members/models.py:229 msgid "members" msgstr "Teilnehmer" -#: members/models.py:25 +#: members/models.py:26 msgid "Name" msgstr "Name" -#: members/models.py:26 +#: members/models.py:27 msgid "Description" msgstr "Beschreibung" -#: members/models.py:32 members/models.py:205 members/models.py:284 +#: members/models.py:33 members/models.py:266 members/models.py:345 #: members/templates/members/change_member.html:17 msgid "Activity" msgstr "Aktivität" -#: members/models.py:33 +#: members/models.py:34 msgid "Activities" msgstr "Aktivitäten" -#: members/models.py:41 +#: members/models.py:42 msgid "name" msgstr "Name" -#: members/models.py:42 +#: members/models.py:43 msgid "lowest year" msgstr "Ab Jahrgang" -#: members/models.py:43 +#: members/models.py:44 msgid "highest year" msgstr "Bis Jahrgang" -#: members/models.py:50 members/models.py:72 +#: members/models.py:51 members/models.py:73 msgid "group" msgstr "Gruppe" -#: members/models.py:51 +#: members/models.py:52 msgid "groups" msgstr "Gruppen" -#: members/models.py:59 +#: members/models.py:60 msgid "prename" msgstr "Vorname" -#: members/models.py:60 +#: members/models.py:61 msgid "last name" msgstr "Nachname" -#: members/models.py:61 +#: members/models.py:62 msgid "street" msgstr "Straße" -#: members/models.py:62 +#: members/models.py:63 msgid "Postcode" msgstr "PLZ" -#: members/models.py:64 +#: members/models.py:65 msgid "town" msgstr "Stadt" -#: members/models.py:65 +#: members/models.py:66 msgid "phone number" msgstr "Telefonnummer" -#: members/models.py:66 +#: members/models.py:67 msgid "parents phone number" msgstr "Telefonnummer der Eltern" -#: members/models.py:69 +#: members/models.py:70 msgid "Parents' Email" msgstr "Email der Eltern" -#: members/models.py:70 +#: members/models.py:71 msgid "Also send mails to parents" msgstr "Emails auch an Eltern schicken" -#: members/models.py:71 +#: members/models.py:72 msgid "birth date" msgstr "Geburtsdatum" -#: members/models.py:73 +#: members/models.py:74 msgid "receives newsletter" msgstr "Erhält den Newsletter" -#: members/models.py:77 +#: members/models.py:78 msgid "comments" msgstr "Kommentare" -#: members/models.py:78 +#: members/models.py:79 msgid "created" msgstr "erstellt" -#: members/models.py:80 +#: members/models.py:81 msgid "Active" msgstr "Aktiv" -#: members/models.py:81 +#: members/models.py:82 msgid "Not waiting" msgstr "NICHT Warteliste" -#: members/models.py:82 +#: members/models.py:83 msgid "registration form" msgstr "Anmeldeformular" -#: members/models.py:92 +#: members/models.py:93 msgid "Echoed" msgstr "Rückgemeldet" -#: members/models.py:177 members/models.py:366 +#: members/models.py:94 +msgid "Confirmed" +msgstr "Bestätigt" + +#: members/models.py:95 +msgid "Email confirmed" +msgstr "Emailadresse bestätigt" + +#: members/models.py:96 +msgid "Parents email confirmed" +msgstr "Emailadresse der Eltern bestätigt" + +#: members/models.py:126 members/models.py:136 +msgid "Email confirmation" +msgstr "Email Bestätigung" + +#: members/models.py:225 members/models.py:427 msgid "Group" msgstr "Gruppe" -#: members/models.py:180 +#: members/models.py:228 msgid "member" msgstr "Teilnehmer" -#: members/models.py:207 members/models.py:286 +#: members/models.py:252 +msgid "Unconfirmed registration" +msgstr "Unbestätigte Registrierung" + +#: members/models.py:253 +msgid "Unconfirmed registrations" +msgstr "Unbestätigte Registrierungen" + +#: members/models.py:268 members/models.py:347 msgid "Place" msgstr "Ort" -#: members/models.py:208 members/models.py:287 +#: members/models.py:269 members/models.py:348 msgid "Destination (optional)" msgstr "Ziel (optional)" -#: members/models.py:210 members/models.py:289 members/models.py:344 -#: members/models.py:362 +#: members/models.py:271 members/models.py:350 members/models.py:405 +#: members/models.py:423 msgid "Date" msgstr "Datum" -#: members/models.py:211 members/models.py:290 +#: members/models.py:272 members/models.py:351 msgid "End (optional)" msgstr "Ende" -#: members/models.py:213 members/models.py:292 +#: members/models.py:274 members/models.py:353 msgid "Groups" msgstr "Gruppen" -#: members/models.py:221 members/models.py:305 +#: members/models.py:282 members/models.py:366 msgid "Categories" msgstr "Kategorien" -#: members/models.py:222 members/models.py:306 +#: members/models.py:283 members/models.py:367 msgid "easy" msgstr "leicht" -#: members/models.py:222 members/models.py:306 +#: members/models.py:283 members/models.py:367 msgid "medium" msgstr "mittel" -#: members/models.py:222 members/models.py:306 +#: members/models.py:283 members/models.py:367 msgid "hard" msgstr "schwer" -#: members/models.py:231 +#: members/models.py:292 msgid "Memberlist" msgstr "Teilnehmerliste" -#: members/models.py:232 +#: members/models.py:293 msgid "Memberlists" msgstr "Teilnehmerlisten" -#: members/models.py:250 members/models.py:258 members/models.py:266 -#: members/models.py:277 members/models.py:397 members/models.py:404 +#: members/models.py:311 members/models.py:319 members/models.py:327 +#: members/models.py:338 members/models.py:458 members/models.py:465 msgid "Member" msgstr "Teilnehmer" -#: members/models.py:252 members/models.py:271 +#: members/models.py:313 members/models.py:332 msgid "Comment" msgstr "Kommentar" -#: members/models.py:259 members/models.py:278 members/models.py:405 +#: members/models.py:320 members/models.py:339 members/models.py:466 msgid "Members" msgstr "Teilnehmer" -#: members/models.py:343 +#: members/models.py:404 msgid "Title" msgstr "Titel" -#: members/models.py:363 +#: members/models.py:424 msgid "Location" msgstr "Ort" -#: members/models.py:364 +#: members/models.py:425 msgid "Topic" msgstr "Thema" -#: members/models.py:388 +#: members/models.py:449 msgid "Jugendleiter" msgstr "Jugendleiter" -#: members/models.py:391 +#: members/models.py:452 msgid "Klettertreff" msgstr "Klettertreff" -#: members/models.py:392 +#: members/models.py:453 msgid "Klettertreffs" msgstr "Klettertreffs" +#: members/models.py:471 +msgid "Password" +msgstr "Passwort" + +#: members/models.py:474 +msgid "registration password" +msgstr "Registrierungspassort" + +#: members/models.py:475 +msgid "registration passwords" +msgstr "Registrierungspasswörter" + #: members/templates/admin/klettertreff_overview.html:9 msgid "date" msgstr "Datum" @@ -285,6 +355,10 @@ msgstr "Fähigkeiten:" msgid "Skill level" msgstr "Fähigkeitsniveau" +#: members/templates/members/change_member_unconfirmed.html:11 +msgid "Save and confirm registration" +msgstr "Speichern und Registrierung bestätigen" + #: members/templates/members/echo.html:6 members/templates/members/echo.html:13 #: members/templates/members/echo_failed.html:11 #: members/templates/members/echo_success.html:10 @@ -298,8 +372,10 @@ msgstr "" "Falls sich etwas geändert hat, trage das bitte hier ein." #: members/templates/members/echo.html:27 +#: members/templates/members/register.html:28 +#: members/templates/members/register_password.html:22 msgid "submit" -msgstr "Rückmelden" +msgstr "Bestätigen" #: members/templates/members/echo_failed.html:6 msgid "Echo failed" @@ -329,14 +405,96 @@ msgstr "Danke" msgid "Your data was successfully updated." msgstr "Deine Daten wurden erfolgreich aktualisiert." -#: members/views.py:46 members/views.py:67 +#: members/templates/members/mail_confirmation_invalid.html:6 +#: members/templates/members/mail_confirmation_invalid.html:11 +msgid "Mail confirmation failed" +msgstr "Emailbestätigung fehlgeschlagen" + +#: members/templates/members/mail_confirmation_invalid.html:13 +msgid "The supplied link is invalid." +msgstr "Der verwendete Link ist ungültig." + +#: members/templates/members/mail_confirmation_success.html:6 +#: members/templates/members/mail_confirmation_success.html:11 +msgid "Mail confirmed" +msgstr "Emailadresse bestätigt" + +#: members/templates/members/mail_confirmation_success.html:14 +#, python-format +msgid "" +"The email address %(email)s was successfully confirmed as parents email of " +"%(name)s." +msgstr "" +"Die Emailadresse %(email)s wurde erfolgreich als Emailadresse der Eltern von " +"%(name)s bestätigt." + +#: members/templates/members/mail_confirmation_success.html:17 +#, python-format +msgid "" +"The email address %(email)s was successfully confirmed as personal email of " +"%(name)s." +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 +#: members/templates/members/register_wrong_password.html:11 +msgid "Register" +msgstr "Registrieren" + +#: members/templates/members/register.html:15 +msgid "Here you can register for group" +msgstr "Hier kannst du dich registrieren für die Gruppe" + +#: members/templates/members/register_password.html:13 +msgid "" +"Thanks for your interest in participating. Please enter the registration " +"password, your youth leader gave you." +msgstr "" +"Danke für dein Interesse bei der JDAV Ludwigsburg teilzunehmen. Bitte gib " +"das Passwort ein, das du von deinem Jugendleiter erhalten hast." + +#: members/templates/members/register_success.html:13 +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." + +#: members/templates/members/register_wrong_password.html:13 +msgid "" +"You entered a wrong password to often. Please ask your youth leader again." +msgstr "" +"Du hast zu oft ein falsches Passwort eingegeben. Bitte frage deinen " +"Jugendleiter nach einem korrekten Passwort." + +#: members/views.py:54 members/views.py:75 msgid "invalid" msgstr "ungültig" -#: members/views.py:48 +#: members/views.py:56 msgid "expired" msgstr "abgelaufen" +#: members/views.py:85 +msgid "The entered password is wrong." +msgstr "Das eingegebene Passwort ist falsch." + +#~ msgid "Can't confirm. " +#~ msgstr "Bestätigung nicht möglich. " + #~ msgid "minimum age (years)" #~ msgstr "Mindestalter (Jahre)" diff --git a/jdav_web/members/models.py b/jdav_web/members/models.py index 15bd508..970aacb 100644 --- a/jdav_web/members/models.py +++ b/jdav_web/members/models.py @@ -10,6 +10,7 @@ from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelatio from django.contrib.contenttypes.models import ContentType from utils import RestrictedFileField import os +from mailer.mailutils import send as send_mail, mail_root, get_mail_confirmation_link from dateutil.relativedelta import relativedelta @@ -90,6 +91,11 @@ class Member(models.Model): 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="") def __str__(self): """String representation""" @@ -113,6 +119,48 @@ class Member(models.Model): 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'), + CONFIRM_MAIL_TEXT.format(name=self.prename, + group=group, + link=get_mail_confirmation_link(self.confirm_mail_key), + whattoconfirm='deiner Emailadresse'), + mail_root, + self.email) + if self.email_parents: + self.confirmed_mail_parents = False + self.confirm_mail_parents_key = uuid.uuid4().hex + send_mail(_('Email confirmation'), + 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, + self.email_parents) + else: + self.confirmed_mail_parents = True + self.save() + + def confirm_mail(self, key): + if self.confirm_mail_key == key: + self.confirm_mail_key, self.confirmed_mail = "", True + self.save() + return (self.email, False) + elif self.confirm_mail_parents_key == key: + self.confirm_mail_parents_key, self.confirmed_mail_parents = "", True + self.save() + return (self.email_parents, True) + + def confirm(self): + if not self.confirmed_mail or not self.confirmed_mail_parents: + return False + self.confirmed = True + self.save() + return True + def unsubscribe(self, key): if self.unsubscribe_key == key and timezone.now() <\ self.unsubscribe_expire: @@ -196,6 +244,19 @@ class Member(models.Model): return Freizeit.objects.filter(membersonlist__member=self) +class MemberUnconfirmedProxy(Member): + """Proxy to show unconfirmed members seperately in admin""" + + class Meta: + proxy = True + verbose_name = _('Unconfirmed registration') + verbose_name_plural = _('Unconfirmed registrations') + + def __str__(self): + """String representation""" + return self.name + + class MemberList(models.Model): """Lets the user create a list of members in pdf format. @@ -501,3 +562,15 @@ def annotate_activity_score(queryset): + F('_jugendleiter_klettertreff_score') + 3 * F('_jugendleiter_freizeit_score')) ) return queryset + + +CONFIRM_MAIL_TEXT = """Hallo {name}, + +du hast dich bei der JDAV Ludwigsburg für die Gruppe {group} registriert. Da bei uns alle Kommunikation +per Email funktioniert, brauchen wir eine Bestätigung {whattoconfirm}. Dazu klicke bitte einfach auf +folgenden Link: + +{link} + +Viele Grüße, +Deine JDAV Ludwigsburg""" diff --git a/jdav_web/members/templates/members/base.html b/jdav_web/members/templates/members/base.html index 4199dcf..36a8a9c 100644 --- a/jdav_web/members/templates/members/base.html +++ b/jdav_web/members/templates/members/base.html @@ -5,5 +5,5 @@ {% block navbar %}
  • Jugendgruppen
  • -
  • Mitglied
  • +
  • Mitglied
  • {% endblock %} diff --git a/jdav_web/members/templates/members/change_member_unconfirmed.html b/jdav_web/members/templates/members/change_member_unconfirmed.html new file mode 100644 index 0000000..679c7b1 --- /dev/null +++ b/jdav_web/members/templates/members/change_member_unconfirmed.html @@ -0,0 +1,15 @@ +{% extends "admin/change_form.html" %} +{% load i18n %} +{% block content %} +{{ block.super }} +{% load static %} + + + + +{% endblock %} diff --git a/jdav_web/members/templates/members/mail_confirmation_invalid.html b/jdav_web/members/templates/members/mail_confirmation_invalid.html new file mode 100644 index 0000000..731d999 --- /dev/null +++ b/jdav_web/members/templates/members/mail_confirmation_invalid.html @@ -0,0 +1,15 @@ +{% extends "members/base.html" %} +{% load i18n %} +{% load static %} + +{% block title %} +{% trans "Mail confirmation failed" %} +{% endblock %} + +{% block content %} + +

    {% trans "Mail confirmation failed" %}

    + +

    {% trans "The supplied link is invalid." %}

    + +{% endblock %} diff --git a/jdav_web/members/templates/members/mail_confirmation_success.html b/jdav_web/members/templates/members/mail_confirmation_success.html new file mode 100644 index 0000000..698527d --- /dev/null +++ b/jdav_web/members/templates/members/mail_confirmation_success.html @@ -0,0 +1,21 @@ +{% extends "members/base.html" %} +{% load i18n %} +{% load static %} + +{% block title %} +{% trans "Mail confirmed" %} +{% endblock %} + +{% block content %} + +

    {% trans "Mail confirmed" %}

    + +{% if parents %} +

    {% blocktrans %}The email address {{ email }} was successfully confirmed as parents email of {{name}}.{% endblocktrans %} +

    +{% else %} +

    {% blocktrans %}The email address {{email}} was successfully confirmed as personal email of {{name}}.{% endblocktrans %} +

    +{% endif %} + +{% endblock %} diff --git a/jdav_web/members/templates/members/register.html b/jdav_web/members/templates/members/register.html index dfe6b03..c4f46d8 100644 --- a/jdav_web/members/templates/members/register.html +++ b/jdav_web/members/templates/members/register.html @@ -12,7 +12,7 @@

    {% trans "Register" %}

    -

    {% trans "Here you can register for group" %} {{groupname}}.

    +

    {% trans "Here you can register for group" %} {{ pwd.group.name }}.

    {% if error_message %}

    {{ error_message }}

    @@ -23,7 +23,8 @@ {% csrf_token %} {{form}} - + +

    diff --git a/jdav_web/members/templates/members/register_password.html b/jdav_web/members/templates/members/register_password.html index c3413f4..cb9ab3f 100644 --- a/jdav_web/members/templates/members/register_password.html +++ b/jdav_web/members/templates/members/register_password.html @@ -17,6 +17,7 @@ {% endif %}
    + {% csrf_token %}

    diff --git a/jdav_web/members/urls.py b/jdav_web/members/urls.py index 5a4e10a..ee6540d 100644 --- a/jdav_web/members/urls.py +++ b/jdav_web/members/urls.py @@ -5,4 +5,6 @@ from . import views app_name = "mailer" urlpatterns = [ re_path(r'^echo', views.echo , name='echo'), + re_path(r'^register', views.register , name='register'), + 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 34e9d1f..a2b8458 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 +from members.models import Member, RegistrationPassword from django.urls import reverse from django.utils import timezone @@ -16,10 +16,14 @@ class MemberForm(ModelForm): 'birth_date': DateInput(format='%d.%m.%Y', attrs={'class': 'datepicker'}) } -class MemberFormWithEmail(MemberForm): +class MemberFormWithEmail(ModelForm): class Meta: + model = Member fields = ['prename', 'lastname', 'street', 'plz', 'town', 'phone_number', 'phone_number_parents', 'birth_date', 'email', 'email_parents', 'cc_email_parents'] + widgets = { + 'birth_date': DateInput(format='%d.%m.%Y', attrs={'class': 'datepicker'}) + } def render_echo_failed(request, reason=""): context = {} @@ -78,7 +82,7 @@ def render_register_password(request): def render_register_wrong_password(request): return render(request, 'members/register_password.html', - {'error_message': _("The entered password is wrong.")) + {'error_message': _("The entered password is wrong.")}) def render_register_success(request, groupname, membername): @@ -88,12 +92,12 @@ def render_register_success(request, groupname, membername): 'membername': membername}) -def render_register(request, groupname, pwd, form=None): +def render_register(request, pwd, form=None): if form is None: - form = MemberFormWithEmail(request.POST) + form = MemberFormWithEmail() return render(request, 'members/register.html', - {'form': form, 'password': pwd, 'groupname': groupname}) + {'form': form, 'pwd': pwd}) def register(request): @@ -103,16 +107,41 @@ def register(request): # confirm password try: pwd = RegistrationPassword.objects.get(password=request.POST['password']) - except Member.DoesNotExist: + except RegistrationPassword.DoesNotExist: return render_register_wrong_password(request) if "save" in request.POST: # process registration form = MemberFormWithEmail(request.POST) try: - form.save() - return render_register_success(request, pwd.group.name, form.prename) + new_member = form.save() + new_member.group.add(pwd.group) + new_member.confirmed = False + new_member.save() + new_member.request_mail_confirmation() + return render_register_success(request, pwd.group.name, new_member.prename) except ValueError: # when input is invalid return render_register(request, pwd, form) # we are not saving yet return render_register(request, pwd, form=None) + + +def confirm_mail(request): + if request.method == 'GET' and 'key' in request.GET: + key = request.GET['key'] + res = Member.objects.filter(confirm_mail_key=key) | Member.objects.filter(confirm_mail_parents_key=key) + if len(res) != 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) + return HttpResponseRedirect(reverse('startpage:index')) + + +def render_mail_confirmation_invalid(request): + return render(request, 'members/mail_confirmation_invalid.html') + + +def render_mail_confirmation_success(request, email, name, parents=False): + return render(request, 'members/mail_confirmation_success.html', + {'email': email, 'name': name, 'parents': parents})