waiting list: add intermediate view to select group when inviting waiter

v1-0-stable
Christian Merten 3 years ago
parent 7390459ad8
commit a362f963b4
Signed by: christian.merten
GPG Key ID: D953D69721B948B3

@ -7,7 +7,9 @@ import time
import unicodedata
import random
import string
from functools import partial, update_wrapper
from django.urls import path, reverse
from django.http import HttpResponse, HttpResponseRedirect
from wsgiref.util import FileWrapper
from django import forms
@ -25,7 +27,7 @@ from .models import (Member, Group, Freizeit, MemberNoteList, NewMemberOnList, K
MemberWaitingList,
KlettertreffAttendee, ActivityCategory, OldMemberOnList, MemberList,
annotate_activity_score, RegistrationPassword, MemberUnconfirmedProxy)
from mailer.mailutils import send as send_mail, get_echo_link, mail_root, get_registration_link
from mailer.mailutils import send as send_mail, get_echo_link, mail_root
from django.conf import settings
#from easy_select2 import apply_select2
@ -238,48 +240,106 @@ class MemberUnconfirmedAdmin(admin.ModelAdmin):
return super(MemberUnconfirmedAdmin, self).response_change(request, member)
class WaiterInviteForm(forms.Form):
_selected_action = forms.CharField(widget=forms.MultipleHiddenInput)
group = forms.ModelChoiceField(queryset=Group.objects.all(),
label=_('Group'))
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']
readonly_fields= ('invited_for_group',)
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:
if "apply" in request.POST:
try:
group = Group.objects.get(pk=request.POST['group'])
except Group.DoesNotExist:
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.
_("An error occurred while trying to invite said members. Please try again."))
return HttpResponseRedirect(request.get_full_path())
for waiter in queryset:
waiter.invited_for_group = group
waiter.save()
waiter.invite_to_group()
messages.success(request,
_("Successfully invited %(name)s to %(group)s.") % {'name': waiter.name, 'group': waiter.invited_for_group.name})
return HttpResponseRedirect(request.get_full_path())
context = dict(self.admin_site.each_context(request),
title=_('Select group for invitation'),
opts=self.opts,
waiters=queryset.all(),
form=WaiterInviteForm(initial={'_selected_action': queryset.values_list('id', flat=True)}))
return render(request,
'admin/invite_selected_for_group.html',
context=context)
ask_for_registration.short_description = _('Offer waiter a place in a group.')
Bei Fragen, wende dich gerne an jugendreferent@jdav-ludwigsburg.de.
def response_change(self, request, waiter):
ret = super(MemberWaitingListAdmin, self).response_change(request, waiter)
if "_invite" in request.POST:
return HttpResponseRedirect(
reverse('admin:%s_%s_invite' % (waiter._meta.app_label, waiter._meta.model_name),
args=(waiter.pk,)))
return ret
def get_urls(self):
urls = super().get_urls()
def wrap(view):
def wrapper(*args, **kwargs):
return self.admin_site.admin_view(view)(*args, **kwargs)
wrapper.model_admin = self
return update_wrapper(wrapper, view)
custom_urls = [
path(
"<path:object_id>/invite/",
wrap(self.invite_view),
name="%s_%s_invite" % (self.opts.app_label, self.opts.model_name),
),
]
return custom_urls + urls
def invite_view(self, request, object_id):
waiter = MemberWaitingList.objects.get(pk=object_id)
if "apply" in request.POST:
try:
group = Group.objects.get(pk=request.POST['group'])
except Group.DoesNotExist:
messages.error(request,
_("An error occurred while trying to invite said members. Please try again."))
return HttpResponseRedirect(request.get_full_path())
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)
waiter.invited_for_group = group
waiter.save()
waiter.invite_to_group()
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.')
return HttpResponseRedirect(reverse('admin:%s_%s_changelist' % (waiter._meta.app_label, waiter._meta.model_name)))
context = dict(self.admin_site.each_context(request),
title=_('Select group for invitation'),
opts=self.opts,
object=waiter,
waiter=waiter,
form=WaiterInviteForm(initial={'_selected_action': [waiter.pk]}))
return render(request,
'admin/invite_for_group.html',
context=context)
class RegistrationPasswordInline(admin.TabularInline):
model = RegistrationPassword

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-03-10 23:28+0100\n"
"POT-Creation-Date: 2023-03-12 19:31+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -18,472 +18,520 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: members/admin.py:34 members/models.py:161
#: admin.py:36 models.py:161
msgid "Registration complete"
msgstr "Anmeldung vollständig"
#: members/admin.py:40
#: admin.py:42
msgid "True"
msgstr "Ja"
#: members/admin.py:41
#: admin.py:43
msgid "False"
msgstr "Nein"
#: members/admin.py:42
#: admin.py:44
msgid "All"
msgstr "Alle"
#: members/admin.py:116
#: admin.py:118
msgid "Compose new mail to selected members"
msgstr "Neue Nachricht an ausgewählte Teilnehmer verfassen"
#: members/admin.py:141
#: admin.py:143
msgid "Successfully requested echo from selected members."
msgstr ""
"Rückmeldungsaufforderung erfolgreich an ausgewählte Teilnehmer verschickt."
#: members/admin.py:142
#: admin.py:144
msgid "Request echo from selected members"
msgstr "Rückmeldungsaufforderung an ausgewählte Teilnehmer verschicken"
#: members/admin.py:159
#: admin.py:161
msgid "activity"
msgstr "Aktivität"
#: members/admin.py:188
#: admin.py:190
msgid "Successfully requested mail confirmation from selected registrations."
msgstr "Aufforderung zur Bestätigung der Email Adresse versendet."
#: members/admin.py:189
#: admin.py:191
msgid "Request mail confirmation from selected registrations"
msgstr "Aufforderung zur Bestätigung der Email Adresse versenden"
#: members/admin.py:196 members/admin.py:234
#: admin.py:198 admin.py:236
#, python-format
msgid "Successfully confirmed %(name)s."
msgstr "Registrierung von %(name)s erfolgreich bestätigt."
#: members/admin.py:200 members/admin.py:237
#: admin.py:202 admin.py:239
#, 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:205
#: admin.py:207
msgid "Successfully confirmed multiple registrations."
msgstr "Erfolgreich mehrere Registrierungen bestätigt."
#: members/admin.py:207
#: admin.py:209
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:208
#: admin.py:210
msgid "Confirm selected registrations"
msgstr "Ausgewählte Registrierungen bestätigen"
#: members/admin.py:228
#: admin.py:230
#, python-format
msgid "Successfully demoted %(name)s to waiter."
msgstr "%(name)s zurück auf die Warteliste gesetzt."
#: members/admin.py:229
#: admin.py:231
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."
#: admin.py:266 admin.py:322
msgid ""
"An error occurred while trying to invite said members. Please try again."
msgstr ""
"Beim Einladen dieser Personen ist ein Fehler aufgetreten. Bitte versuche es "
"nochmal. "
#: members/admin.py:279
#: admin.py:274 admin.py:329
#, python-format
msgid "Successfully invited %(name)s to %(group)s."
msgstr "Erfolgreich %(name)s zu Gruppe %(group)s eingeladen."
#: members/admin.py:281
#: admin.py:278 admin.py:334
msgid "Select group for invitation"
msgstr "Wähle Gruppe für Einladung aus"
#: admin.py:285
msgid "Offer waiter a place in a group."
msgstr "Personen auf der Warteliste einen Gruppenplatz anbieten."
#: members/admin.py:314
#: admin.py:373
msgid "Difficulty"
msgstr "Schwierigkeit"
#: members/admin.py:317 members/admin.py:320
#: admin.py:376 admin.py:379
msgid "Tour type"
msgstr "Art der Tour"
#: members/admin.py:618
#: admin.py:677
msgid "Convert to PDF"
msgstr "Kriseninterventionsliste erstellen"
#: members/admin.py:727
#: admin.py:786
msgid "Generate overview"
msgstr "Hinweise für Jugendleiter erstellen"
#: members/admin.py:824
#: admin.py:883
msgid "Generate list for LJP"
msgstr "LJP Liste erstellen"
#: members/apps.py:7 members/models.py:260
#: apps.py:7 models.py:260
msgid "members"
msgstr "Teilnehmer"
#: members/models.py:33
#: models.py:33
msgid "Name"
msgstr "Name"
#: members/models.py:34
#: models.py:34
msgid "Description"
msgstr "Beschreibung"
#: members/models.py:40 members/models.py:365 members/models.py:444
#: members/templates/members/change_member.html:17
#: models.py:40 models.py:375 models.py:454
#: templates/members/change_member.html:17
msgid "Activity"
msgstr "Aktivität"
#: members/models.py:41
#: models.py:41
msgid "Activities"
msgstr "Aktivitäten"
#: members/models.py:49
#: models.py:49
msgid "name"
msgstr "Name"
#: members/models.py:50
#: models.py:50
msgid "lowest year"
msgstr "Ab Jahrgang"
#: members/models.py:51
#: models.py:51
msgid "highest year"
msgstr "Bis Jahrgang"
#: members/models.py:52
#: models.py:52
msgid "youth leaders"
msgstr "Jugendleiter"
#: members/models.py:61 members/models.py:154
#: models.py:61 models.py:154
msgid "group"
msgstr "Gruppe"
#: members/models.py:62
#: models.py:62
msgid "groups"
msgstr "Gruppen"
#: members/models.py:74
#: models.py:74
msgid "prename"
msgstr "Vorname"
#: members/models.py:75
#: models.py:75
msgid "last name"
msgstr "Nachname"
#: members/models.py:78
#: models.py:78
msgid "Parents' Email"
msgstr "Email der Eltern"
#: members/models.py:79
#: models.py:79
msgid "Also send mails to parents"
msgstr "Emails auch an Eltern schicken"
#: members/models.py:81
#: models.py:81
msgid "birth date"
msgstr "Geburtsdatum"
#: members/models.py:83
#: models.py:83
msgid "comments"
msgstr "Kommentare"
#: members/models.py:85
#: models.py:85
msgid "Email confirmed"
msgstr "Emailadresse bestätigt"
#: members/models.py:86
#: models.py:86
msgid "Parents email confirmed"
msgstr "Emailadresse der Eltern bestätigt"
#: members/models.py:110 members/models.py:119
#: models.py:110 models.py:119
msgid "Email confirmation needed"
msgstr "Email Bestätigung erforderlich"
#: members/models.py:147
#: models.py:147
msgid "street and house number"
msgstr "Straße und Hausnummer"
#: members/models.py:148
#: models.py:148
msgid "Postcode"
msgstr "PLZ"
#: members/models.py:150
#: models.py:150
msgid "town"
msgstr "Stadt"
#: members/models.py:152
#: models.py:152
msgid "phone number"
msgstr "Telefonnummer"
#: members/models.py:153
#: models.py:153
msgid "parents phone number"
msgstr "Telefonnummer der Eltern"
#: members/models.py:156
#: models.py:156
msgid "receives newsletter"
msgstr "Erhält den Newsletter"
#: members/models.py:160
#: models.py:160
msgid "created"
msgstr "erstellt"
#: members/models.py:162
#: models.py:162
msgid "Active"
msgstr "Aktiv"
#: members/models.py:164
#: models.py:164
msgid "registration form"
msgstr "Anmeldeformular"
#: members/models.py:174
#: models.py:174
msgid "Echoed"
msgstr "Rückgemeldet"
#: members/models.py:175
#: models.py:175
msgid "Confirmed"
msgstr "Bestätigt"
#: members/models.py:256 members/models.py:526
#: models.py:256 models.py:536
msgid "Group"
msgstr "Gruppe"
#: members/models.py:259
#: models.py:259
msgid "member"
msgstr "Teilnehmer"
#: members/models.py:291
#: 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
#: models.py:309
msgid "Unconfirmed registration"
msgstr "Unbestätigte Registrierung"
#: members/models.py:310
#: models.py:310
msgid "Unconfirmed registrations"
msgstr "Unbestätigte Registrierungen"
#: members/models.py:321
#: models.py:321
msgid "Last wait confirmation"
msgstr "Letzte Wartebestätigung"
#: members/models.py:331
#: models.py:332
msgid "Invited for group"
msgstr "Einladung zu Gruppe austehend"
#: members/models.py:335
#: models.py:336
msgid "Waiter"
msgstr "Wartende Person"
#: members/models.py:336
#: models.py:337
msgid "Waiters"
msgstr "Warteliste"
#: members/models.py:367 members/models.py:446
#: models.py:377 models.py:456
msgid "Place"
msgstr "Ort"
#: members/models.py:368 members/models.py:447
#: models.py:378 models.py:457
msgid "Destination (optional)"
msgstr "Ziel (optional)"
#: members/models.py:370 members/models.py:449 members/models.py:504
#: members/models.py:522
#: models.py:380 models.py:459 models.py:514 models.py:532
msgid "Date"
msgstr "Datum"
#: members/models.py:371 members/models.py:450
#: models.py:381 models.py:460
msgid "End (optional)"
msgstr "Ende"
#: members/models.py:373 members/models.py:452
#: models.py:383 models.py:462
msgid "Groups"
msgstr "Gruppen"
#: members/models.py:381 members/models.py:465
#: models.py:391 models.py:475
msgid "Categories"
msgstr "Kategorien"
#: members/models.py:382 members/models.py:466
#: models.py:392 models.py:476
msgid "easy"
msgstr "leicht"
#: members/models.py:382 members/models.py:466
#: models.py:392 models.py:476
msgid "medium"
msgstr "mittel"
#: members/models.py:382 members/models.py:466
#: models.py:392 models.py:476
msgid "hard"
msgstr "schwer"
#: members/models.py:391
#: models.py:401
msgid "Memberlist"
msgstr "Teilnehmerliste"
#: members/models.py:392
#: models.py:402
msgid "Memberlists"
msgstr "Teilnehmerlisten"
#: members/models.py:410 members/models.py:418 members/models.py:426
#: members/models.py:437 members/models.py:557 members/models.py:564
#: models.py:420 models.py:428 models.py:436 models.py:447 models.py:567
#: models.py:574
msgid "Member"
msgstr "Teilnehmer"
#: members/models.py:412 members/models.py:431
#: models.py:422 models.py:441
msgid "Comment"
msgstr "Kommentar"
#: members/models.py:419 members/models.py:438 members/models.py:565
#: models.py:429 models.py:448 models.py:575
msgid "Members"
msgstr "Teilnehmer"
#: members/models.py:503
#: models.py:513
msgid "Title"
msgstr "Titel"
#: members/models.py:523
#: models.py:533
msgid "Location"
msgstr "Ort"
#: members/models.py:524
#: models.py:534
msgid "Topic"
msgstr "Thema"
#: members/models.py:548
#: models.py:558
msgid "Jugendleiter"
msgstr "Jugendleiter"
#: members/models.py:551
#: models.py:561
msgid "Klettertreff"
msgstr "Klettertreff"
#: members/models.py:552
#: models.py:562
msgid "Klettertreffs"
msgstr "Klettertreffs"
#: members/models.py:570
#: models.py:580
msgid "Password"
msgstr "Passwort"
#: members/models.py:573
#: models.py:583
msgid "registration password"
msgstr "Registrierungspassort"
#: members/models.py:574
#: models.py:584
msgid "registration passwords"
msgstr "Registrierungspasswörter"
#: members/templates/admin/klettertreff_overview.html:9
#: templates/admin/invite_for_group.html:17
#: templates/admin/invite_selected_for_group.html:17
msgid "Home"
msgstr "Start"
#: templates/admin/invite_for_group.html:21
msgid "Invite to group"
msgstr "Zu Gruppe einladen"
#: templates/admin/invite_for_group.html:26
#: templates/admin/invite_selected_for_group.html:25
msgid "Invite to a group"
msgstr "Zu einer Gruppe einladen"
#: templates/admin/invite_for_group.html:28
msgid "You are inviting:"
msgstr "Du lädst die folgende Person ein:"
#: templates/admin/invite_for_group.html:39
#, python-format
msgid "Please choose the group that you want to invite %(waiter)s to."
msgstr "Bitte wähle die Gruppe aus zu der du %(waiter)s einladen möchtest."
#: templates/admin/invite_for_group.html:51
#: templates/admin/invite_selected_for_group.html:52
msgid "Invite"
msgstr "Einladen"
#: templates/admin/invite_for_group.html:52
#: templates/admin/invite_selected_for_group.html:53
msgid "Cancel"
msgstr "Abbrechen"
#: templates/admin/invite_selected_for_group.html:20
msgid "Invite multiple waiters"
msgstr "Mehrere Wartende einladen"
#: templates/admin/invite_selected_for_group.html:27
msgid "You selected the following waiters:"
msgstr "Du hast die folgenden Wartenden ausgewählt:"
#: templates/admin/invite_selected_for_group.html:40
msgid "Please choose the group you want these waiters to be invited for."
msgstr ""
"Bitte wähle die Gruppe aus zu der du die obigen Wartenden einladen möchtest."
#: templates/admin/klettertreff_overview.html:9
msgid "date"
msgstr "Datum"
#: members/templates/members/change_member.html:6
#: templates/members/change_member.html:6
msgid "Participations:"
msgstr "Freizeitteilnahmen:"
#: members/templates/members/change_member.html:14
#: templates/members/change_member.html:14
msgid "Qualities:"
msgstr "Fähigkeiten:"
#: members/templates/members/change_member.html:18
#: templates/members/change_member.html:18
msgid "Skill level"
msgstr "Fähigkeitsniveau"
#: members/templates/members/change_member_unconfirmed.html:11
#: 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
#: templates/members/echo.html:6 templates/members/echo.html:13
#: templates/members/echo_failed.html:11 templates/members/echo_success.html:10
msgid "Echo"
msgstr "Rückmeldung"
#: members/templates/members/echo.html:15
#: templates/members/echo.html:15
msgid "Thanks for echoing back. Here is your current data:"
msgstr ""
"Vielen Dank, dass du dich rückmeldest. Hier siehst du deine aktuellen Daten. "
"Falls sich etwas geändert hat, trage das bitte hier ein."
#: members/templates/members/echo.html:27
#: members/templates/members/register.html:34
#: members/templates/members/register_password.html:22
#: members/templates/members/register_waiting_list.html:31
#: templates/members/echo.html:27 templates/members/register.html:34
#: templates/members/register_password.html:22
#: templates/members/register_waiting_list.html:31
msgid "submit"
msgstr "Bestätigen"
#: members/templates/members/echo_failed.html:6
#: templates/members/echo_failed.html:6
msgid "Echo failed"
msgstr "Rückmeldung fehlgeschlagen"
#: members/templates/members/echo_failed.html:13
#: members/templates/members/invited_registration_failed.html:13
#: templates/members/echo_failed.html:13
#: 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
#: templates/members/echo_failed.html:15
#: templates/members/invited_registration_failed.html:15
#: 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
#: templates/members/echo_failed.html:15
#: templates/members/invited_registration_failed.html:15
#: templates/members/register_failed.html:15
msgid "contact us."
msgstr "kontaktiere uns."
#: members/templates/members/echo_success.html:5
#: templates/members/echo_success.html:5
msgid "Echo successful"
msgstr "Rückmeldung erfolgreich"
#: members/templates/members/echo_success.html:12
#: templates/members/echo_success.html:12
msgid "Thank you"
msgstr "Danke"
#: members/templates/members/echo_success.html:12
#: templates/members/echo_success.html:12
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
#: templates/members/invited_registration_failed.html:6
#: 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
#: templates/members/invited_registration_failed.html:11
#: templates/members/register.html:6 templates/members/register_failed.html:11
#: templates/members/register_password.html:6
#: templates/members/register_success.html:6
#: 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
#: templates/members/mail_confirmation_invalid.html:6
#: templates/members/mail_confirmation_invalid.html:11
msgid "Mail confirmation failed"
msgstr "Emailbestätigung fehlgeschlagen"
#: members/templates/members/mail_confirmation_invalid.html:13
#: 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
#: templates/members/mail_confirmation_success.html:6
#: templates/members/mail_confirmation_success.html:11
msgid "Mail confirmed"
msgstr "Emailadresse bestätigt"
#: members/templates/members/mail_confirmation_success.html:14
#: templates/members/mail_confirmation_success.html:14
#, python-format
msgid ""
"The email address %(email)s was successfully confirmed as parents email of "
@ -492,7 +540,7 @@ msgstr ""
"Die Emailadresse %(email)s wurde erfolgreich als Emailadresse der Eltern von "
"%(name)s bestätigt."
#: members/templates/members/mail_confirmation_success.html:17
#: templates/members/mail_confirmation_success.html:17
#, python-format
msgid ""
"The email address %(email)s was successfully confirmed as personal email of "
@ -501,23 +549,23 @@ msgstr ""
"Die Emailadresse %(email)s wurde erfolgreich als persönliche Emailadresse "
"von %(name)s bestätigt."
#: 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
#: templates/members/register.html:13
#: templates/members/register_password.html:11
#: templates/members/register_success.html:11
#: templates/members/register_wrong_password.html:11
msgid "Register"
msgstr "Registrieren"
#: members/templates/members/register.html:15
#: 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.html:28
#: templates/members/register.html:28
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
#: templates/members/register.html:30
#: templates/members/register_waiting_list.html:28
msgid ""
"I agree that my data is stored and processed on the server of the JDAV "
"Ludwigsburg."
@ -525,11 +573,11 @@ msgstr ""
"Ich bin einverstanden, dass meine Daten auf dem Server der JDAV Ludwigsburg "
"gespeichert und verarbeitet werden."
#: members/templates/members/register_failed.html:13
#: 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
#: templates/members/register_password.html:13
msgid ""
"Thanks for your interest in participating. Please enter the registration "
"password, your youth leader gave you."
@ -537,15 +585,15 @@ 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
#: templates/members/register_success.html:13
msgid "Your registration succeeded."
msgstr "Deine Registrierung war erfolgreich."
#: members/templates/members/register_success.html:16
#: 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
#: templates/members/register_success.html:17
msgid ""
"The coordinating team will process your registration when your email address "
"is confirmed."
@ -553,63 +601,68 @@ msgstr ""
"Unser Jugendleiterteam wird deine Registrierung bearbeiten, wenn deine "
"Emailadressen bestätigt sind."
#: members/templates/members/register_success.html:19
#: 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
#: 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
#: 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
#: 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
#: templates/members/register_waiting_list_success.html:6
#: 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
#: 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
#: 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
#: 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
#: 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:83 members/views.py:104 members/views.py:268
#: views.py:83 views.py:104 views.py:268
msgid "invalid"
msgstr "ungültig"
#: members/views.py:85 members/views.py:270
#: views.py:85 views.py:270
msgid "expired"
msgstr "abgelaufen"
#: members/views.py:114
#: views.py:114
msgid "The entered password is wrong."
msgstr "Das eingegebene Passwort ist falsch."
#, 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."
#~ msgid "Successfully asked for registration from selected waiting persons."
#~ msgstr ""
#~ "Erfolgreich Einladung zur Registrierung an die ausgewählten Wartenden "

@ -11,7 +11,7 @@ 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,\
prepend_base_url
prepend_base_url, get_registration_link
from django.contrib.auth.models import User
from dateutil.relativedelta import relativedelta
@ -327,6 +327,7 @@ class MemberWaitingList(Person):
invited_for_group = models.ForeignKey(Group,
null=True,
blank=True,
default=None,
verbose_name=_('Invited for group'),
on_delete=models.SET_NULL)
@ -356,6 +357,15 @@ class MemberWaitingList(Person):
def may_register(self, key):
return self.registration_key == key and timezone.now() < self.registration_expire
def invite_to_group(self):
send_mail("Gute Neuigkeiten von der JDAV",
INVITE_TEXT.format(name=self.prename,
link=get_registration_link(self)),
mail_root,
[self.email, self.email_parents] if self.email_parents and self.cc_email_parents
else self.email)
class MemberList(models.Model):
"""Lets the user create a list of members in pdf format.
@ -684,3 +694,19 @@ der Registrierung kommst du hier:
Viele Grüße
Dein KOMPASS"""
INVITE_TEXT = """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"""

@ -0,0 +1,56 @@
{% extends "admin/base_site.html" %}
{% load i18n admin_urls static %}
{% block extrahead %}
{{ block.super }}
{{ media }}
<script src="{% static 'admin/js/cancel.js' %}" async></script>
<script type="text/javascript" src="{% static "admin/js/vendor/jquery/jquery.js" %}"></script>
<script type="text/javascript" src="{% static "admin/js/jquery.init.js" %}"></script>
{% endblock %}
{% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} invite-waiter
{% endblock %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">{% translate 'Home' %}</a>
&rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a>
&rsaquo; <a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a>
&rsaquo; <a href="{% url opts|admin_urlname:'change' object.pk|admin_urlquote %}">{{ object|truncatewords:"18" }}</a>
&rsaquo; {% translate 'Invite to group' %}
</div>
{% endblock %}
{% block content %}
<h2>{% translate "Invite to a group" %}</h2>
<p>
{% trans "You are inviting:" %}
</p>
<p>
<ul>
<li>
<a href="{% url 'admin:members_memberwaitinglist_change' waiter.id %}">{{ waiter }}</a>
</li>
</ul>
</p>
<p>
{% blocktrans %}Please choose the group that you want to invite {{ waiter }} to.{% endblocktrans %}
</p>
<form action="" method="post">
{% csrf_token %}
<p>
{{form}}
</p>
<br>
<div>
<p>
<input type="hidden" name="action" value="ask_for_registration">
<input class="default" style="color: $default-link-color" type="submit" name="apply" value="{% translate 'Invite' %}">
<a href="#" class="button cancel-link">{% translate "Cancel" %}</a>
</p>
</div>
</form>
{% endblock %}

@ -0,0 +1,57 @@
{% extends "admin/base_site.html" %}
{% load i18n admin_urls static %}
{% block extrahead %}
{{ block.super }}
{{ media }}
<script src="{% static 'admin/js/cancel.js' %}" async></script>
<script type="text/javascript" src="{% static "admin/js/vendor/jquery/jquery.js" %}"></script>
<script type="text/javascript" src="{% static "admin/js/jquery.init.js" %}"></script>
{% endblock %}
{% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} invite-waiter
{% endblock %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">{% translate 'Home' %}</a>
&rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a>
&rsaquo; <a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a>
&rsaquo; {% translate 'Invite multiple waiters' %}
</div>
{% endblock %}
{% block content %}
<h2>{% translate "Invite to a group" %}</h2>
<p>
{% trans "You selected the following waiters:" %}
</p>
<p>
{% for waiter in waiters %}
<ul>
<li>
<a href="{% url 'admin:members_memberwaitinglist_change' waiter.id %}">{{ waiter }}</a>
</li>
</ul>
{% endfor %}
</p>
<p>
{% trans "Please choose the group you want these waiters to be invited for." %}
</p>
<form action="" method="post">
{% csrf_token %}
<p>
{{form}}
</p>
<br>
<div>
<p>
<input type="hidden" name="action" value="ask_for_registration">
<input class="default" style="color: $default-link-color" type="submit" name="apply" value="{% translate 'Invite' %}">
<a href="#" class="button cancel-link">{% translate "Cancel" %}</a>
</p>
</div>
</form>
{% endblock %}

@ -170,4 +170,5 @@ body {
@import "relatedpopup";
@import "dashboard";
@import "delete-confirmation";
@import "invite-waiter";
@import "login";

@ -0,0 +1,78 @@
@import "globals";
.invite-waiter {
#content > ul, #content > h1 + p + ul {
background: $content-background-color;
border-radius: 4px;
box-shadow: 0 2px 0 0 $content-border2-color;
&, ul {
list-style-type: none;
margin: 0;
padding: 0;
li {
list-style: disc;
line-height: 1.8;
}
}
ul {
margin-left: 20px;
}
> li {
padding: 8px;
border-bottom: 1px solid $content-border-color;
font-size: 13px;
list-style: none;
&:last-child {
border-bottom: 0;
}
}
}
#content form {
margin-top: 20px;
input[type="submit"] {
background-color: $primary-button-background-color;
color: $primary-button-text-color;
font-size: 12px;
font-weight: lighter;
padding: 0 20px;
text-transform: uppercase;
vertical-align: middle;
margin-bottom: 5px;
@include for-mobile {
display: block;
width: 100%;
}
&:hover, &:focus {
background-color: $button-hover-background-color;
color: $button-hover-text-color;
}
&:active {
background-color: $button-active-background-color;
color: $button-active-text-color;
}
}
.button {
vertical-align: middle;
margin-left: 10px;
margin-bottom: 5px;
box-sizing: border-box;
@include for-mobile {
margin-left: 0;
display: block;
width: 100%;
}
}
}
}

@ -8331,7 +8331,7 @@ ul.actionlist li {
.dashboard-container.columns_2 .dashboard-column-wrapper {
width: 100%; } }
.dashboard-container.columns_3 .dashboard-column-wrapper {
width: 33.33333%; }
width: 33.3333333333%; }
@media only screen and (max-width: 960px) {
.dashboard-container.columns_3 .dashboard-column-wrapper {
width: 100%; } }
@ -9263,6 +9263,365 @@ ul.actionlist li {
.fill_width {
width: 100% !important; }
@keyframes spin {
100% {
transform: rotate(360deg); } }
.invite-waiter #content > ul, .invite-waiter #content > h1 + p + ul {
background: #fff;
border-radius: 4px;
box-shadow: 0 2px 0 0 #cceae4; }
.invite-waiter #content > ul, .invite-waiter #content > ul ul, .invite-waiter #content > h1 + p + ul, .invite-waiter #content > h1 + p + ul ul {
list-style-type: none;
margin: 0;
padding: 0; }
.invite-waiter #content > ul li, .invite-waiter #content > ul ul li, .invite-waiter #content > h1 + p + ul li, .invite-waiter #content > h1 + p + ul ul li {
list-style: disc;
line-height: 1.8; }
.invite-waiter #content > ul ul, .invite-waiter #content > h1 + p + ul ul {
margin-left: 20px; }
.invite-waiter #content > ul > li, .invite-waiter #content > h1 + p + ul > li {
padding: 8px;
border-bottom: 1px solid #f5f3f4;
font-size: 13px;
list-style: none; }
.invite-waiter #content > ul > li:last-child, .invite-waiter #content > h1 + p + ul > li:last-child {
border-bottom: 0; }
.invite-waiter #content form {
margin-top: 20px; }
.invite-waiter #content form input[type="submit"] {
background-color: #44b78b;
color: #fff;
font-size: 12px;
font-weight: lighter;
padding: 0 20px;
text-transform: uppercase;
vertical-align: middle;
margin-bottom: 5px; }
@media only screen and (max-width: 960px) {
.invite-waiter #content form input[type="submit"] {
display: block;
width: 100%; } }
.invite-waiter #content form input[type="submit"]:hover, .invite-waiter #content form input[type="submit"]:focus {
background-color: #7fb1dc;
color: #fff; }
.invite-waiter #content form input[type="submit"]:active {
background-color: #4f8580;
color: #fff; }
.invite-waiter #content form .button {
vertical-align: middle;
margin-left: 10px;
margin-bottom: 5px;
box-sizing: border-box; }
@media only screen and (max-width: 960px) {
.invite-waiter #content form .button {
margin-left: 0;
display: block;
width: 100%; } }
/*
* Default variable values
* Create separate themes/theme/_variables.scss to override these variables
*/
/*
* General
*/
/*
* Sidebar
*/
/*
* Top
*/
/*
* Content
*/
/*
* Buttons
*/
/*
* Inputs
*/
/*
* Messages
*/
/*
* Login
*/
/*
* jQuery UI
*/
/*
* Charts
*/
.hidden {
display: none; }
.clear-list, .dashboard-item-content ul:not(.inline), .dashboard-item-content ul.inline {
margin: 0;
padding: 0;
list-style: none; }
.fl {
float: left; }
.fr {
float: right; }
.cf:before, .cf:after {
content: "";
display: table; }
.cf:after {
clear: both; }
.p10 {
padding: 10px; }
.p20 {
padding: 20px; }
.p30 {
padding: 30px; }
.p40 {
padding: 40px; }
.p50 {
padding: 50px; }
.p60 {
padding: 60px; }
.p70 {
padding: 70px; }
.p80 {
padding: 80px; }
.pt10 {
padding-top: 10px; }
.pt20 {
padding-top: 20px; }
.pt30 {
padding-top: 30px; }
.pt40 {
padding-top: 40px; }
.pt50 {
padding-top: 50px; }
.pt60 {
padding-top: 60px; }
.pt70 {
padding-top: 70px; }
.pt80 {
padding-top: 80px; }
.pr10 {
padding-right: 10px; }
.pr20 {
padding-right: 20px; }
.pr30 {
padding-right: 30px; }
.pr40 {
padding-right: 40px; }
.pr50 {
padding-right: 50px; }
.pr60 {
padding-right: 60px; }
.pr70 {
padding-right: 70px; }
.pr80 {
padding-right: 80px; }
.pb10 {
padding-bottom: 10px; }
.pb20 {
padding-bottom: 20px; }
.pb30 {
padding-bottom: 30px; }
.pb40 {
padding-bottom: 40px; }
.pb50 {
padding-bottom: 50px; }
.pb60 {
padding-bottom: 60px; }
.pb70 {
padding-bottom: 70px; }
.pb80 {
padding-bottom: 80px; }
.pl10 {
padding-left: 10px; }
.pl20 {
padding-left: 20px; }
.pl30 {
padding-left: 30px; }
.pl40 {
padding-left: 40px; }
.pl50 {
padding-left: 50px; }
.pl60 {
padding-left: 60px; }
.pl70 {
padding-left: 70px; }
.pl80 {
padding-left: 80px; }
.m10 {
margin: 10px; }
.m20 {
margin: 20px; }
.m30 {
margin: 30px; }
.m40 {
margin: 40px; }
.m50 {
margin: 50px; }
.m60 {
margin: 60px; }
.m70 {
margin: 70px; }
.m80 {
margin: 80px; }
.mt10 {
margin-top: 10px; }
.mt20 {
margin-top: 20px; }
.mt30 {
margin-top: 30px; }
.mt40 {
margin-top: 40px; }
.mt50 {
margin-top: 50px; }
.mt60 {
margin-top: 60px; }
.mt70 {
margin-top: 70px; }
.mt80 {
margin-top: 80px; }
.mr10 {
margin-right: 10px; }
.mr20 {
margin-right: 20px; }
.mr30 {
margin-right: 30px; }
.mr40 {
margin-right: 40px; }
.mr50 {
margin-right: 50px; }
.mr60 {
margin-right: 60px; }
.mr70 {
margin-right: 70px; }
.mr80 {
margin-right: 80px; }
.mb10 {
margin-bottom: 10px; }
.mb20 {
margin-bottom: 20px; }
.mb30 {
margin-bottom: 30px; }
.mb40 {
margin-bottom: 40px; }
.mb50 {
margin-bottom: 50px; }
.mb60 {
margin-bottom: 60px; }
.mb70 {
margin-bottom: 70px; }
.mb80 {
margin-bottom: 80px; }
.ml10 {
margin-left: 10px; }
.ml20 {
margin-left: 20px; }
.ml30 {
margin-left: 30px; }
.ml40 {
margin-left: 40px; }
.ml50 {
margin-left: 50px; }
.ml60 {
margin-left: 60px; }
.ml70 {
margin-left: 70px; }
.ml80 {
margin-left: 80px; }
.pos_rel {
position: relative; }
.pos_abs {
position: absolute; }
.fill_width {
width: 100% !important; }
@keyframes spin {
100% {
transform: rotate(360deg); } }

File diff suppressed because one or more lines are too long

@ -0,0 +1,13 @@
{% extends "admin/change_form_object_tools.html" %}
{% load i18n admin_urls %}
{% block object-tools-items %}
<li>
{% url opts|admin_urlname:'invite' original.pk|admin_urlquote as invite_url %}
<a class="historylink" href="{% add_preserved_filters invite_url %}">{% trans 'Invite to group' %}</a>
</li>
{{block.super}}
{% endblock %}

@ -0,0 +1,13 @@
{% extends "admin/submit_line.html" %}
{% load i18n admin_urls %}
{% block submit-row %}
{{block.super}}
<p class="deletelink-box">
{% url opts|admin_urlname:'invite' original.pk|admin_urlquote as invite_url %}
<a class="button" style="" href="{% add_preserved_filters invite_url %}">{% trans 'Invite to group' %}</a>
</p>
{% endblock %}
Loading…
Cancel
Save