Merge branch 'group-leiter-can-confirm-registrations'

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

@ -87,9 +87,18 @@ class MemberAdmin(admin.ModelAdmin):
#ordering = ('activity_score',) #ordering = ('activity_score',)
actions = ['send_mail_to', 'request_echo'] actions = ['send_mail_to', 'request_echo']
def get_fields(self, request, obj=None):
if request.user.has_perm('members.may_set_auth_user'):
if 'user' not in self.fields:
self.fields.append('user')
else:
if 'user' in self.fields:
self.fields.remove('user')
return super(MemberAdmin, self).get_fields(request, obj)
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.filter(confirmed=True)) return annotate_activity_score(queryset)
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 {}
@ -167,7 +176,13 @@ class MemberUnconfirmedAdmin(admin.ModelAdmin):
def get_queryset(self, request): def get_queryset(self, request):
queryset = super().get_queryset(request) queryset = super().get_queryset(request)
return queryset.filter(confirmed=False) if request.user.has_perm('members.may_manage_all_registrations'):
return queryset
if request.user.member is None:
return MemberUnconfirmedProxy.objects.none()
groups = request.user.member.leited_groups.all()
# this is magic (the first part, group is a manytomanyfield) but seems to work
return queryset.filter(group__in=groups).distinct()
def request_mail_confirmation(self, request, queryset): def request_mail_confirmation(self, request, queryset):
for member in queryset: for member in queryset:
@ -209,8 +224,20 @@ class RegistrationPasswordInline(admin.TabularInline):
extra = 0 extra = 0
class GroupAdminForm(forms.ModelForm):
class Meta:
model = Freizeit
exclude = ['add_member']
def __init__(self, *args, **kwargs):
super(GroupAdminForm, self).__init__(*args, **kwargs)
self.fields['leiters'].queryset = Member.objects.filter(group__name='Jugendleiter')
class GroupAdmin(admin.ModelAdmin): class GroupAdmin(admin.ModelAdmin):
fields = ['name', 'year_from', 'year_to'] fields = ['name', 'year_from', 'year_to', 'leiters']
form = GroupAdminForm
list_display = ('name', 'year_from', 'year_to') list_display = ('name', 'year_from', 'year_to')
inlines = [RegistrationPasswordInline] inlines = [RegistrationPasswordInline]

@ -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-03 21:38+0200\n" "POT-Creation-Date: 2022-10-03 23:57+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:80 #: members/admin.py:33 members/models.py:88
msgid "Registration complete" msgid "Registration complete"
msgstr "Anmeldung vollständig" msgstr "Anmeldung vollständig"
@ -34,122 +34,126 @@ msgstr "Nein"
msgid "All" msgid "All"
msgstr "Alle" msgstr "Alle"
#: members/admin.py:108 #: members/admin.py:117
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:133 #: members/admin.py:142
msgid "Successfully requested echo from selected members." msgid "Successfully requested echo from selected members."
msgstr "" msgstr ""
"Rückmeldungsaufforderung erfolgreich an ausgewählte Teilnehmer verschickt." "Rückmeldungsaufforderung erfolgreich an ausgewählte Teilnehmer verschickt."
#: members/admin.py:134 #: members/admin.py:143
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:151 #: members/admin.py:160
msgid "activity" msgid "activity"
msgstr "Aktivität" msgstr "Aktivität"
#: members/admin.py:175 #: members/admin.py:190
msgid "Successfully requested mail confirmation from selected registrations." msgid "Successfully requested mail confirmation from selected registrations."
msgstr "Aufforderung zur Bestätigung der Email Adresse versendet" msgstr "Aufforderung zur Bestätigung der Email Adresse versendet"
#: members/admin.py:176 #: members/admin.py:191
msgid "Request mail confirmation from selected registrations" msgid "Request mail confirmation from selected registrations"
msgstr "Aufforderung zur Bestätigung der Email Adresse versenden" msgstr "Aufforderung zur Bestätigung der Email Adresse versenden"
#: members/admin.py:183 members/admin.py:200 #: members/admin.py:198 members/admin.py:215
#, python-format #, python-format
msgid "Successfully confirmed %(name)s." msgid "Successfully confirmed %(name)s."
msgstr "Registrierung von %(name)s erfolgreich bestätigt." msgstr "Registrierung von %(name)s erfolgreich bestätigt."
#: members/admin.py:187 members/admin.py:203 #: members/admin.py:202 members/admin.py:218
#, python-format #, python-format
msgid "Can't confirm. %(name)s has unconfirmed email addresses." msgid "Can't confirm. %(name)s has unconfirmed email addresses."
msgstr "Bestätigung nicht möglich. %(name)s hat unbestätigte Emailadressen." msgstr "Bestätigung nicht möglich. %(name)s hat unbestätigte Emailadressen."
#: members/admin.py:192 #: members/admin.py:207
msgid "Successfully confirmed multiple registrations." msgid "Successfully confirmed multiple registrations."
msgstr "Erfolgreich mehrere Registrierungen bestätigt." msgstr "Erfolgreich mehrere Registrierungen bestätigt."
#: members/admin.py:194 #: members/admin.py:209
msgid "" msgid ""
"Failed to confirm some registrations because of unconfirmed email addresses." "Failed to confirm some registrations because of unconfirmed email addresses."
msgstr "" msgstr ""
"Einige Bestätigungen fehlgeschlagen, weil Emailadressen noch nicht bestätigt " "Einige Bestätigungen fehlgeschlagen, weil Emailadressen noch nicht bestätigt "
"sind." "sind."
#: members/admin.py:195 #: members/admin.py:210
msgid "Confirm selected registrations" msgid "Confirm selected registrations"
msgstr "Ausgewählte Registrierungen bestätigen" msgstr "Ausgewählte Registrierungen bestätigen"
#: members/admin.py:225 #: members/admin.py:252
msgid "Difficulty" msgid "Difficulty"
msgstr "Schwierigkeit" msgstr "Schwierigkeit"
#: members/admin.py:228 members/admin.py:231 #: members/admin.py:255 members/admin.py:258
msgid "Tour type" msgid "Tour type"
msgstr "Art der Tour" msgstr "Art der Tour"
#: members/admin.py:529 #: members/admin.py:556
msgid "Convert to PDF" msgid "Convert to PDF"
msgstr "Kriseninterventionsliste erstellen" msgstr "Kriseninterventionsliste erstellen"
#: members/admin.py:638 #: members/admin.py:665
msgid "Generate overview" msgid "Generate overview"
msgstr "Hinweise für Jugendleiter erstellen" msgstr "Hinweise für Jugendleiter erstellen"
#: members/admin.py:735 #: members/admin.py:762
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:229 #: members/apps.py:7 members/models.py:240
msgid "members" msgid "members"
msgstr "Teilnehmer" msgstr "Teilnehmer"
#: members/models.py:26 #: members/models.py:27
msgid "Name" msgid "Name"
msgstr "Name" msgstr "Name"
#: members/models.py:27 #: members/models.py:28
msgid "Description" msgid "Description"
msgstr "Beschreibung" msgstr "Beschreibung"
#: members/models.py:33 members/models.py:266 members/models.py:345 #: members/models.py:34 members/models.py:285 members/models.py:364
#: 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:34 #: members/models.py:35
msgid "Activities" msgid "Activities"
msgstr "Aktivitäten" msgstr "Aktivitäten"
#: members/models.py:42 #: members/models.py:43
msgid "name" msgid "name"
msgstr "Name" msgstr "Name"
#: members/models.py:43 #: members/models.py:44
msgid "lowest year" msgid "lowest year"
msgstr "Ab Jahrgang" msgstr "Ab Jahrgang"
#: members/models.py:44 #: members/models.py:45
msgid "highest year" msgid "highest year"
msgstr "Bis Jahrgang" msgstr "Bis Jahrgang"
#: members/models.py:51 members/models.py:73 #: members/models.py:46
msgid "youth leaders"
msgstr "Jugendleiter"
#: members/models.py:54 members/models.py:81
msgid "group" msgid "group"
msgstr "Gruppe" msgstr "Gruppe"
#: members/models.py:52 #: members/models.py:55
msgid "groups" msgid "groups"
msgstr "Gruppen" msgstr "Gruppen"
#: members/models.py:60 #: members/models.py:68
msgid "prename" msgid "prename"
msgstr "Vorname" msgstr "Vorname"
#: members/models.py:61 #: members/models.py:69
msgid "last name" msgid "last name"
msgstr "Nachname" msgstr "Nachname"
@ -157,185 +161,185 @@ msgstr "Nachname"
msgid "street and house number" msgid "street and house number"
msgstr "Straße und Hausnummer" msgstr "Straße und Hausnummer"
#: members/models.py:63 #: members/models.py:71
msgid "Postcode" msgid "Postcode"
msgstr "PLZ" msgstr "PLZ"
#: members/models.py:65 #: members/models.py:73
msgid "town" msgid "town"
msgstr "Stadt" msgstr "Stadt"
#: members/models.py:66 #: members/models.py:74
msgid "phone number" msgid "phone number"
msgstr "Telefonnummer" msgstr "Telefonnummer"
#: members/models.py:67 #: members/models.py:75
msgid "parents phone number" msgid "parents phone number"
msgstr "Telefonnummer der Eltern" msgstr "Telefonnummer der Eltern"
#: members/models.py:70 #: members/models.py:78
msgid "Parents' Email" msgid "Parents' Email"
msgstr "Email der Eltern" msgstr "Email der Eltern"
#: members/models.py:71 #: members/models.py:79
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:72 #: members/models.py:80
msgid "birth date" msgid "birth date"
msgstr "Geburtsdatum" msgstr "Geburtsdatum"
#: members/models.py:74 #: members/models.py:82
msgid "receives newsletter" msgid "receives newsletter"
msgstr "Erhält den Newsletter" msgstr "Erhält den Newsletter"
#: members/models.py:78 #: members/models.py:86
msgid "comments" msgid "comments"
msgstr "Kommentare" msgstr "Kommentare"
#: members/models.py:79 #: members/models.py:87
msgid "created" msgid "created"
msgstr "erstellt" msgstr "erstellt"
#: members/models.py:81 #: members/models.py:89
msgid "Active" msgid "Active"
msgstr "Aktiv" msgstr "Aktiv"
#: members/models.py:82 #: members/models.py:90
msgid "Not waiting" msgid "Not waiting"
msgstr "NICHT Warteliste" msgstr "NICHT Warteliste"
#: members/models.py:83 #: members/models.py:91
msgid "registration form" msgid "registration form"
msgstr "Anmeldeformular" msgstr "Anmeldeformular"
#: members/models.py:93 #: members/models.py:101
msgid "Echoed" msgid "Echoed"
msgstr "Rückgemeldet" msgstr "Rückgemeldet"
#: members/models.py:94 #: members/models.py:102
msgid "Confirmed" msgid "Confirmed"
msgstr "Bestätigt" msgstr "Bestätigt"
#: members/models.py:95 #: members/models.py:103
msgid "Email confirmed" msgid "Email confirmed"
msgstr "Emailadresse bestätigt" msgstr "Emailadresse bestätigt"
#: members/models.py:96 #: members/models.py:104
msgid "Parents email confirmed" msgid "Parents email confirmed"
msgstr "Emailadresse der Eltern bestätigt" msgstr "Emailadresse der Eltern bestätigt"
#: members/models.py:126 members/models.py:136 #: members/models.py:137 members/models.py:147
msgid "Email confirmation" msgid "Email confirmation"
msgstr "Email Bestätigung" msgstr "Email Bestätigung"
#: members/models.py:225 members/models.py:427 #: members/models.py:236 members/models.py:446
msgid "Group" msgid "Group"
msgstr "Gruppe" msgstr "Gruppe"
#: members/models.py:228 #: members/models.py:239
msgid "member" msgid "member"
msgstr "Teilnehmer" msgstr "Teilnehmer"
#: members/models.py:252 #: members/models.py:270
msgid "Unconfirmed registration" msgid "Unconfirmed registration"
msgstr "Unbestätigte Registrierung" msgstr "Unbestätigte Registrierung"
#: members/models.py:253 #: members/models.py:271
msgid "Unconfirmed registrations" msgid "Unconfirmed registrations"
msgstr "Unbestätigte Registrierungen" msgstr "Unbestätigte Registrierungen"
#: members/models.py:268 members/models.py:347 #: members/models.py:287 members/models.py:366
msgid "Place" msgid "Place"
msgstr "Ort" msgstr "Ort"
#: members/models.py:269 members/models.py:348 #: members/models.py:288 members/models.py:367
msgid "Destination (optional)" msgid "Destination (optional)"
msgstr "Ziel (optional)" msgstr "Ziel (optional)"
#: members/models.py:271 members/models.py:350 members/models.py:405 #: members/models.py:290 members/models.py:369 members/models.py:424
#: members/models.py:423 #: members/models.py:442
msgid "Date" msgid "Date"
msgstr "Datum" msgstr "Datum"
#: members/models.py:272 members/models.py:351 #: members/models.py:291 members/models.py:370
msgid "End (optional)" msgid "End (optional)"
msgstr "Ende" msgstr "Ende"
#: members/models.py:274 members/models.py:353 #: members/models.py:293 members/models.py:372
msgid "Groups" msgid "Groups"
msgstr "Gruppen" msgstr "Gruppen"
#: members/models.py:282 members/models.py:366 #: members/models.py:301 members/models.py:385
msgid "Categories" msgid "Categories"
msgstr "Kategorien" msgstr "Kategorien"
#: members/models.py:283 members/models.py:367 #: members/models.py:302 members/models.py:386
msgid "easy" msgid "easy"
msgstr "leicht" msgstr "leicht"
#: members/models.py:283 members/models.py:367 #: members/models.py:302 members/models.py:386
msgid "medium" msgid "medium"
msgstr "mittel" msgstr "mittel"
#: members/models.py:283 members/models.py:367 #: members/models.py:302 members/models.py:386
msgid "hard" msgid "hard"
msgstr "schwer" msgstr "schwer"
#: members/models.py:292 #: members/models.py:311
msgid "Memberlist" msgid "Memberlist"
msgstr "Teilnehmerliste" msgstr "Teilnehmerliste"
#: members/models.py:293 #: members/models.py:312
msgid "Memberlists" msgid "Memberlists"
msgstr "Teilnehmerlisten" msgstr "Teilnehmerlisten"
#: members/models.py:311 members/models.py:319 members/models.py:327 #: members/models.py:330 members/models.py:338 members/models.py:346
#: members/models.py:338 members/models.py:458 members/models.py:465 #: members/models.py:357 members/models.py:477 members/models.py:484
msgid "Member" msgid "Member"
msgstr "Teilnehmer" msgstr "Teilnehmer"
#: members/models.py:313 members/models.py:332 #: members/models.py:332 members/models.py:351
msgid "Comment" msgid "Comment"
msgstr "Kommentar" msgstr "Kommentar"
#: members/models.py:320 members/models.py:339 members/models.py:466 #: members/models.py:339 members/models.py:358 members/models.py:485
msgid "Members" msgid "Members"
msgstr "Teilnehmer" msgstr "Teilnehmer"
#: members/models.py:404 #: members/models.py:423
msgid "Title" msgid "Title"
msgstr "Titel" msgstr "Titel"
#: members/models.py:424 #: members/models.py:443
msgid "Location" msgid "Location"
msgstr "Ort" msgstr "Ort"
#: members/models.py:425 #: members/models.py:444
msgid "Topic" msgid "Topic"
msgstr "Thema" msgstr "Thema"
#: members/models.py:449 #: members/models.py:468
msgid "Jugendleiter" msgid "Jugendleiter"
msgstr "Jugendleiter" msgstr "Jugendleiter"
#: members/models.py:452 #: members/models.py:471
msgid "Klettertreff" msgid "Klettertreff"
msgstr "Klettertreff" msgstr "Klettertreff"
#: members/models.py:453 #: members/models.py:472
msgid "Klettertreffs" msgid "Klettertreffs"
msgstr "Klettertreffs" msgstr "Klettertreffs"
#: members/models.py:471 #: members/models.py:490
msgid "Password" msgid "Password"
msgstr "Passwort" msgstr "Passwort"
#: members/models.py:474 #: members/models.py:493
msgid "registration password" msgid "registration password"
msgstr "Registrierungspassort" msgstr "Registrierungspassort"
#: members/models.py:475 #: members/models.py:494
msgid "registration passwords" msgid "registration passwords"
msgstr "Registrierungspasswörter" msgstr "Registrierungspasswörter"

@ -11,6 +11,7 @@ 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 mailer.mailutils import send as send_mail, mail_root, get_mail_confirmation_link
from django.contrib.auth.models import User
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
@ -42,6 +43,8 @@ class Group(models.Model):
name = models.CharField(max_length=20, verbose_name=_('name')) # e.g: J1 name = models.CharField(max_length=20, verbose_name=_('name')) # e.g: J1
year_from = models.IntegerField(verbose_name=_('lowest year'), default=2010) year_from = models.IntegerField(verbose_name=_('lowest year'), default=2010)
year_to = models.IntegerField(verbose_name=_('highest year'), default=2011) year_to = models.IntegerField(verbose_name=_('highest year'), default=2011)
leiters = models.ManyToManyField('members.Member', verbose_name=_('youth leaders'),
related_name='leited_groups', blank=True)
def __str__(self): def __str__(self):
"""String representation""" """String representation"""
@ -52,6 +55,11 @@ class Group(models.Model):
verbose_name_plural = _('groups') verbose_name_plural = _('groups')
class MemberManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(confirmed=True)
class Member(models.Model): class Member(models.Model):
""" """
Represents a member of the association Represents a member of the association
@ -96,6 +104,9 @@ class Member(models.Model):
confirmed_mail_parents = models.BooleanField(default=True, verbose_name=_('Parents 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_key = models.CharField(max_length=32, default="")
confirm_mail_parents_key = models.CharField(max_length=32, default="") confirm_mail_parents_key = models.CharField(max_length=32, default="")
user = models.OneToOneField(User, blank=True, null=True, on_delete=models.SET_NULL)
objects = MemberManager()
def __str__(self): def __str__(self):
"""String representation""" """String representation"""
@ -227,7 +238,8 @@ class Member(models.Model):
class Meta: class Meta:
verbose_name = _('member') verbose_name = _('member')
verbose_name_plural = _('members') verbose_name_plural = _('members')
permissions = (('may_see_qualities', 'Is allowed to see the quality overview'),) permissions = (('may_see_qualities', 'Is allowed to see the quality overview'),
('may_set_auth_user', 'Is allowed to set auth user member connections.'))
def get_skills(self): def get_skills(self):
# get skills by summing up all the activities taken part in # get skills by summing up all the activities taken part in
@ -244,13 +256,20 @@ class Member(models.Model):
return Freizeit.objects.filter(membersonlist__member=self) return Freizeit.objects.filter(membersonlist__member=self)
class MemberUnconfirmedManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(confirmed=False)
class MemberUnconfirmedProxy(Member): class MemberUnconfirmedProxy(Member):
"""Proxy to show unconfirmed members seperately in admin""" """Proxy to show unconfirmed members seperately in admin"""
objects = MemberUnconfirmedManager()
class Meta: class Meta:
proxy = True proxy = True
verbose_name = _('Unconfirmed registration') verbose_name = _('Unconfirmed registration')
verbose_name_plural = _('Unconfirmed registrations') verbose_name_plural = _('Unconfirmed registrations')
permissions = (('may_manage_all_registrations', 'Can view and manage all unconfirmed registrations.'),)
def __str__(self): def __str__(self):
"""String representation""" """String representation"""

Loading…
Cancel
Save