members: add mail confirmation, improve admin page, translations

v1-0-stable
Christian Merten 3 years ago
parent 9722dd68c5
commit 3bdfbd9083
Signed by: christian.merten
GPG Key ID: D953D69721B948B3

@ -217,7 +217,8 @@ JET_SIDE_MENU_ITEMS = [
{'name': 'membernotelist'}, {'name': 'membernotelist'},
{'name': 'freizeit'}, {'name': 'freizeit'},
{'name': 'klettertreff'}, {'name': 'klettertreff'},
{'name': 'activitycategory', 'permissions': ['members.activitycategory'] }, {'name': 'activitycategory', 'permissions': ['members.activitycategory']},
{'name': 'memberunconfirmedproxy', 'permissions': ['members.memberunconfirmedproxy']},
]}, ]},
{'app_label': 'material', 'items': [ {'app_label': 'material', 'items': [
{'name': 'materialcategory', 'permissions': ['material.materialcategory']}, {'name': 'materialcategory', 'permissions': ['material.materialcategory']},

@ -5,6 +5,7 @@ import os
NOT_SENT, SENT, PARTLY_SENT = 0, 1, 2 NOT_SENT, SENT, PARTLY_SENT = 0, 1, 2
HOST = os.environ.get('DJANGO_ALLOWED_HOST', 'localhost:8000').split(",")[0] 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, 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) 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') mail_root = os.environ.get('EMAIL_SENDING_ADDRESS', 'christian@localhost')

@ -23,7 +23,7 @@ from django.shortcuts import render
from .models import (Member, Group, Freizeit, MemberNoteList, NewMemberOnList, Klettertreff, from .models import (Member, Group, Freizeit, MemberNoteList, NewMemberOnList, Klettertreff,
KlettertreffAttendee, ActivityCategory, OldMemberOnList, MemberList, 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 mailer.mailutils import send as send_mail, get_echo_link, mail_root
from django.conf import settings from django.conf import settings
#from easy_select2 import apply_select2 #from easy_select2 import apply_select2
@ -89,7 +89,7 @@ class MemberAdmin(admin.ModelAdmin):
def get_queryset(self, request): def get_queryset(self, request):
queryset = super().get_queryset(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): def change_view(self, request, object_id, form_url="", extra_context=None):
extra_context = extra_context or {} 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') 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): class GroupAdmin(admin.ModelAdmin):
fields = ['name', 'year_from', 'year_to'] fields = ['name', 'year_from', 'year_to']
list_display = ('name', 'year_from', 'year_to') list_display = ('name', 'year_from', 'year_to')
inlines = [RegistrationPasswordInline]
class ActivityCategoryAdmin(admin.ModelAdmin): class ActivityCategoryAdmin(admin.ModelAdmin):
@ -743,6 +802,7 @@ class KlettertreffAdmin(admin.ModelAdmin):
admin.site.register(Member, MemberAdmin) admin.site.register(Member, MemberAdmin)
admin.site.register(MemberUnconfirmedProxy, MemberUnconfirmedAdmin)
admin.site.register(Group, GroupAdmin) admin.site.register(Group, GroupAdmin)
admin.site.register(Freizeit, FreizeitAdmin) admin.site.register(Freizeit, FreizeitAdmin)
admin.site.register(MemberNoteList, MemberNoteListAdmin) admin.site.register(MemberNoteList, MemberNoteListAdmin)

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -18,7 +18,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\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" msgid "Registration complete"
msgstr "Anmeldung vollständig" msgstr "Anmeldung vollständig"
@ -38,237 +38,307 @@ msgstr "Alle"
msgid "Compose new mail to selected members" msgid "Compose new mail to selected members"
msgstr "Neue Nachricht an ausgewählte Teilnehmer verfassen" msgstr "Neue Nachricht an ausgewählte Teilnehmer verfassen"
#: members/admin.py:131 #: members/admin.py:133
msgid "Successfully requested echo from selected members." 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" msgid "Request echo from selected members"
msgstr "Rückmeldungsaufforderung an ausgewählte Teilnehmer verschicken" msgstr "Rückmeldungsaufforderung an ausgewählte Teilnehmer verschicken"
#: members/admin.py:149 #: members/admin.py:151
msgid "activity" msgid "activity"
msgstr "Aktivität" 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" msgid "Difficulty"
msgstr "Schwierigkeit" msgstr "Schwierigkeit"
#: members/admin.py:167 members/admin.py:170 #: members/admin.py:228 members/admin.py:231
msgid "Tour type" msgid "Tour type"
msgstr "Art der Tour" msgstr "Art der Tour"
#: members/admin.py:468 #: members/admin.py:529
msgid "Convert to PDF" msgid "Convert to PDF"
msgstr "Kriseninterventionsliste erstellen" msgstr "Kriseninterventionsliste erstellen"
#: members/admin.py:577 #: members/admin.py:638
msgid "Generate overview" msgid "Generate overview"
msgstr "Hinweise für Jugendleiter erstellen" msgstr "Hinweise für Jugendleiter erstellen"
#: members/admin.py:674 #: members/admin.py:735
msgid "Generate list for LJP" msgid "Generate list for LJP"
msgstr "LJP Liste erstellen" msgstr "LJP Liste erstellen"
#: members/apps.py:7 members/models.py:181 #: members/apps.py:7 members/models.py:229
msgid "members" msgid "members"
msgstr "Teilnehmer" msgstr "Teilnehmer"
#: members/models.py:25 #: members/models.py:26
msgid "Name" msgid "Name"
msgstr "Name" msgstr "Name"
#: members/models.py:26 #: members/models.py:27
msgid "Description" msgid "Description"
msgstr "Beschreibung" 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 #: members/templates/members/change_member.html:17
msgid "Activity" msgid "Activity"
msgstr "Aktivität" msgstr "Aktivität"
#: members/models.py:33 #: members/models.py:34
msgid "Activities" msgid "Activities"
msgstr "Aktivitäten" msgstr "Aktivitäten"
#: members/models.py:41 #: members/models.py:42
msgid "name" msgid "name"
msgstr "Name" msgstr "Name"
#: members/models.py:42 #: members/models.py:43
msgid "lowest year" msgid "lowest year"
msgstr "Ab Jahrgang" msgstr "Ab Jahrgang"
#: members/models.py:43 #: members/models.py:44
msgid "highest year" msgid "highest year"
msgstr "Bis Jahrgang" msgstr "Bis Jahrgang"
#: members/models.py:50 members/models.py:72 #: members/models.py:51 members/models.py:73
msgid "group" msgid "group"
msgstr "Gruppe" msgstr "Gruppe"
#: members/models.py:51 #: members/models.py:52
msgid "groups" msgid "groups"
msgstr "Gruppen" msgstr "Gruppen"
#: members/models.py:59 #: members/models.py:60
msgid "prename" msgid "prename"
msgstr "Vorname" msgstr "Vorname"
#: members/models.py:60 #: members/models.py:61
msgid "last name" msgid "last name"
msgstr "Nachname" msgstr "Nachname"
#: members/models.py:61 #: members/models.py:62
msgid "street" msgid "street"
msgstr "Straße" msgstr "Straße"
#: members/models.py:62 #: members/models.py:63
msgid "Postcode" msgid "Postcode"
msgstr "PLZ" msgstr "PLZ"
#: members/models.py:64 #: members/models.py:65
msgid "town" msgid "town"
msgstr "Stadt" msgstr "Stadt"
#: members/models.py:65 #: members/models.py:66
msgid "phone number" msgid "phone number"
msgstr "Telefonnummer" msgstr "Telefonnummer"
#: members/models.py:66 #: members/models.py:67
msgid "parents phone number" msgid "parents phone number"
msgstr "Telefonnummer der Eltern" msgstr "Telefonnummer der Eltern"
#: members/models.py:69 #: members/models.py:70
msgid "Parents' Email" msgid "Parents' Email"
msgstr "Email der Eltern" msgstr "Email der Eltern"
#: members/models.py:70 #: members/models.py:71
msgid "Also send mails to parents" msgid "Also send mails to parents"
msgstr "Emails auch an Eltern schicken" msgstr "Emails auch an Eltern schicken"
#: members/models.py:71 #: members/models.py:72
msgid "birth date" msgid "birth date"
msgstr "Geburtsdatum" msgstr "Geburtsdatum"
#: members/models.py:73 #: members/models.py:74
msgid "receives newsletter" msgid "receives newsletter"
msgstr "Erhält den Newsletter" msgstr "Erhält den Newsletter"
#: members/models.py:77 #: members/models.py:78
msgid "comments" msgid "comments"
msgstr "Kommentare" msgstr "Kommentare"
#: members/models.py:78 #: members/models.py:79
msgid "created" msgid "created"
msgstr "erstellt" msgstr "erstellt"
#: members/models.py:80 #: members/models.py:81
msgid "Active" msgid "Active"
msgstr "Aktiv" msgstr "Aktiv"
#: members/models.py:81 #: members/models.py:82
msgid "Not waiting" msgid "Not waiting"
msgstr "NICHT Warteliste" msgstr "NICHT Warteliste"
#: members/models.py:82 #: members/models.py:83
msgid "registration form" msgid "registration form"
msgstr "Anmeldeformular" msgstr "Anmeldeformular"
#: members/models.py:92 #: members/models.py:93
msgid "Echoed" msgid "Echoed"
msgstr "Rückgemeldet" 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" msgid "Group"
msgstr "Gruppe" msgstr "Gruppe"
#: members/models.py:180 #: members/models.py:228
msgid "member" msgid "member"
msgstr "Teilnehmer" 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" msgid "Place"
msgstr "Ort" msgstr "Ort"
#: members/models.py:208 members/models.py:287 #: members/models.py:269 members/models.py:348
msgid "Destination (optional)" msgid "Destination (optional)"
msgstr "Ziel (optional)" msgstr "Ziel (optional)"
#: members/models.py:210 members/models.py:289 members/models.py:344 #: members/models.py:271 members/models.py:350 members/models.py:405
#: members/models.py:362 #: members/models.py:423
msgid "Date" msgid "Date"
msgstr "Datum" msgstr "Datum"
#: members/models.py:211 members/models.py:290 #: members/models.py:272 members/models.py:351
msgid "End (optional)" msgid "End (optional)"
msgstr "Ende" msgstr "Ende"
#: members/models.py:213 members/models.py:292 #: members/models.py:274 members/models.py:353
msgid "Groups" msgid "Groups"
msgstr "Gruppen" msgstr "Gruppen"
#: members/models.py:221 members/models.py:305 #: members/models.py:282 members/models.py:366
msgid "Categories" msgid "Categories"
msgstr "Kategorien" msgstr "Kategorien"
#: members/models.py:222 members/models.py:306 #: members/models.py:283 members/models.py:367
msgid "easy" msgid "easy"
msgstr "leicht" msgstr "leicht"
#: members/models.py:222 members/models.py:306 #: members/models.py:283 members/models.py:367
msgid "medium" msgid "medium"
msgstr "mittel" msgstr "mittel"
#: members/models.py:222 members/models.py:306 #: members/models.py:283 members/models.py:367
msgid "hard" msgid "hard"
msgstr "schwer" msgstr "schwer"
#: members/models.py:231 #: members/models.py:292
msgid "Memberlist" msgid "Memberlist"
msgstr "Teilnehmerliste" msgstr "Teilnehmerliste"
#: members/models.py:232 #: members/models.py:293
msgid "Memberlists" msgid "Memberlists"
msgstr "Teilnehmerlisten" msgstr "Teilnehmerlisten"
#: members/models.py:250 members/models.py:258 members/models.py:266 #: members/models.py:311 members/models.py:319 members/models.py:327
#: members/models.py:277 members/models.py:397 members/models.py:404 #: members/models.py:338 members/models.py:458 members/models.py:465
msgid "Member" msgid "Member"
msgstr "Teilnehmer" msgstr "Teilnehmer"
#: members/models.py:252 members/models.py:271 #: members/models.py:313 members/models.py:332
msgid "Comment" msgid "Comment"
msgstr "Kommentar" 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" msgid "Members"
msgstr "Teilnehmer" msgstr "Teilnehmer"
#: members/models.py:343 #: members/models.py:404
msgid "Title" msgid "Title"
msgstr "Titel" msgstr "Titel"
#: members/models.py:363 #: members/models.py:424
msgid "Location" msgid "Location"
msgstr "Ort" msgstr "Ort"
#: members/models.py:364 #: members/models.py:425
msgid "Topic" msgid "Topic"
msgstr "Thema" msgstr "Thema"
#: members/models.py:388 #: members/models.py:449
msgid "Jugendleiter" msgid "Jugendleiter"
msgstr "Jugendleiter" msgstr "Jugendleiter"
#: members/models.py:391 #: members/models.py:452
msgid "Klettertreff" msgid "Klettertreff"
msgstr "Klettertreff" msgstr "Klettertreff"
#: members/models.py:392 #: members/models.py:453
msgid "Klettertreffs" msgid "Klettertreffs"
msgstr "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 #: members/templates/admin/klettertreff_overview.html:9
msgid "date" msgid "date"
msgstr "Datum" msgstr "Datum"
@ -285,6 +355,10 @@ msgstr "Fähigkeiten:"
msgid "Skill level" msgid "Skill level"
msgstr "Fähigkeitsniveau" 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.html:6 members/templates/members/echo.html:13
#: members/templates/members/echo_failed.html:11 #: members/templates/members/echo_failed.html:11
#: members/templates/members/echo_success.html:10 #: members/templates/members/echo_success.html:10
@ -298,8 +372,10 @@ msgstr ""
"Falls sich etwas geändert hat, trage das bitte hier ein." "Falls sich etwas geändert hat, trage das bitte hier ein."
#: members/templates/members/echo.html:27 #: members/templates/members/echo.html:27
#: members/templates/members/register.html:28
#: members/templates/members/register_password.html:22
msgid "submit" msgid "submit"
msgstr "Rückmelden" msgstr "Bestätigen"
#: members/templates/members/echo_failed.html:6 #: members/templates/members/echo_failed.html:6
msgid "Echo failed" msgid "Echo failed"
@ -329,14 +405,96 @@ msgstr "Danke"
msgid "Your data was successfully updated." msgid "Your data was successfully updated."
msgstr "Deine Daten wurden erfolgreich aktualisiert." 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" msgid "invalid"
msgstr "ungültig" msgstr "ungültig"
#: members/views.py:48 #: members/views.py:56
msgid "expired" msgid "expired"
msgstr "abgelaufen" 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)" #~ msgid "minimum age (years)"
#~ msgstr "Mindestalter (Jahre)" #~ msgstr "Mindestalter (Jahre)"

@ -10,6 +10,7 @@ from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelatio
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from utils import RestrictedFileField from utils import RestrictedFileField
import os import os
from mailer.mailutils import send as send_mail, mail_root, get_mail_confirmation_link
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
@ -90,6 +91,11 @@ class Member(models.Model):
echo_key = models.CharField(max_length=32, default="") echo_key = models.CharField(max_length=32, default="")
echo_expire = models.DateTimeField(default=timezone.now) echo_expire = models.DateTimeField(default=timezone.now)
echoed = models.BooleanField(default=True, verbose_name=_('Echoed')) 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): def __str__(self):
"""String representation""" """String representation"""
@ -113,6 +119,48 @@ class Member(models.Model):
self.save() self.save()
return self.echo_key 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): def unsubscribe(self, key):
if self.unsubscribe_key == key and timezone.now() <\ if self.unsubscribe_key == key and timezone.now() <\
self.unsubscribe_expire: self.unsubscribe_expire:
@ -196,6 +244,19 @@ class Member(models.Model):
return Freizeit.objects.filter(membersonlist__member=self) 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): class MemberList(models.Model):
"""Lets the user create a list of members in pdf format. """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')) + F('_jugendleiter_klettertreff_score') + 3 * F('_jugendleiter_freizeit_score'))
) )
return queryset 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"""

@ -5,5 +5,5 @@
{% block navbar %} {% block navbar %}
<li><a href="/">Jugendgruppen</a></li> <li><a href="/">Jugendgruppen</a></li>
<li class="current"><a href="" %}">Mitglied</a></li> <li class="current"><a href="?">Mitglied</a></li>
{% endblock %} {% endblock %}

@ -0,0 +1,15 @@
{% extends "admin/change_form.html" %}
{% load i18n %}
{% block content %}
{{ block.super }}
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'mailer/change_style.css' %}" />
<script type="text/javascript">
(function($){
$('<input type="submit" value="{% trans 'Save and confirm registration' %}" name="_confirm" class="send_mail"/>')
.prependTo('div.submit-row');
})(django.jQuery);
</script>
{% endblock %}

@ -0,0 +1,15 @@
{% extends "members/base.html" %}
{% load i18n %}
{% load static %}
{% block title %}
{% trans "Mail confirmation failed" %}
{% endblock %}
{% block content %}
<h1>{% trans "Mail confirmation failed" %}</h1>
<p>{% trans "The supplied link is invalid." %}</p>
{% endblock %}

@ -0,0 +1,21 @@
{% extends "members/base.html" %}
{% load i18n %}
{% load static %}
{% block title %}
{% trans "Mail confirmed" %}
{% endblock %}
{% block content %}
<h1>{% trans "Mail confirmed" %}</h1>
{% if parents %}
<p>{% blocktrans %}The email address {{ email }} was successfully confirmed as parents email of {{name}}.{% endblocktrans %}
</p>
{% else %}
<p>{% blocktrans %}The email address {{email}} was successfully confirmed as personal email of {{name}}.{% endblocktrans %}
</p>
{% endif %}
{% endblock %}

@ -12,7 +12,7 @@
<h1>{% trans "Register" %}</h1> <h1>{% trans "Register" %}</h1>
<p>{% trans "Here you can register for group" %} {{groupname}}.</p> <p>{% trans "Here you can register for group" %} {{ pwd.group.name }}.</p>
{% if error_message %} {% if error_message %}
<p><b>{{ error_message }}</b></p> <p><b>{{ error_message }}</b></p>
@ -23,7 +23,8 @@
{% csrf_token %} {% csrf_token %}
{{form}} {{form}}
</table> </table>
<input type="hidden" name="password" value="{{ password }}"> <input type="hidden" name="password" value="{{ pwd.password }}">
<input type="hidden" name="save">
<p><input type="submit" value="{% trans "submit" %}"/></p> <p><input type="submit" value="{% trans "submit" %}"/></p>
</form> </form>

@ -17,6 +17,7 @@
{% endif %} {% endif %}
<form action="" method="post"> <form action="" method="post">
{% csrf_token %}
<input type="password" name="password" required> <input type="password" name="password" required>
<p><input type="submit" value="{% trans "submit" %}"/></p> <p><input type="submit" value="{% trans "submit" %}"/></p>
</form> </form>

@ -5,4 +5,6 @@ from . import views
app_name = "mailer" app_name = "mailer"
urlpatterns = [ urlpatterns = [
re_path(r'^echo', views.echo , name='echo'), 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'),
] ]

@ -2,7 +2,7 @@ from django.shortcuts import render
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.forms import ModelForm, TextInput, DateInput 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.urls import reverse
from django.utils import timezone from django.utils import timezone
@ -16,10 +16,14 @@ class MemberForm(ModelForm):
'birth_date': DateInput(format='%d.%m.%Y', attrs={'class': 'datepicker'}) 'birth_date': DateInput(format='%d.%m.%Y', attrs={'class': 'datepicker'})
} }
class MemberFormWithEmail(MemberForm): class MemberFormWithEmail(ModelForm):
class Meta: class Meta:
model = Member
fields = ['prename', 'lastname', 'street', 'plz', 'town', 'phone_number', fields = ['prename', 'lastname', 'street', 'plz', 'town', 'phone_number',
'phone_number_parents', 'birth_date', 'email', 'email_parents', 'cc_email_parents'] '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=""): def render_echo_failed(request, reason=""):
context = {} context = {}
@ -78,7 +82,7 @@ def render_register_password(request):
def render_register_wrong_password(request): def render_register_wrong_password(request):
return render(request, return render(request,
'members/register_password.html', '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): def render_register_success(request, groupname, membername):
@ -88,12 +92,12 @@ def render_register_success(request, groupname, membername):
'membername': membername}) 'membername': membername})
def render_register(request, groupname, pwd, form=None): def render_register(request, pwd, form=None):
if form is None: if form is None:
form = MemberFormWithEmail(request.POST) form = MemberFormWithEmail()
return render(request, return render(request,
'members/register.html', 'members/register.html',
{'form': form, 'password': pwd, 'groupname': groupname}) {'form': form, 'pwd': pwd})
def register(request): def register(request):
@ -103,16 +107,41 @@ def register(request):
# confirm password # confirm password
try: try:
pwd = RegistrationPassword.objects.get(password=request.POST['password']) pwd = RegistrationPassword.objects.get(password=request.POST['password'])
except Member.DoesNotExist: except RegistrationPassword.DoesNotExist:
return render_register_wrong_password(request) return render_register_wrong_password(request)
if "save" in request.POST: if "save" in request.POST:
# process registration # process registration
form = MemberFormWithEmail(request.POST) form = MemberFormWithEmail(request.POST)
try: try:
form.save() new_member = form.save()
return render_register_success(request, pwd.group.name, form.prename) 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: except ValueError:
# when input is invalid # when input is invalid
return render_register(request, pwd, form) return render_register(request, pwd, form)
# we are not saving yet # we are not saving yet
return render_register(request, pwd, form=None) 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})

Loading…
Cancel
Save