From fa6f31e560a800440165e58a6ff220415b075100 Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Wed, 4 Dec 2024 00:10:05 +0100 Subject: [PATCH 01/10] admin: allow * in group names, verify that only valid group names, section urls and post urls are saved --- jdav_web/jdav_web/settings/components/base.py | 3 + jdav_web/members/admin.py | 4 + .../members/locale/de/LC_MESSAGES/django.po | 437 +++++++++--------- jdav_web/startpage/admin.py | 16 + .../startpage/locale/de/LC_MESSAGES/django.po | 17 +- jdav_web/startpage/urls.py | 10 +- 6 files changed, 264 insertions(+), 223 deletions(-) diff --git a/jdav_web/jdav_web/settings/components/base.py b/jdav_web/jdav_web/settings/components/base.py index 2717694..bbe5684 100644 --- a/jdav_web/jdav_web/settings/components/base.py +++ b/jdav_web/jdav_web/settings/components/base.py @@ -191,3 +191,6 @@ MARKDOWNIFY = { } } } + +# allowed characters in names appearing in urls on the website +STARTPAGE_URL_NAME_PATTERN = "[\w\-: *]" diff --git a/jdav_web/members/admin.py b/jdav_web/members/admin.py index d4ca8c8..299f38c 100644 --- a/jdav_web/members/admin.py +++ b/jdav_web/members/admin.py @@ -704,6 +704,10 @@ class RegistrationPasswordInline(admin.TabularInline): class GroupAdminForm(forms.ModelForm): + name = forms.RegexField(regex=r'^{pattern}+$'.format(pattern=settings.STARTPAGE_URL_NAME_PATTERN), + label=_('name'), + error_messages={'invalid': _('The group name may only consist of letters, numerals, _, -, :, * and spaces.')}) + class Meta: model = Freizeit exclude = ['add_member'] diff --git a/jdav_web/members/locale/de/LC_MESSAGES/django.po b/jdav_web/members/locale/de/LC_MESSAGES/django.po index af1e6d9..2479933 100644 --- a/jdav_web/members/locale/de/LC_MESSAGES/django.po +++ b/jdav_web/members/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-12-03 00:26+0100\n" +"POT-Creation-Date: 2024-12-04 00:04+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,7 +18,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: members/admin.py:126 members/models.py:391 +#: members/admin.py:126 members/models.py:404 msgid "Registration complete" msgstr "Anmeldung vollständig" @@ -34,170 +34,170 @@ msgstr "Nein" msgid "All" msgstr "Alle" -#: members/admin.py:184 members/admin.py:413 +#: members/admin.py:184 members/admin.py:414 msgid "Contact information" msgstr "Kontaktinformationen" -#: members/admin.py:189 members/admin.py:418 +#: members/admin.py:189 members/admin.py:419 msgid "Skills" msgstr "Fähigkeiten" -#: members/admin.py:194 members/admin.py:423 +#: members/admin.py:194 members/admin.py:424 msgid "Others" msgstr "Sonstiges" -#: members/admin.py:200 members/admin.py:428 +#: members/admin.py:200 members/admin.py:429 msgid "Organizational" msgstr "Organisatorisches" -#: members/admin.py:281 +#: members/admin.py:282 msgid "Compose new mail to selected members" msgstr "Neue Nachricht an ausgewählte Teilnehmer*innen verfassen" -#: members/admin.py:287 +#: members/admin.py:288 msgid "Echo required" msgstr "Rückmeldung erforderlich" -#: members/admin.py:289 +#: members/admin.py:290 msgid "Successfully requested echo from selected members." msgstr "" "Rückmeldungsaufforderung erfolgreich an ausgewählte Teilnehmer*innen " "verschickt." -#: members/admin.py:290 +#: members/admin.py:291 msgid "Request echo from selected members" msgstr "Rückmeldungsaufforderung an ausgewählte Teilnehmer*innen verschicken" -#: members/admin.py:299 +#: members/admin.py:300 #, python-format msgid "%(name)s does not have a DAV360 email address or is already registered." msgstr "%(name)s hat keine DAV360 E-Mail Adresse oder ist bereits registriert." -#: members/admin.py:301 +#: members/admin.py:302 #, python-format msgid "Successfully invited %(name)s as user." msgstr "Erfolgreich %(name)s aufgefordert Zugangsdaten zu wählen." -#: members/admin.py:303 +#: members/admin.py:304 msgid "Successfully invited selected members to join as users." msgstr "" "Erfolgreich ausgewählte Teilnehmer*innen aufgefordert Zugangsdaten zu wählen." -#: members/admin.py:305 +#: members/admin.py:306 msgid "Some members have been invited, others could not be invited." msgstr "" "Manche Teilnehmer*innen wurden eingeladen, andere konnten nicht eingeladen " "werden." -#: members/admin.py:312 members/admin.py:329 +#: members/admin.py:313 members/admin.py:330 msgid "Permission denied." msgstr "Fehlende Berechtigungen." -#: members/admin.py:319 members/admin.py:353 +#: members/admin.py:320 members/admin.py:354 #: members/templates/admin/invite_as_user.html:21 msgid "Invite as user" msgstr "Kompass Zugangsdaten wählen lassen" -#: members/admin.py:324 +#: members/admin.py:325 msgid "Invite selected members to join Kompass as users." msgstr "Ausgewählte Teilnehmer*innen Kompass Zugangsdaten wählen lassen." -#: members/admin.py:335 +#: members/admin.py:336 msgid "Member not found." msgstr "Teilnehmer*in nicht gefunden." -#: members/admin.py:339 +#: members/admin.py:340 #, python-format msgid "%(name)s already has login data." msgstr "%(name)s hat schon Zugangsdaten." -#: members/admin.py:344 +#: members/admin.py:345 #, python-format msgid "The configured email address for %(name)s is not an internal one." msgstr "Die für %(name)s eingestellte E-Mail Adresse ist keine DAV360 Adresse." -#: members/admin.py:358 +#: members/admin.py:359 #, python-format msgid "%(name)s already has a pending invitation as user." msgstr "" "%(name)s hat bereits eine ausstehende Aufforderung Zugangsdaten zu wählen." -#: members/admin.py:376 +#: members/admin.py:377 msgid "activity" msgstr "Aktivität" -#: members/admin.py:386 members/models.py:55 members/models.py:1506 +#: members/admin.py:387 members/models.py:56 members/models.py:1519 msgid "Name" msgstr "Name" -#: members/admin.py:476 +#: members/admin.py:477 msgid "Successfully requested mail confirmation from selected registrations." msgstr "Aufforderung zur Bestätigung der Email Adresse versendet." -#: members/admin.py:477 +#: members/admin.py:478 msgid "Request mail confirmation from selected registrations" msgstr "Aufforderung zur Bestätigung der Email Adresse versenden" -#: members/admin.py:484 members/admin.py:558 +#: members/admin.py:485 members/admin.py:559 #, python-format msgid "Successfully confirmed %(name)s." msgstr "Registrierung von %(name)s erfolgreich bestätigt." -#: members/admin.py:488 members/admin.py:561 +#: members/admin.py:489 members/admin.py:562 #, 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:493 +#: members/admin.py:494 msgid "Successfully confirmed multiple registrations." msgstr "Erfolgreich mehrere Registrierungen bestätigt." -#: members/admin.py:495 +#: members/admin.py:496 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:496 +#: members/admin.py:497 msgid "Confirm selected registrations" msgstr "Ausgewählte Registrierungen bestätigen" -#: members/admin.py:519 +#: members/admin.py:520 msgid "Demote selected registrations to waiters." msgstr "Ausgewählte Registrierungen zurück auf die Warteliste setzen." -#: members/admin.py:535 +#: members/admin.py:536 msgid "Demote member to waiter" msgstr "Ausgewählte Registrierung zurück auf die Warteliste setzen." -#: members/admin.py:553 +#: members/admin.py:554 #, python-format msgid "Successfully demoted %(name)s to waiter." msgstr "%(name)s zurück auf die Warteliste gesetzt." -#: members/admin.py:568 members/models.py:398 members/models.py:764 -#: members/models.py:1251 +#: members/admin.py:569 members/models.py:411 members/models.py:777 +#: members/models.py:1264 msgid "Group" msgstr "Gruppe" -#: members/admin.py:602 +#: members/admin.py:603 #, python-format msgid "Successfully asked %(name)s to confirm their waiting status." msgstr "Erfolgreich %(name)s aufgefordert den Wartelistenplatz zu bestätigen." -#: members/admin.py:603 +#: members/admin.py:604 msgid "Ask selected waiters to confirm their waiting status" msgstr "Wartende auffordern den Wartelistenplatz zu bestätigen" -#: members/admin.py:612 members/admin.py:672 +#: members/admin.py:613 members/admin.py:673 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:616 members/admin.py:677 +#: members/admin.py:617 members/admin.py:678 msgid "" "The selected group does not have a contact email. Please first set a contact " "email and then try again." @@ -205,32 +205,43 @@ msgstr "" "Die ausgewählte Gruppe hat keine Kontakt E-Mail Adresse. Bitte stelle eine " "Kontakt E-Mail Adresse ein und versuche es erneut." -#: members/admin.py:624 members/admin.py:684 +#: members/admin.py:625 members/admin.py:685 #, python-format msgid "Successfully invited %(name)s to %(group)s." msgstr "Erfolgreich %(name)s zu Gruppe %(group)s eingeladen." -#: members/admin.py:628 members/admin.py:690 +#: members/admin.py:629 members/admin.py:691 msgid "Select group for invitation" msgstr "Wähle Gruppe für Einladung aus" -#: members/admin.py:635 +#: members/admin.py:636 msgid "Offer waiter a place in a group." msgstr "Personen auf der Warteliste einen Gruppenplatz anbieten." -#: members/admin.py:733 +#: members/admin.py:708 members/models.py:72 +msgid "name" +msgstr "Name" + +#: members/admin.py:709 +msgid "" +"The group name may only consist of letters, numerals, _, -, :, * and spaces." +msgstr "" +"Der Gruppenname darf nur aus Buchstaben, Zahlen, _, -, :, * oder Leerzeichen " +"bestehen." + +#: members/admin.py:738 msgid "Difficulty" msgstr "Schwierigkeit" -#: members/admin.py:736 +#: members/admin.py:741 msgid "Tour type" msgstr "Art der Tour" -#: members/admin.py:739 members/models.py:982 +#: members/admin.py:744 members/models.py:995 msgid "Means of transportation" msgstr "Verkehrsmittel" -#: members/admin.py:765 +#: members/admin.py:770 msgid "" "Please list here all expenses in relation with this excursion and upload " "relevant bills. These have to be permanently stored for the application of " @@ -243,7 +254,7 @@ msgstr "" "einzelnen Posten wird dabei auf der LJP-Kostenübersicht angezeigt (sinnvoll " "wären z.B. Anreise, Verpflegung, Material etc.)." -#: members/admin.py:783 +#: members/admin.py:788 msgid "" "Here you can work on a seminar report for applying for financial " "contributions from Landesjugendplan (LJP). More information on creating a " @@ -256,7 +267,7 @@ msgstr "" "wahlweise nur TN-Liste und Kostenübersicht kannst du anschließend " "herunterladen." -#: members/admin.py:791 +#: members/admin.py:796 msgid "" "Please list all participants (also youth leaders) of this excursion. Here " "you can still make changes just before departure and hence generate the " @@ -267,34 +278,34 @@ msgstr "" "jederzeit die aktuelle Teilnehmer*innenliste für die Krisenintervention " "generieren." -#: members/admin.py:837 +#: members/admin.py:842 #, python-format msgid "You are not allowed to view all members on note list %(name)s." msgstr "" "Du hast nicht die nötigen Rechte um alle Teilnehmer*innen der Notizliste " "%(name)s anzusehen." -#: members/admin.py:847 +#: members/admin.py:852 msgid "Generate PDF summary" msgstr "Übersicht erstellen" -#: members/admin.py:851 +#: members/admin.py:856 msgid "Full report" msgstr "Vollständiger Seminarbericht" -#: members/admin.py:852 +#: members/admin.py:857 msgid "Costs and participants only" msgstr "Nur Kosten und Teilnehmende" -#: members/admin.py:853 +#: members/admin.py:858 msgid "Mode" msgstr "Modus" -#: members/admin.py:854 +#: members/admin.py:859 msgid "Prepend V32" msgstr "V32 Formblatt einfügen" -#: members/admin.py:870 +#: members/admin.py:875 msgid "" "General information on your excursion. These are partly relevant for the " "amount of financial compensation (means of transport, travel distance, etc.)." @@ -303,48 +314,48 @@ msgstr "" "teilweise relevant für die Zuschüsse aus dem Jugendetat (Verkehrsmittel, " "Fahrstrecke in km)." -#: members/admin.py:900 +#: members/admin.py:905 #, python-format msgid "You are not allowed to view all members on excursion %(name)s." msgstr "" "Du hast nicht die nötigen Rechte um alle Teilnehmer*innen der Ausfahrt " "%(name)s anzusehen." -#: members/admin.py:908 +#: members/admin.py:913 msgid "Generate crisis intervention list" msgstr "Kriseninterventionsliste erstellen" -#: members/admin.py:916 +#: members/admin.py:921 msgid "Generate overview" msgstr "Hinweise für Jugendleiter erstellen" -#: members/admin.py:920 members/admin.py:952 +#: members/admin.py:925 members/admin.py:957 #: members/templates/admin/generate_seminar_report.html:21 msgid "Generate seminar report" msgstr "Landesjugendplan Antrag erstellen" -#: members/admin.py:933 +#: members/admin.py:938 msgid "Please select a mode." msgstr "Bitte wähle einen Modus aus." -#: members/admin.py:938 +#: members/admin.py:943 msgid "" "Full mode is only available, if the seminar report section is filled out." msgstr "" "Der vollständiger Modus ist nur verfügbar, wenn der Seminarbericht " "ausgefüllt ist. " -#: members/admin.py:964 +#: members/admin.py:969 msgid "Generate SJR application" msgstr "SJR Antrag erstellen" -#: members/admin.py:968 +#: members/admin.py:973 msgid "No statement found. Please add a statement and then retry." msgstr "" "Keine Abrechnung angelegt. Bitte lege eine Abrechnung and und versuche es " "erneut." -#: members/admin.py:972 +#: members/admin.py:977 msgid "" "Successfully submited statement. The finance department will notify you as " "soon as possible." @@ -352,7 +363,7 @@ msgstr "" "Abrechnung erfolgreich eingericht. Die Finanzabteilung wird sich bei dir so " "schnell wie möglich melden." -#: members/admin.py:975 +#: members/admin.py:980 #: members/templates/admin/freizeit_finance_overview.html:21 msgid "Finance overview" msgstr "Kostenübersicht" @@ -361,580 +372,576 @@ msgstr "Kostenübersicht" msgid "member administration" msgstr "Teilnehmer*innenverwaltung" -#: members/models.py:41 +#: members/models.py:42 msgid "Monday" msgstr "Montag" -#: members/models.py:42 +#: members/models.py:43 msgid "Tuesday" msgstr "Dienstag" -#: members/models.py:43 +#: members/models.py:44 msgid "Wednesday" msgstr "Mittwoch" -#: members/models.py:44 +#: members/models.py:45 msgid "Thursday" msgstr "Donnerstag" -#: members/models.py:45 +#: members/models.py:46 msgid "Friday" msgstr "Freitag" -#: members/models.py:46 +#: members/models.py:47 msgid "Saturday" msgstr "Samstag" -#: members/models.py:47 +#: members/models.py:48 msgid "Sunday" msgstr "Sonntag" -#: members/models.py:56 members/models.py:968 +#: members/models.py:57 members/models.py:981 msgid "Description" msgstr "Beschreibung" -#: members/models.py:62 members/models.py:960 +#: members/models.py:63 members/models.py:973 #: members/templates/members/change_member.html:18 msgid "Activity" msgstr "Aktivität" -#: members/models.py:63 +#: members/models.py:64 msgid "Activities" msgstr "Aktivitäten" -#: members/models.py:71 -msgid "name" -msgstr "Name" - -#: members/models.py:72 +#: members/models.py:73 msgid "description" msgstr "Beschreibung" -#: members/models.py:73 +#: members/models.py:74 msgid "show on website" msgstr "Auf der Webseite anzeigen" -#: members/models.py:74 +#: members/models.py:75 msgid "lowest year" msgstr "Ab Jahrgang" -#: members/models.py:75 +#: members/models.py:76 msgid "highest year" msgstr "Bis Jahrgang" -#: members/models.py:76 +#: members/models.py:77 msgid "youth leaders" msgstr "Jugendleiter" -#: members/models.py:78 +#: members/models.py:79 msgid "week day" msgstr "Wochentag" -#: members/models.py:79 members/models.py:1333 +#: members/models.py:80 members/models.py:1346 msgid "Starting time" msgstr "Zeitpunkt" -#: members/models.py:80 +#: members/models.py:81 msgid "Ending time" msgstr "Endzeitpunkt" -#: members/models.py:82 +#: members/models.py:83 msgid "Contact email" msgstr "Kontakt Email" -#: members/models.py:92 members/models.py:259 +#: members/models.py:93 members/models.py:272 msgid "group" msgstr "Gruppe" -#: members/models.py:93 +#: members/models.py:94 msgid "groups" msgstr "Gruppen" -#: members/models.py:109 +#: members/models.py:110 msgid "prename" msgstr "Vorname" -#: members/models.py:110 +#: members/models.py:111 msgid "last name" msgstr "Nachname" -#: members/models.py:113 +#: members/models.py:114 msgid "Email confirmed" msgstr "Emailadresse bestätigt" -#: members/models.py:150 -msgid "Email confirmation needed" -msgstr "Email Bestätigung erforderlich" - -#: members/models.py:190 members/models.py:233 +#: members/models.py:132 members/models.py:203 members/models.py:246 msgid "phone number" msgstr "Telefonnummer (mobil)" -#: members/models.py:200 +#: members/models.py:163 +msgid "Email confirmation needed" +msgstr "Email Bestätigung erforderlich" + +#: members/models.py:213 msgid "birth date" msgstr "Geburtsdatum" -#: members/models.py:205 +#: members/models.py:218 msgid "Gender" msgstr "Gender" -#: members/models.py:206 +#: members/models.py:219 msgid "comments" msgstr "Kommentare" -#: members/models.py:230 +#: members/models.py:243 msgid "Alternative email confirmed" msgstr "Alternative E-Mail Adresse bestätigt" -#: members/models.py:234 +#: members/models.py:247 msgid "street and house number" msgstr "Straße und Hausnummer" -#: members/models.py:235 +#: members/models.py:248 msgid "Postcode" msgstr "PLZ" -#: members/models.py:237 +#: members/models.py:250 msgid "town" msgstr "Stadt" -#: members/models.py:238 +#: members/models.py:251 msgid "Address extra" msgstr "Adress-Zusatz" -#: members/models.py:239 +#: members/models.py:252 msgid "Country" msgstr "Land" -#: members/models.py:241 +#: members/models.py:254 msgid "Good conduct certificate presented on" msgstr "Führungszeugnis vorgelegt am" -#: members/models.py:242 +#: members/models.py:255 msgid "Joined on" msgstr "Eintritt" -#: members/models.py:243 +#: members/models.py:256 msgid "Left on" msgstr "Austritt" -#: members/models.py:244 +#: members/models.py:257 msgid "Has key" msgstr "Hat Jugendraumschlüssel" -#: members/models.py:245 +#: members/models.py:258 msgid "Has a free ticket for the climbing gym" msgstr "Hat Freikarte für Kletterhalle" -#: members/models.py:246 +#: members/models.py:259 msgid "DAV badge number" msgstr "DAV Mitgliedsnummer" -#: members/models.py:247 +#: members/models.py:260 msgid "Knows how to swim" msgstr "Kann schwimmen" -#: members/models.py:248 +#: members/models.py:261 msgid "Climbing badge" msgstr "Kletterschein" -#: members/models.py:249 +#: members/models.py:262 msgid "Alpine experience" msgstr "Alpine Erfahrung" -#: members/models.py:250 +#: members/models.py:263 msgid "Allergies" msgstr "Allergieen" -#: members/models.py:251 +#: members/models.py:264 msgid "Medication" msgstr "Medikamente" -#: members/models.py:252 +#: members/models.py:265 msgid "Tetanus vaccination" msgstr "Tetanusimpfung" -#: members/models.py:253 +#: members/models.py:266 msgid "Photos may be taken" msgstr "Fotoerlaubnis" -#: members/models.py:254 +#: members/models.py:267 msgid "Legal guardians" msgstr "Erziehungsberechtigte" -#: members/models.py:256 +#: members/models.py:269 msgid "May cancel a group appointment independently" msgstr "Darf sich allein von der Gruppenstunde abmelden" -#: members/models.py:263 +#: members/models.py:276 msgid "receives newsletter" msgstr "Erhält den Newsletter" -#: members/models.py:267 +#: members/models.py:280 msgid "created" msgstr "erstellt" -#: members/models.py:268 +#: members/models.py:281 msgid "Active" msgstr "Aktiv" -#: members/models.py:269 +#: members/models.py:282 msgid "registration form" msgstr "Anmeldeformular" -#: members/models.py:277 +#: members/models.py:290 msgid "image" msgstr "Bild" -#: members/models.py:286 +#: members/models.py:299 msgid "Echoed" msgstr "Rückgemeldet" -#: members/models.py:287 +#: members/models.py:300 msgid "Confirmed" msgstr "Bestätigt" -#: members/models.py:289 +#: members/models.py:302 msgid "Login data" msgstr "Zugangsdaten" -#: members/models.py:319 +#: members/models.py:332 msgid "Good conduct certificate valid" msgstr "Führungszeugnis gültig" -#: members/models.py:401 +#: members/models.py:414 msgid "member" msgstr "Teilnehmer*in" -#: members/models.py:402 +#: members/models.py:415 msgid "members" msgstr "Teilnehmer*innen" -#: members/models.py:471 +#: members/models.py:484 #, python-format msgid "New unconfirmed registration for group %(group)s" msgstr "Neue unbestätigte Registrierung für Gruppe %(group)s" -#: members/models.py:697 +#: members/models.py:710 msgid "Set login data for Kompass" msgstr "Zugangsdaten für Kompass wählen" -#: members/models.py:715 members/models.py:916 members/models.py:927 -#: members/models.py:1282 members/models.py:1289 +#: members/models.py:728 members/models.py:929 members/models.py:940 +#: members/models.py:1295 members/models.py:1302 msgid "Member" msgstr "Teilnehmer*in" -#: members/models.py:722 +#: members/models.py:735 msgid "Emergency contact" msgstr "Notfallkontakt" -#: members/models.py:723 +#: members/models.py:736 msgid "Emergency contacts" msgstr "Notfallkontakte" -#: members/models.py:743 +#: members/models.py:756 msgid "Unconfirmed registration" msgstr "Unbestätigte Registrierung" -#: members/models.py:744 +#: members/models.py:757 msgid "Unconfirmed registrations" msgstr "Unbestätigte Registrierungen" -#: members/models.py:763 members/models.py:808 +#: members/models.py:776 members/models.py:821 msgid "Waiter" msgstr "Wartende Person" -#: members/models.py:765 +#: members/models.py:778 msgid "Invitation date" msgstr "Einladungsdatum" -#: members/models.py:766 members/templates/members/reject_success.html:6 +#: members/models.py:779 members/templates/members/reject_success.html:6 #: members/templates/members/reject_success.html:11 msgid "Invitation rejected" msgstr "Einladung abgelehnt" -#: members/models.py:770 +#: members/models.py:783 msgid "Invitation to group" msgstr "Gruppeneinladung" -#: members/models.py:771 +#: members/models.py:784 msgid "Invitations to groups" msgstr "Gruppeneinladungen" -#: members/models.py:778 +#: members/models.py:791 msgid "Rejected" msgstr "Abgelehnt" -#: members/models.py:780 +#: members/models.py:793 msgid "Expired" msgstr "Abgelaufen" -#: members/models.py:782 +#: members/models.py:795 msgid "Undecided" msgstr "Ausstehend" -#: members/models.py:783 +#: members/models.py:796 msgid "Status" msgstr "Status" -#: members/models.py:794 +#: members/models.py:807 msgid "Do you want to tell us something else?" msgstr "Möchtest du uns noch etwas mitteilen?" -#: members/models.py:795 +#: members/models.py:808 msgid "application date" msgstr "Bewerbungsdatum" -#: members/models.py:797 +#: members/models.py:810 msgid "Last wait confirmation" msgstr "Letzte Wartebestätigung" -#: members/models.py:801 +#: members/models.py:814 msgid "Last reminder" msgstr "Letzte Erinnerung" -#: members/models.py:802 +#: members/models.py:815 msgid "Missed reminders" msgstr "Verpasste Erinnerungen" -#: members/models.py:809 +#: members/models.py:822 msgid "Waiters" msgstr "Warteliste" -#: members/models.py:833 +#: members/models.py:846 msgid "Waiting status confirmed" msgstr "Wartelistenplatz bestätigt" -#: members/models.py:840 +#: members/models.py:853 msgid "Waiting confirmation needed" msgstr "Wartelistenplatzbestätigung erforderlich" -#: members/models.py:895 +#: members/models.py:908 msgid "Invitation to trial group meeting" msgstr "Einladung zu Schnupperstunde" -#: members/models.py:907 +#: members/models.py:920 msgid "Unregistered from waiting list" msgstr "Von der Warteliste abgemeldet" -#: members/models.py:921 +#: members/models.py:934 msgid "Comment" msgstr "Kommentar" -#: members/models.py:928 members/models.py:1290 +#: members/models.py:941 members/models.py:1303 msgid "Members" msgstr "Teilnehmer*innen" -#: members/models.py:962 +#: members/models.py:975 msgid "Place" msgstr "Stützpunkt / Ort" -#: members/models.py:963 +#: members/models.py:976 msgid "Destination (optional)" msgstr "ggf. Ziel" -#: members/models.py:965 +#: members/models.py:978 msgid "e.g. a peak" msgstr "z.B. ein Gipfel" -#: members/models.py:966 +#: members/models.py:979 msgid "Begin" msgstr "Anfang" -#: members/models.py:967 +#: members/models.py:980 msgid "End (optional)" msgstr "Ende" -#: members/models.py:970 +#: members/models.py:983 msgid "Groups" msgstr "Gruppen" -#: members/models.py:983 +#: members/models.py:996 msgid "Kilometers traveled" msgstr "Fahrstrecke in Kilometer" -#: members/models.py:986 +#: members/models.py:999 msgid "Categories" msgstr "Kategorien" -#: members/models.py:987 +#: members/models.py:1000 msgid "easy" msgstr "leicht" -#: members/models.py:987 +#: members/models.py:1000 msgid "medium" msgstr "mittel" -#: members/models.py:987 +#: members/models.py:1000 msgid "hard" msgstr "schwer" -#: members/models.py:997 members/models.py:1313 +#: members/models.py:1010 members/models.py:1326 #: members/templates/admin/freizeit_finance_overview.html:26 msgid "Excursion" msgstr "Ausfahrt" -#: members/models.py:998 +#: members/models.py:1011 msgid "Excursions" msgstr "Ausfahrten" -#: members/models.py:1228 members/models.py:1304 members/models.py:1520 +#: members/models.py:1241 members/models.py:1317 members/models.py:1533 msgid "Title" msgstr "Titel" -#: members/models.py:1229 members/models.py:1247 members/models.py:1521 +#: members/models.py:1242 members/models.py:1260 members/models.py:1534 msgid "Date" msgstr "Datum" -#: members/models.py:1248 +#: members/models.py:1261 msgid "Location" msgstr "Ort" -#: members/models.py:1249 +#: members/models.py:1262 msgid "Topic" msgstr "Thema" -#: members/models.py:1273 +#: members/models.py:1286 msgid "Jugendleiter" msgstr "Jugendleiter" -#: members/models.py:1276 +#: members/models.py:1289 msgid "Klettertreff" msgstr "Klettertreff" -#: members/models.py:1277 +#: members/models.py:1290 msgid "Klettertreffs" msgstr "Klettertreffs" -#: members/models.py:1295 +#: members/models.py:1308 msgid "Password" msgstr "Passwort" -#: members/models.py:1298 +#: members/models.py:1311 msgid "registration password" msgstr "Registrierungspassort" -#: members/models.py:1299 +#: members/models.py:1312 msgid "registration passwords" msgstr "Registrierungspasswörter" -#: members/models.py:1306 +#: members/models.py:1319 msgid "Alpinistic goals" msgstr "Alpintechnische Ziele" -#: members/models.py:1307 +#: members/models.py:1320 msgid "Pedagogic goals" msgstr "Pädagogische Ziele" -#: members/models.py:1308 +#: members/models.py:1321 msgid "Content and methods" msgstr "Inhalte und Methoden" -#: members/models.py:1309 +#: members/models.py:1322 msgid "Evaluation" msgstr "Wertung" -#: members/models.py:1310 +#: members/models.py:1323 msgid "Experiences and possible improvements" msgstr "Erfahrungen und Verbesserungsvorschläge" -#: members/models.py:1319 members/models.py:1340 +#: members/models.py:1332 members/models.py:1353 msgid "LJP Proposal" msgstr "Seminarbericht" -#: members/models.py:1320 +#: members/models.py:1333 msgid "LJP Proposals" msgstr "Seminarberichte" -#: members/models.py:1334 +#: members/models.py:1347 msgid "Duration in hours" msgstr "Dauer in Stunden" -#: members/models.py:1337 +#: members/models.py:1350 msgid "Activity and method" msgstr "Art der Aktion inkl. Methode" -#: members/models.py:1345 +#: members/models.py:1358 msgid "Intervention" msgstr "Aktion" -#: members/models.py:1346 +#: members/models.py:1359 msgid "Interventions" msgstr "Aktionen" -#: members/models.py:1448 members/models.py:1478 +#: members/models.py:1461 members/models.py:1491 msgid "May list members" msgstr "Darf folgende Teilnehmer*innen listen" -#: members/models.py:1450 members/models.py:1480 +#: members/models.py:1463 members/models.py:1493 msgid "May view members" msgstr "Darf folgende Teilnehmer*innen anzeigen" -#: members/models.py:1452 members/models.py:1482 +#: members/models.py:1465 members/models.py:1495 msgid "May change members" msgstr "Darf folgende Teilnehmer*innen ändern" -#: members/models.py:1454 members/models.py:1484 +#: members/models.py:1467 members/models.py:1497 msgid "May delete members" msgstr "Darf folgende Teilnehmer*innen löschen" -#: members/models.py:1458 members/models.py:1488 +#: members/models.py:1471 members/models.py:1501 msgid "May list members of groups" msgstr "Darf Teilnehmer*innen folgender Gruppen listen" -#: members/models.py:1460 members/models.py:1490 +#: members/models.py:1473 members/models.py:1503 msgid "May view members of groups" msgstr "Darf Teilnehmer*innen folgender Gruppen anzeigen" -#: members/models.py:1462 members/models.py:1492 +#: members/models.py:1475 members/models.py:1505 msgid "May change members of groups" msgstr "Darf Teilnehmer*innen folgender Gruppen ändern" -#: members/models.py:1464 members/models.py:1494 +#: members/models.py:1477 members/models.py:1507 msgid "May delete members of groups" msgstr "Darf Teilnehmer*innen folgender Gruppen löschen" -#: members/models.py:1467 members/models.py:1468 members/models.py:1471 +#: members/models.py:1480 members/models.py:1481 members/models.py:1484 msgid "Permissions" msgstr "Berechtigungen" -#: members/models.py:1497 members/models.py:1498 members/models.py:1501 +#: members/models.py:1510 members/models.py:1511 members/models.py:1514 msgid "Group permissions" msgstr "Gruppenberechtigungen" -#: members/models.py:1507 +#: members/models.py:1520 msgid "Permission needed" msgstr "Freigabe erforderlich" -#: members/models.py:1510 +#: members/models.py:1523 msgid "Training category" msgstr "Fortbildungstyp" -#: members/models.py:1511 +#: members/models.py:1524 msgid "Training categories" msgstr "Fortbildungstypen" -#: members/models.py:1522 +#: members/models.py:1535 msgid "Category" msgstr "Kategorien" -#: members/models.py:1523 +#: members/models.py:1536 msgid "Comments" msgstr "Kommentar" -#: members/models.py:1524 +#: members/models.py:1537 msgid "Participated" msgstr "Teilgenommmen" -#: members/models.py:1525 +#: members/models.py:1538 msgid "Passed" msgstr "Bestanden" -#: members/models.py:1528 +#: members/models.py:1541 msgid "Training" msgstr "Fortbildung" -#: members/models.py:1529 +#: members/models.py:1542 msgid "Trainings" msgstr "Fortbildungen" diff --git a/jdav_web/startpage/admin.py b/jdav_web/startpage/admin.py index c1dcd06..724f17d 100644 --- a/jdav_web/startpage/admin.py +++ b/jdav_web/startpage/admin.py @@ -1,4 +1,7 @@ from django.contrib import admin +from django.conf import settings +from django import forms +from django.utils.translation import gettext_lazy as _ from .models import Post, Image, Section, MemberOnPost @@ -13,14 +16,27 @@ class MemberOnPostInline(admin.TabularInline): extra = 0 +class PostForm(forms.ModelForm): + urlname = forms.RegexField(regex=r'^{pattern}+$'.format(pattern=settings.STARTPAGE_URL_NAME_PATTERN), + label=_('URL'), + error_messages={'invalid': _('The url may only consist of letters, numerals, _, -, :, * and spaces.')}) + + @admin.register(Post) class PostAdmin(admin.ModelAdmin): inlines = [ImageInline, MemberOnPostInline] list_display = ['title', 'date', 'section', 'absolute_urlname'] list_filter = ['section'] search_fields = ['title'] + form = PostForm + +class SectionForm(forms.ModelForm): + urlname = forms.RegexField(regex=r'^{pattern}+$'.format(pattern=settings.STARTPAGE_URL_NAME_PATTERN), + label=_('URL'), + error_messages={'invalid': _('The url may only consist of letters, numerals, _, -, :, * and spaces.')}) @admin.register(Section) class SectionAdmin(admin.ModelAdmin): list_display = ['title', 'absolute_urlname'] + form = SectionForm diff --git a/jdav_web/startpage/locale/de/LC_MESSAGES/django.po b/jdav_web/startpage/locale/de/LC_MESSAGES/django.po index a02680c..4705c40 100644 --- a/jdav_web/startpage/locale/de/LC_MESSAGES/django.po +++ b/jdav_web/startpage/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-12-01 16:23+0100\n" +"POT-Creation-Date: 2024-12-04 00:04+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,14 +18,21 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: startpage/admin.py:21 startpage/admin.py:36 startpage/models.py:18 +#: startpage/models.py:40 +msgid "URL" +msgstr "URL" + +#: startpage/admin.py:22 startpage/admin.py:37 +msgid "The url may only consist of letters, numerals, _, -, :, * and spaces." +msgstr "" +"Die URL darf nur aus Buchstaben, Zahlen, _, -, :, * oder Leerzeichen " +"bestehen." + #: startpage/models.py:17 startpage/models.py:39 msgid "Title" msgstr "Titel" -#: startpage/models.py:18 startpage/models.py:40 -msgid "URL" -msgstr "URL" - #: startpage/models.py:19 startpage/models.py:42 msgid "website text" msgstr "Webseitentext" diff --git a/jdav_web/startpage/urls.py b/jdav_web/startpage/urls.py index de98543..417f6fc 100644 --- a/jdav_web/startpage/urls.py +++ b/jdav_web/startpage/urls.py @@ -1,3 +1,4 @@ +from django.conf import settings from django.urls import re_path from . import views @@ -10,7 +11,10 @@ urlpatterns = [ re_path(r'^berichte/?$', views.berichte, name='berichte'), re_path(r'^gruppen/?$', views.static_view('startpage/gruppen.html'), name='gruppen'), re_path(r'^gruppen/faq/?$', views.static_view('startpage/gruppen/faq.html'), name='faq'), - re_path(r'^gruppen/(?P[\w\-:]+)/?$', views.gruppe_detail, name='gruppe_detail'), - re_path(r'^(?P[\w\-:]+)/(?P[\w\-:]+)/?$', views.post, name='post'), - re_path(r'^(?P[\w\-:]+)/?$', views.section, name='section'), + re_path(r'^gruppen/(?P{pattern}+)/?$'.format(pattern=settings.STARTPAGE_URL_NAME_PATTERN), + views.gruppe_detail, name='gruppe_detail'), + re_path(r'^(?P{pattern}+)/(?P{pattern}+)/?$'.format(pattern=settings.STARTPAGE_URL_NAME_PATTERN), + views.post, name='post'), + re_path(r'^(?P{pattern}+)/?$'.format(pattern=settings.STARTPAGE_URL_NAME_PATTERN), + views.section, name='section'), ] From d4d9d97a94c38f5a3a2adf614f110fe0cf9ff6ac Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Wed, 4 Dec 2024 00:32:00 +0100 Subject: [PATCH 02/10] mailer: force email address names to be unique --- .../0008_alter_emailaddress_name.py | 19 +++++++++++++++++++ jdav_web/mailer/models.py | 4 +++- 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 jdav_web/mailer/migrations/0008_alter_emailaddress_name.py diff --git a/jdav_web/mailer/migrations/0008_alter_emailaddress_name.py b/jdav_web/mailer/migrations/0008_alter_emailaddress_name.py new file mode 100644 index 0000000..952bacd --- /dev/null +++ b/jdav_web/mailer/migrations/0008_alter_emailaddress_name.py @@ -0,0 +1,19 @@ +# Generated by Django 4.0.1 on 2024-12-03 23:19 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mailer', '0007_emailaddress_internal_only'), + ] + + operations = [ + migrations.AlterField( + model_name='emailaddress', + name='name', + field=models.CharField(max_length=50, unique=True, validators=[django.core.validators.RegexValidator('^[0-9a-zA-Z._-]*$', 'Only alphanumeric characters, ., - and _ are allowed')], verbose_name='name'), + ), + ] diff --git a/jdav_web/mailer/models.py b/jdav_web/mailer/models.py index bed3877..685be2f 100644 --- a/jdav_web/mailer/models.py +++ b/jdav_web/mailer/models.py @@ -22,7 +22,8 @@ alphanumeric = RegexValidator(r'^[0-9a-zA-Z._-]*$', class EmailAddress(models.Model): """Represents an email address, that is forwarded to specific members""" - name = models.CharField(_('name'), max_length=50, validators=[alphanumeric]) + name = models.CharField(_('name'), max_length=50, validators=[alphanumeric], + unique=True) to_members = models.ManyToManyField('members.Member', verbose_name=_('Forward to participants'), blank=True) @@ -63,6 +64,7 @@ class EmailAddressForm(forms.ModelForm): exclude = [] def clean(self): + super(EmailAddressForm, self).clean() group = self.cleaned_data.get('to_groups') members = self.cleaned_data.get('to_members') if not group and not members: From f0ed36a0cca7247f11dc3539595b8207b3deca78 Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Sat, 7 Dec 2024 13:56:26 +0100 Subject: [PATCH 03/10] docker/development: add example .env file --- docker/development/docker.env.example | 33 +++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 docker/development/docker.env.example diff --git a/docker/development/docker.env.example b/docker/development/docker.env.example new file mode 100644 index 0000000..1e1131d --- /dev/null +++ b/docker/development/docker.env.example @@ -0,0 +1,33 @@ +DJANGO_ALLOWED_HOST='*' +DJANGO_BASE_URL='localhost:8000' +DJANGO_PROTOCOL='http' + +EMAIL_HOST='example.com' +EMAIL_HOST_USER='foo@example.com' +EMAIL_HOST_PASSWORD='password' +EMAIL_SENDING_ADDRESS='foo@example.com' +EMAIL_SENDING_NAME='My association' + +DOMAIN='example.com' + +DJANGO_DEPLOY=1 +DJANGO_DEBUG=1 + +DJANGO_DATABASE_NAME='kompass' +DJANGO_DATABASE_USER='kompass' +DJANGO_DATABASE_PASSWORD='foobar' +DJANGO_DATABASE_HOST='db' +DJANGO_DATABASE_PORT=3306 + +MYSQL_ROOT_PASSWORD='secret' +MYSQL_PASSWORD='foobar' +MYSQL_USER='kompass' +MYSQL_DATABASE='kompass' + +DJANGO_SETTINGS_MODULE='jdav_web.settings' +DJANGO_STATIC_ROOT='/var/www/jdav_web/assets' + +MEMCACHED_URL='cache:11211' +BROKER_URL='redis://redis:6379/0' + +SEND_FROM_ASSOCIATION_EMAIL=0 From f61941c3d0cff4f07b346196d31e4a85fd3a7403 Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Fri, 13 Dec 2024 23:34:19 +0100 Subject: [PATCH 04/10] settings: populate links from environment variables --- jdav_web/jdav_web/settings/local.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jdav_web/jdav_web/settings/local.py b/jdav_web/jdav_web/settings/local.py index c2c96c9..d2bd9eb 100644 --- a/jdav_web/jdav_web/settings/local.py +++ b/jdav_web/jdav_web/settings/local.py @@ -45,9 +45,9 @@ SEND_FROM_ASSOCIATION_EMAIL = os.environ.get('SEND_FROM_ASSOCIATION_EMAIL', '0') ALLOWANCE_PER_DAY = 22 MAX_NIGHT_COST = 11 -CLOUD_LINK = 'https://nc.cloud-jdav-hd.de' -DAV_360_LINK = 'https://dav360.de' -WIKI_LINK = 'https://davbgs.sharepoint.com/sites/S-114-O-JDAV-Jugendreferat' +CLOUD_LINK = os.environ.get('CLOUD_LINK', 'https://startpage.com') +DAV_360_LINK = os.environ.get('DAV_360_LINK', 'https://dav360.de') +WIKI_LINK = os.environ.get('WIKI_LINK', 'https://wikipedia.org') DOCS_LINK = os.environ.get('DOCS_LINK', 'https://jdav-hd.de/static/docs/') # Admin setup @@ -65,7 +65,7 @@ MAX_REMINDER_COUNT = 3 TEST_MAIL = "post@flavigny.de" -REGISTRATION_FORM_DOWNLOAD_LINK = 'https://nc.cloud-jdav-hd.de' +REGISTRATION_FORM_DOWNLOAD_LINK = os.environ.get('REGISTRATION_FORM_DOWNLOAD_LINK', 'https://startpage.com') DOMAIN = os.environ.get('DOMAIN', 'example.com') From 55c960542827358bf9ba2fdc518f470b46ac56de Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Sat, 14 Dec 2024 16:52:45 +0100 Subject: [PATCH 05/10] members/admin: show last group invitation and gender in list --- jdav_web/members/admin.py | 25 +- .../members/locale/de/LC_MESSAGES/django.po | 276 +++++++++--------- jdav_web/members/models.py | 8 + 3 files changed, 170 insertions(+), 139 deletions(-) diff --git a/jdav_web/members/admin.py b/jdav_web/members/admin.py index 299f38c..3bd3653 100644 --- a/jdav_web/members/admin.py +++ b/jdav_web/members/admin.py @@ -15,6 +15,7 @@ from django.template.loader import get_template from django.urls import path, reverse from django.http import HttpResponse, HttpResponseRedirect from wsgiref.util import FileWrapper +from django.utils import timezone from django import forms from django.contrib import admin, messages from django.contrib.admin import DateFieldListFilter @@ -580,14 +581,28 @@ class InvitationToGroupAdmin(admin.TabularInline): return False +class InvitedToGroupFilter(admin.SimpleListFilter): + title = _('Pending group invitation for group') + parameter_name = 'pending_group_invitation' + + def lookups(self, request, model_admin): + return [(g.pk, g.name) for g in Group.objects.all()] + + def queryset(self, request, queryset): + pk = self.value() + if not pk: + return queryset + return queryset.filter(invitationtogroup__group__pk=pk, invitationtogroup__rejected=False, + invitationtogroup__date__gt=(timezone.now() - timezone.timedelta(days=30)).date()).distinct() + + class MemberWaitingListAdmin(CommonAdminMixin, admin.ModelAdmin): fields = ['prename', 'lastname', 'email', 'birth_date', 'gender', 'application_text', - 'application_date', 'comments', - 'sent_reminders'] - list_display = ('name', 'birth_date', 'age', 'application_date', 'confirmed_mail', - 'waiting_confirmed', 'sent_reminders') + 'application_date', 'comments', 'sent_reminders'] + list_display = ('name', 'birth_date', 'age', 'gender', 'application_date', 'latest_group_invitation', + 'confirmed_mail', 'waiting_confirmed', 'sent_reminders') search_fields = ('prename', 'lastname', 'email') - list_filter = ('confirmed_mail',) + list_filter = ['confirmed_mail', 'gender', InvitedToGroupFilter] actions = ['ask_for_registration', 'ask_for_wait_confirmation'] inlines = [InvitationToGroupAdmin] readonly_fields= ['application_date', 'sent_reminders'] diff --git a/jdav_web/members/locale/de/LC_MESSAGES/django.po b/jdav_web/members/locale/de/LC_MESSAGES/django.po index 2479933..15d2225 100644 --- a/jdav_web/members/locale/de/LC_MESSAGES/django.po +++ b/jdav_web/members/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-12-04 00:04+0100\n" +"POT-Creation-Date: 2024-12-14 16:49+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,186 +18,190 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: members/admin.py:126 members/models.py:404 +#: members/admin.py:127 members/models.py:404 msgid "Registration complete" msgstr "Anmeldung vollständig" -#: members/admin.py:132 +#: members/admin.py:133 msgid "True" msgstr "Ja" -#: members/admin.py:133 +#: members/admin.py:134 msgid "False" msgstr "Nein" -#: members/admin.py:134 +#: members/admin.py:135 msgid "All" msgstr "Alle" -#: members/admin.py:184 members/admin.py:414 +#: members/admin.py:185 members/admin.py:415 msgid "Contact information" msgstr "Kontaktinformationen" -#: members/admin.py:189 members/admin.py:419 +#: members/admin.py:190 members/admin.py:420 msgid "Skills" msgstr "Fähigkeiten" -#: members/admin.py:194 members/admin.py:424 +#: members/admin.py:195 members/admin.py:425 msgid "Others" msgstr "Sonstiges" -#: members/admin.py:200 members/admin.py:429 +#: members/admin.py:201 members/admin.py:430 msgid "Organizational" msgstr "Organisatorisches" -#: members/admin.py:282 +#: members/admin.py:283 msgid "Compose new mail to selected members" msgstr "Neue Nachricht an ausgewählte Teilnehmer*innen verfassen" -#: members/admin.py:288 +#: members/admin.py:289 msgid "Echo required" msgstr "Rückmeldung erforderlich" -#: members/admin.py:290 +#: members/admin.py:291 msgid "Successfully requested echo from selected members." msgstr "" "Rückmeldungsaufforderung erfolgreich an ausgewählte Teilnehmer*innen " "verschickt." -#: members/admin.py:291 +#: members/admin.py:292 msgid "Request echo from selected members" msgstr "Rückmeldungsaufforderung an ausgewählte Teilnehmer*innen verschicken" -#: members/admin.py:300 +#: members/admin.py:301 #, python-format msgid "%(name)s does not have a DAV360 email address or is already registered." msgstr "%(name)s hat keine DAV360 E-Mail Adresse oder ist bereits registriert." -#: members/admin.py:302 +#: members/admin.py:303 #, python-format msgid "Successfully invited %(name)s as user." msgstr "Erfolgreich %(name)s aufgefordert Zugangsdaten zu wählen." -#: members/admin.py:304 +#: members/admin.py:305 msgid "Successfully invited selected members to join as users." msgstr "" "Erfolgreich ausgewählte Teilnehmer*innen aufgefordert Zugangsdaten zu wählen." -#: members/admin.py:306 +#: members/admin.py:307 msgid "Some members have been invited, others could not be invited." msgstr "" "Manche Teilnehmer*innen wurden eingeladen, andere konnten nicht eingeladen " "werden." -#: members/admin.py:313 members/admin.py:330 +#: members/admin.py:314 members/admin.py:331 msgid "Permission denied." msgstr "Fehlende Berechtigungen." -#: members/admin.py:320 members/admin.py:354 +#: members/admin.py:321 members/admin.py:355 #: members/templates/admin/invite_as_user.html:21 msgid "Invite as user" msgstr "Kompass Zugangsdaten wählen lassen" -#: members/admin.py:325 +#: members/admin.py:326 msgid "Invite selected members to join Kompass as users." msgstr "Ausgewählte Teilnehmer*innen Kompass Zugangsdaten wählen lassen." -#: members/admin.py:336 +#: members/admin.py:337 msgid "Member not found." msgstr "Teilnehmer*in nicht gefunden." -#: members/admin.py:340 +#: members/admin.py:341 #, python-format msgid "%(name)s already has login data." msgstr "%(name)s hat schon Zugangsdaten." -#: members/admin.py:345 +#: members/admin.py:346 #, python-format msgid "The configured email address for %(name)s is not an internal one." msgstr "Die für %(name)s eingestellte E-Mail Adresse ist keine DAV360 Adresse." -#: members/admin.py:359 +#: members/admin.py:360 #, python-format msgid "%(name)s already has a pending invitation as user." msgstr "" "%(name)s hat bereits eine ausstehende Aufforderung Zugangsdaten zu wählen." -#: members/admin.py:377 +#: members/admin.py:378 msgid "activity" msgstr "Aktivität" -#: members/admin.py:387 members/models.py:56 members/models.py:1519 +#: members/admin.py:388 members/models.py:56 members/models.py:1527 msgid "Name" msgstr "Name" -#: members/admin.py:477 +#: members/admin.py:478 msgid "Successfully requested mail confirmation from selected registrations." msgstr "Aufforderung zur Bestätigung der Email Adresse versendet." -#: members/admin.py:478 +#: members/admin.py:479 msgid "Request mail confirmation from selected registrations" msgstr "Aufforderung zur Bestätigung der Email Adresse versenden" -#: members/admin.py:485 members/admin.py:559 +#: members/admin.py:486 members/admin.py:560 #, python-format msgid "Successfully confirmed %(name)s." msgstr "Registrierung von %(name)s erfolgreich bestätigt." -#: members/admin.py:489 members/admin.py:562 +#: members/admin.py:490 members/admin.py:563 #, 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:494 +#: members/admin.py:495 msgid "Successfully confirmed multiple registrations." msgstr "Erfolgreich mehrere Registrierungen bestätigt." -#: members/admin.py:496 +#: members/admin.py:497 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:497 +#: members/admin.py:498 msgid "Confirm selected registrations" msgstr "Ausgewählte Registrierungen bestätigen" -#: members/admin.py:520 +#: members/admin.py:521 msgid "Demote selected registrations to waiters." msgstr "Ausgewählte Registrierungen zurück auf die Warteliste setzen." -#: members/admin.py:536 +#: members/admin.py:537 msgid "Demote member to waiter" msgstr "Ausgewählte Registrierung zurück auf die Warteliste setzen." -#: members/admin.py:554 +#: members/admin.py:555 #, python-format msgid "Successfully demoted %(name)s to waiter." msgstr "%(name)s zurück auf die Warteliste gesetzt." -#: members/admin.py:569 members/models.py:411 members/models.py:777 -#: members/models.py:1264 +#: members/admin.py:570 members/models.py:411 members/models.py:777 +#: members/models.py:1272 msgid "Group" msgstr "Gruppe" -#: members/admin.py:603 +#: members/admin.py:585 +msgid "Pending group invitation for group" +msgstr "Ausstehende Gruppeneinladung für Gruppe" + +#: members/admin.py:618 #, python-format msgid "Successfully asked %(name)s to confirm their waiting status." msgstr "Erfolgreich %(name)s aufgefordert den Wartelistenplatz zu bestätigen." -#: members/admin.py:604 +#: members/admin.py:619 msgid "Ask selected waiters to confirm their waiting status" msgstr "Wartende auffordern den Wartelistenplatz zu bestätigen" -#: members/admin.py:613 members/admin.py:673 +#: members/admin.py:628 members/admin.py:688 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:617 members/admin.py:678 +#: members/admin.py:632 members/admin.py:693 msgid "" "The selected group does not have a contact email. Please first set a contact " "email and then try again." @@ -205,43 +209,43 @@ msgstr "" "Die ausgewählte Gruppe hat keine Kontakt E-Mail Adresse. Bitte stelle eine " "Kontakt E-Mail Adresse ein und versuche es erneut." -#: members/admin.py:625 members/admin.py:685 +#: members/admin.py:640 members/admin.py:700 #, python-format msgid "Successfully invited %(name)s to %(group)s." msgstr "Erfolgreich %(name)s zu Gruppe %(group)s eingeladen." -#: members/admin.py:629 members/admin.py:691 +#: members/admin.py:644 members/admin.py:706 msgid "Select group for invitation" msgstr "Wähle Gruppe für Einladung aus" -#: members/admin.py:636 +#: members/admin.py:651 msgid "Offer waiter a place in a group." msgstr "Personen auf der Warteliste einen Gruppenplatz anbieten." -#: members/admin.py:708 members/models.py:72 +#: members/admin.py:723 members/models.py:72 msgid "name" msgstr "Name" -#: members/admin.py:709 +#: members/admin.py:724 msgid "" "The group name may only consist of letters, numerals, _, -, :, * and spaces." msgstr "" "Der Gruppenname darf nur aus Buchstaben, Zahlen, _, -, :, * oder Leerzeichen " "bestehen." -#: members/admin.py:738 +#: members/admin.py:753 msgid "Difficulty" msgstr "Schwierigkeit" -#: members/admin.py:741 +#: members/admin.py:756 msgid "Tour type" msgstr "Art der Tour" -#: members/admin.py:744 members/models.py:995 +#: members/admin.py:759 members/models.py:1003 msgid "Means of transportation" msgstr "Verkehrsmittel" -#: members/admin.py:770 +#: members/admin.py:785 msgid "" "Please list here all expenses in relation with this excursion and upload " "relevant bills. These have to be permanently stored for the application of " @@ -254,7 +258,7 @@ msgstr "" "einzelnen Posten wird dabei auf der LJP-Kostenübersicht angezeigt (sinnvoll " "wären z.B. Anreise, Verpflegung, Material etc.)." -#: members/admin.py:788 +#: members/admin.py:803 msgid "" "Here you can work on a seminar report for applying for financial " "contributions from Landesjugendplan (LJP). More information on creating a " @@ -267,7 +271,7 @@ msgstr "" "wahlweise nur TN-Liste und Kostenübersicht kannst du anschließend " "herunterladen." -#: members/admin.py:796 +#: members/admin.py:811 msgid "" "Please list all participants (also youth leaders) of this excursion. Here " "you can still make changes just before departure and hence generate the " @@ -278,34 +282,34 @@ msgstr "" "jederzeit die aktuelle Teilnehmer*innenliste für die Krisenintervention " "generieren." -#: members/admin.py:842 +#: members/admin.py:857 #, python-format msgid "You are not allowed to view all members on note list %(name)s." msgstr "" "Du hast nicht die nötigen Rechte um alle Teilnehmer*innen der Notizliste " "%(name)s anzusehen." -#: members/admin.py:852 +#: members/admin.py:867 msgid "Generate PDF summary" msgstr "Übersicht erstellen" -#: members/admin.py:856 +#: members/admin.py:871 msgid "Full report" msgstr "Vollständiger Seminarbericht" -#: members/admin.py:857 +#: members/admin.py:872 msgid "Costs and participants only" msgstr "Nur Kosten und Teilnehmende" -#: members/admin.py:858 +#: members/admin.py:873 msgid "Mode" msgstr "Modus" -#: members/admin.py:859 +#: members/admin.py:874 msgid "Prepend V32" msgstr "V32 Formblatt einfügen" -#: members/admin.py:875 +#: members/admin.py:890 msgid "" "General information on your excursion. These are partly relevant for the " "amount of financial compensation (means of transport, travel distance, etc.)." @@ -314,48 +318,48 @@ msgstr "" "teilweise relevant für die Zuschüsse aus dem Jugendetat (Verkehrsmittel, " "Fahrstrecke in km)." -#: members/admin.py:905 +#: members/admin.py:920 #, python-format msgid "You are not allowed to view all members on excursion %(name)s." msgstr "" "Du hast nicht die nötigen Rechte um alle Teilnehmer*innen der Ausfahrt " "%(name)s anzusehen." -#: members/admin.py:913 +#: members/admin.py:928 msgid "Generate crisis intervention list" msgstr "Kriseninterventionsliste erstellen" -#: members/admin.py:921 +#: members/admin.py:936 msgid "Generate overview" msgstr "Hinweise für Jugendleiter erstellen" -#: members/admin.py:925 members/admin.py:957 +#: members/admin.py:940 members/admin.py:972 #: members/templates/admin/generate_seminar_report.html:21 msgid "Generate seminar report" msgstr "Landesjugendplan Antrag erstellen" -#: members/admin.py:938 +#: members/admin.py:953 msgid "Please select a mode." msgstr "Bitte wähle einen Modus aus." -#: members/admin.py:943 +#: members/admin.py:958 msgid "" "Full mode is only available, if the seminar report section is filled out." msgstr "" "Der vollständiger Modus ist nur verfügbar, wenn der Seminarbericht " "ausgefüllt ist. " -#: members/admin.py:969 +#: members/admin.py:984 msgid "Generate SJR application" msgstr "SJR Antrag erstellen" -#: members/admin.py:973 +#: members/admin.py:988 msgid "No statement found. Please add a statement and then retry." msgstr "" "Keine Abrechnung angelegt. Bitte lege eine Abrechnung and und versuche es " "erneut." -#: members/admin.py:977 +#: members/admin.py:992 msgid "" "Successfully submited statement. The finance department will notify you as " "soon as possible." @@ -363,7 +367,7 @@ msgstr "" "Abrechnung erfolgreich eingericht. Die Finanzabteilung wird sich bei dir so " "schnell wie möglich melden." -#: members/admin.py:980 +#: members/admin.py:995 #: members/templates/admin/freizeit_finance_overview.html:21 msgid "Finance overview" msgstr "Kostenübersicht" @@ -400,11 +404,11 @@ msgstr "Samstag" msgid "Sunday" msgstr "Sonntag" -#: members/models.py:57 members/models.py:981 +#: members/models.py:57 members/models.py:989 msgid "Description" msgstr "Beschreibung" -#: members/models.py:63 members/models.py:973 +#: members/models.py:63 members/models.py:981 #: members/templates/members/change_member.html:18 msgid "Activity" msgstr "Aktivität" @@ -437,7 +441,7 @@ msgstr "Jugendleiter" msgid "week day" msgstr "Wochentag" -#: members/models.py:80 members/models.py:1346 +#: members/models.py:80 members/models.py:1354 msgid "Starting time" msgstr "Zeitpunkt" @@ -626,8 +630,8 @@ msgstr "Neue unbestätigte Registrierung für Gruppe %(group)s" msgid "Set login data for Kompass" msgstr "Zugangsdaten für Kompass wählen" -#: members/models.py:728 members/models.py:929 members/models.py:940 -#: members/models.py:1295 members/models.py:1302 +#: members/models.py:728 members/models.py:937 members/models.py:948 +#: members/models.py:1303 members/models.py:1310 msgid "Member" msgstr "Teilnehmer*in" @@ -708,240 +712,244 @@ msgstr "Verpasste Erinnerungen" msgid "Waiters" msgstr "Warteliste" -#: members/models.py:846 +#: members/models.py:837 +msgid "Latest group invitation" +msgstr "Letzte Gruppeneinladung" + +#: members/models.py:854 msgid "Waiting status confirmed" msgstr "Wartelistenplatz bestätigt" -#: members/models.py:853 +#: members/models.py:861 msgid "Waiting confirmation needed" msgstr "Wartelistenplatzbestätigung erforderlich" -#: members/models.py:908 +#: members/models.py:916 msgid "Invitation to trial group meeting" msgstr "Einladung zu Schnupperstunde" -#: members/models.py:920 +#: members/models.py:928 msgid "Unregistered from waiting list" msgstr "Von der Warteliste abgemeldet" -#: members/models.py:934 +#: members/models.py:942 msgid "Comment" msgstr "Kommentar" -#: members/models.py:941 members/models.py:1303 +#: members/models.py:949 members/models.py:1311 msgid "Members" msgstr "Teilnehmer*innen" -#: members/models.py:975 +#: members/models.py:983 msgid "Place" msgstr "Stützpunkt / Ort" -#: members/models.py:976 +#: members/models.py:984 msgid "Destination (optional)" msgstr "ggf. Ziel" -#: members/models.py:978 +#: members/models.py:986 msgid "e.g. a peak" msgstr "z.B. ein Gipfel" -#: members/models.py:979 +#: members/models.py:987 msgid "Begin" msgstr "Anfang" -#: members/models.py:980 +#: members/models.py:988 msgid "End (optional)" msgstr "Ende" -#: members/models.py:983 +#: members/models.py:991 msgid "Groups" msgstr "Gruppen" -#: members/models.py:996 +#: members/models.py:1004 msgid "Kilometers traveled" msgstr "Fahrstrecke in Kilometer" -#: members/models.py:999 +#: members/models.py:1007 msgid "Categories" msgstr "Kategorien" -#: members/models.py:1000 +#: members/models.py:1008 msgid "easy" msgstr "leicht" -#: members/models.py:1000 +#: members/models.py:1008 msgid "medium" msgstr "mittel" -#: members/models.py:1000 +#: members/models.py:1008 msgid "hard" msgstr "schwer" -#: members/models.py:1010 members/models.py:1326 +#: members/models.py:1018 members/models.py:1334 #: members/templates/admin/freizeit_finance_overview.html:26 msgid "Excursion" msgstr "Ausfahrt" -#: members/models.py:1011 +#: members/models.py:1019 msgid "Excursions" msgstr "Ausfahrten" -#: members/models.py:1241 members/models.py:1317 members/models.py:1533 +#: members/models.py:1249 members/models.py:1325 members/models.py:1541 msgid "Title" msgstr "Titel" -#: members/models.py:1242 members/models.py:1260 members/models.py:1534 +#: members/models.py:1250 members/models.py:1268 members/models.py:1542 msgid "Date" msgstr "Datum" -#: members/models.py:1261 +#: members/models.py:1269 msgid "Location" msgstr "Ort" -#: members/models.py:1262 +#: members/models.py:1270 msgid "Topic" msgstr "Thema" -#: members/models.py:1286 +#: members/models.py:1294 msgid "Jugendleiter" msgstr "Jugendleiter" -#: members/models.py:1289 +#: members/models.py:1297 msgid "Klettertreff" msgstr "Klettertreff" -#: members/models.py:1290 +#: members/models.py:1298 msgid "Klettertreffs" msgstr "Klettertreffs" -#: members/models.py:1308 +#: members/models.py:1316 msgid "Password" msgstr "Passwort" -#: members/models.py:1311 +#: members/models.py:1319 msgid "registration password" msgstr "Registrierungspassort" -#: members/models.py:1312 +#: members/models.py:1320 msgid "registration passwords" msgstr "Registrierungspasswörter" -#: members/models.py:1319 +#: members/models.py:1327 msgid "Alpinistic goals" msgstr "Alpintechnische Ziele" -#: members/models.py:1320 +#: members/models.py:1328 msgid "Pedagogic goals" msgstr "Pädagogische Ziele" -#: members/models.py:1321 +#: members/models.py:1329 msgid "Content and methods" msgstr "Inhalte und Methoden" -#: members/models.py:1322 +#: members/models.py:1330 msgid "Evaluation" msgstr "Wertung" -#: members/models.py:1323 +#: members/models.py:1331 msgid "Experiences and possible improvements" msgstr "Erfahrungen und Verbesserungsvorschläge" -#: members/models.py:1332 members/models.py:1353 +#: members/models.py:1340 members/models.py:1361 msgid "LJP Proposal" msgstr "Seminarbericht" -#: members/models.py:1333 +#: members/models.py:1341 msgid "LJP Proposals" msgstr "Seminarberichte" -#: members/models.py:1347 +#: members/models.py:1355 msgid "Duration in hours" msgstr "Dauer in Stunden" -#: members/models.py:1350 +#: members/models.py:1358 msgid "Activity and method" msgstr "Art der Aktion inkl. Methode" -#: members/models.py:1358 +#: members/models.py:1366 msgid "Intervention" msgstr "Aktion" -#: members/models.py:1359 +#: members/models.py:1367 msgid "Interventions" msgstr "Aktionen" -#: members/models.py:1461 members/models.py:1491 +#: members/models.py:1469 members/models.py:1499 msgid "May list members" msgstr "Darf folgende Teilnehmer*innen listen" -#: members/models.py:1463 members/models.py:1493 +#: members/models.py:1471 members/models.py:1501 msgid "May view members" msgstr "Darf folgende Teilnehmer*innen anzeigen" -#: members/models.py:1465 members/models.py:1495 +#: members/models.py:1473 members/models.py:1503 msgid "May change members" msgstr "Darf folgende Teilnehmer*innen ändern" -#: members/models.py:1467 members/models.py:1497 +#: members/models.py:1475 members/models.py:1505 msgid "May delete members" msgstr "Darf folgende Teilnehmer*innen löschen" -#: members/models.py:1471 members/models.py:1501 +#: members/models.py:1479 members/models.py:1509 msgid "May list members of groups" msgstr "Darf Teilnehmer*innen folgender Gruppen listen" -#: members/models.py:1473 members/models.py:1503 +#: members/models.py:1481 members/models.py:1511 msgid "May view members of groups" msgstr "Darf Teilnehmer*innen folgender Gruppen anzeigen" -#: members/models.py:1475 members/models.py:1505 +#: members/models.py:1483 members/models.py:1513 msgid "May change members of groups" msgstr "Darf Teilnehmer*innen folgender Gruppen ändern" -#: members/models.py:1477 members/models.py:1507 +#: members/models.py:1485 members/models.py:1515 msgid "May delete members of groups" msgstr "Darf Teilnehmer*innen folgender Gruppen löschen" -#: members/models.py:1480 members/models.py:1481 members/models.py:1484 +#: members/models.py:1488 members/models.py:1489 members/models.py:1492 msgid "Permissions" msgstr "Berechtigungen" -#: members/models.py:1510 members/models.py:1511 members/models.py:1514 +#: members/models.py:1518 members/models.py:1519 members/models.py:1522 msgid "Group permissions" msgstr "Gruppenberechtigungen" -#: members/models.py:1520 +#: members/models.py:1528 msgid "Permission needed" msgstr "Freigabe erforderlich" -#: members/models.py:1523 +#: members/models.py:1531 msgid "Training category" msgstr "Fortbildungstyp" -#: members/models.py:1524 +#: members/models.py:1532 msgid "Training categories" msgstr "Fortbildungstypen" -#: members/models.py:1535 +#: members/models.py:1543 msgid "Category" msgstr "Kategorien" -#: members/models.py:1536 +#: members/models.py:1544 msgid "Comments" msgstr "Kommentar" -#: members/models.py:1537 +#: members/models.py:1545 msgid "Participated" msgstr "Teilgenommmen" -#: members/models.py:1538 +#: members/models.py:1546 msgid "Passed" msgstr "Bestanden" -#: members/models.py:1541 +#: members/models.py:1549 msgid "Training" msgstr "Fortbildung" -#: members/models.py:1542 +#: members/models.py:1550 msgid "Trainings" msgstr "Fortbildungen" diff --git a/jdav_web/members/models.py b/jdav_web/members/models.py index 9f11fd3..8c3d27b 100644 --- a/jdav_web/members/models.py +++ b/jdav_web/members/models.py @@ -828,6 +828,14 @@ class MemberWaitingList(Person): 'delete_obj': has_global_perm('members.delete_global_memberwaitinglist'), } + def latest_group_invitation(self): + gi = self.invitationtogroup_set.order_by('-pk').first() + if gi: + return "{group}: {status}".format(group=gi.group.name, status=gi.status()) + else: + return "-" + latest_group_invitation.short_description = _('Latest group invitation') + @property def waiting_confirmation_needed(self): """Returns if person should be asked to confirm waiting status.""" From c76aebdc186d2691df25dcef5ce5d7f8c3301242 Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Sat, 14 Dec 2024 17:22:51 +0100 Subject: [PATCH 06/10] members/admin: prefetch invitations to group in admin --- jdav_web/members/admin.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/jdav_web/members/admin.py b/jdav_web/members/admin.py index 3bd3653..a4a1f95 100644 --- a/jdav_web/members/admin.py +++ b/jdav_web/members/admin.py @@ -677,6 +677,10 @@ class MemberWaitingListAdmin(CommonAdminMixin, admin.ModelAdmin): ] return custom_urls + urls + def get_queryset(self, request): + queryset = super().get_queryset(request) + return queryset.prefetch_related('invitationtogroup_set') + def invite_view(self, request, object_id): waiter = MemberWaitingList.objects.get(pk=object_id) From 436334f23dcf60e73bcb894a5e657da0fcb99428 Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Sun, 15 Dec 2024 00:46:56 +0100 Subject: [PATCH 07/10] members/admin: show new members section also to non-waitinglist managers --- jdav_web/members/admin.py | 5 +++-- jdav_web/members/models.py | 3 +-- jdav_web/templates/admin/members/app_index.html | 11 ++++++++++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/jdav_web/members/admin.py b/jdav_web/members/admin.py index a4a1f95..45e6868 100644 --- a/jdav_web/members/admin.py +++ b/jdav_web/members/admin.py @@ -407,7 +407,7 @@ class MemberUnconfirmedAdmin(CommonAdminMixin, admin.ModelAdmin): 'comments', 'legal_guardians', 'dav_badge_no', - 'active', 'echoed', + 'echoed', 'user', ] } @@ -440,7 +440,7 @@ class MemberUnconfirmedAdmin(CommonAdminMixin, admin.ModelAdmin): search_fields = ('prename', 'lastname', 'email') list_filter = ('group', 'confirmed_mail', 'confirmed_alternative_mail') readonly_fields = ['confirmed_mail', 'confirmed_alternative_mail', - 'good_conduct_certificate_valid'] + 'good_conduct_certificate_valid', 'echoed'] actions = ['request_mail_confirmation', 'confirm', 'demote_to_waiter_action'] inlines = [EmergencyContactInline] change_form_template = "members/change_member_unconfirmed.html" @@ -454,6 +454,7 @@ class MemberUnconfirmedAdmin(CommonAdminMixin, admin.ModelAdmin): field_change_permissions = { 'user': 'members.may_set_auth_user', + 'group': 'members.may_change_member_group', 'good_conduct_certificate_presented_date': 'members.may_change_organizationals', 'has_key': 'members.may_change_organizationals', 'has_free_ticket_gym': 'members.may_change_organizationals', diff --git a/jdav_web/members/models.py b/jdav_web/members/models.py index 8c3d27b..ad497fd 100644 --- a/jdav_web/members/models.py +++ b/jdav_web/members/models.py @@ -465,8 +465,7 @@ class Member(Person): def registration_ready(self): """Returns if the member is currently unconfirmed and all email addresses are confirmed.""" - return not self.confirmed and self.confirmed_alternative_mail and self.confirmed_mail and\ - all([emc.confirmed_mail for emc in self.emergencycontact_set.all()]) + return not self.confirmed and self.confirmed_alternative_mail and self.confirmed_mail def confirm_mail(self, key): ret = super().confirm_mail(key) diff --git a/jdav_web/templates/admin/members/app_index.html b/jdav_web/templates/admin/members/app_index.html index 9773569..6721797 100644 --- a/jdav_web/templates/admin/members/app_index.html +++ b/jdav_web/templates/admin/members/app_index.html @@ -45,11 +45,12 @@ Hier siehst du alle von dir geleiteten Ausfahrten und für dich sichtbare Teilne -{% if perms.members.may_manage_waiting_list %} +{% if perms.members.view_memberunconfirmedproxy %}

Neue Mitglieder

+{% if perms.member.may_manage_waiting_list %} Hier werden neue Mitglieder verwaltet. Um ein neues Mitglied anzulegen, muss sich die Person anmelden. Daraufhin landet sie auf der Warteliste. Eine @@ -57,8 +58,15 @@ Person auf der Warteliste kannst du dann zu einer Schnupperstunde einer gewählt Diese Einladung enthält einen Registrierungslink zu einem Formular in dem die Person alle ihre Stammdaten eingbit. Diese Daten landen dann unter Unbestätigte Registrierungen. +{% else %} +Hier werden neue Mitglieder verwaltet. Ob über die Warteliste oder über ein Registrierungspasswort, +liegt eine neue Registrierung für eine von dir geleitete Jugendgruppe vor, kannst du die hier einsehen +und die Daten prüfen. Falls die Daten vollständig sind, bestätige die Registrierung um die Person in deine +Jugendgruppe aufzunehmen. +{% endif %}

+ {% if perms.member.may_manage_waiting_list %} + {% endif %}
Warteliste @@ -66,6 +74,7 @@ Stammdaten eingbit. Diese Daten landen dann unter
Unbestätigte Registrierungen From e05555412528dfbbf233cd1a82b506db7e2cedd7 Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Sun, 15 Dec 2024 00:50:26 +0100 Subject: [PATCH 08/10] members/admin: remove redundant sentence --- jdav_web/templates/admin/members/app_index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdav_web/templates/admin/members/app_index.html b/jdav_web/templates/admin/members/app_index.html index 6721797..dacacea 100644 --- a/jdav_web/templates/admin/members/app_index.html +++ b/jdav_web/templates/admin/members/app_index.html @@ -51,7 +51,7 @@ Hier siehst du alle von dir geleiteten Ausfahrten und für dich sichtbare Teilne

Neue Mitglieder

{% if perms.member.may_manage_waiting_list %} -Hier werden neue Mitglieder verwaltet. Um ein neues Mitglied anzulegen, muss sich die Person +Um ein neues Mitglied anzulegen, muss sich die Person anmelden. Daraufhin landet sie auf der Warteliste. Eine Person auf der Warteliste kannst du dann zu einer Schnupperstunde einer gewählten Gruppe einladen. @@ -59,7 +59,7 @@ Diese Einladung enthält einen Registrierungslink zu einem Formular in dem die P Stammdaten eingbit. Diese Daten landen dann unter Unbestätigte Registrierungen. {% else %} -Hier werden neue Mitglieder verwaltet. Ob über die Warteliste oder über ein Registrierungspasswort, +Ob über die Warteliste oder über ein Registrierungspasswort, liegt eine neue Registrierung für eine von dir geleitete Jugendgruppe vor, kannst du die hier einsehen und die Daten prüfen. Falls die Daten vollständig sind, bestätige die Registrierung um die Person in deine Jugendgruppe aufzunehmen. From f87837218e7f50a0e77c8929bf9d48c8fdde2358 Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Sun, 15 Dec 2024 21:35:32 +0100 Subject: [PATCH 09/10] members/waitinglist: preserve waitinglist application date --- jdav_web/members/admin.py | 13 ++--------- ...031_member_waitinglist_application_date.py | 18 +++++++++++++++ jdav_web/members/models.py | 23 +++++++++++++++++++ 3 files changed, 43 insertions(+), 11 deletions(-) create mode 100644 jdav_web/members/migrations/0031_member_waitinglist_application_date.py diff --git a/jdav_web/members/admin.py b/jdav_web/members/admin.py index 45e6868..65fa705 100644 --- a/jdav_web/members/admin.py +++ b/jdav_web/members/admin.py @@ -543,17 +543,8 @@ class MemberUnconfirmedAdmin(CommonAdminMixin, admin.ModelAdmin): def demote_to_waiter(self, request, queryset): for member in queryset: - waiter = MemberWaitingList(prename=member.prename, - lastname=member.lastname, - email=member.email, - birth_date=member.birth_date, - gender=member.gender, - comments=member.comments, - confirmed_mail=member.confirmed_mail, - confirm_mail_key=member.confirm_mail_key) - waiter.save() - member.delete() - messages.success(request, _("Successfully demoted %(name)s to waiter.") % {'name': waiter.name}) + member.demote_to_waiter() + messages.success(request, _("Successfully demoted %(name)s to waiter.") % {'name': member.name}) def response_change(self, request, member): if "_confirm" in request.POST: diff --git a/jdav_web/members/migrations/0031_member_waitinglist_application_date.py b/jdav_web/members/migrations/0031_member_waitinglist_application_date.py new file mode 100644 index 0000000..76e72f7 --- /dev/null +++ b/jdav_web/members/migrations/0031_member_waitinglist_application_date.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.1 on 2024-12-15 18:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('members', '0030_alter_member_options'), + ] + + operations = [ + migrations.AddField( + model_name='member', + name='waitinglist_application_date', + field=models.DateTimeField(blank=True, help_text='If the person registered from the waitinglist, this is their application date.', null=True, verbose_name='waitinglist application date'), + ), + ] diff --git a/jdav_web/members/models.py b/jdav_web/members/models.py index ad497fd..273b92e 100644 --- a/jdav_web/members/models.py +++ b/jdav_web/members/models.py @@ -301,6 +301,9 @@ class Member(Person): user = models.OneToOneField(User, blank=True, null=True, on_delete=models.SET_NULL, verbose_name=_('Login data')) invite_as_user_key = models.CharField(max_length=32, default="") + waitinglist_application_date = models.DateTimeField(verbose_name=_('waitinglist application date'), + null=True, blank=True, + help_text=_('If the person registered from the waitinglist, this is their application date.')) objects = MemberManager() @@ -452,6 +455,9 @@ class Member(Person): if self.email == waiter.email: self.confirmed_mail = waiter.confirmed_mail self.confirm_mail_key = waiter.confirm_mail_key + # store waitinglist application date in member, this will be used + # if the member is later demoted to waiter again + self.waitinglist_application_date = waiter.application_date if self.alternative_email: self.confirmed_alternative_mail = False self.save() @@ -719,6 +725,23 @@ class Member(Person): """Returns a queryset of freizeiten that this member is a youth leader of.""" return Freizeit.objects.filter(jugendleiter__pk=self.pk)[:limit] + def demote_to_waiter(self): + """Demote this member to a waiter by creating a waiter from the data and removing + this member.""" + waiter = MemberWaitingList(prename=self.prename, + lastname=self.lastname, + email=self.email, + birth_date=self.birth_date, + gender=self.gender, + comments=self.comments, + confirmed_mail=self.confirmed_mail, + confirm_mail_key=self.confirm_mail_key) + # if this member was created from the waitinglist, keep the original application date + if self.waitinglist_application_date: + waiter.application_date = self.waitinglist_application_date + waiter.save() + self.delete() + class EmergencyContact(ContactWithPhoneNumber): """ From 58da7fae23ccdade5a303fd6b6a3db31bce08a38 Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Wed, 18 Dec 2024 22:57:51 +0100 Subject: [PATCH 10/10] settings/texts: add space to prevent outlook glitch --- jdav_web/jdav_web/settings/components/texts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdav_web/jdav_web/settings/components/texts.py b/jdav_web/jdav_web/settings/components/texts.py index 68042f8..c2ad0ef 100644 --- a/jdav_web/jdav_web/settings/components/texts.py +++ b/jdav_web/jdav_web/settings/components/texts.py @@ -35,7 +35,7 @@ Bitte kontaktiere die Gruppenleitung ({contact_email}) für alle weiteren Abspra Wenn du nach der Schnupperstunde beschließt der Gruppe beizutreten, benötigen wir noch ein paar Informationen und deine Anmeldebestätigung von dir. Die lädst du herunter -(siehe %(REGISTRATION_FORM_DOWNLOAD_LINK)s), lässt sie von deinen Eltern ausfüllen, unterschreiben +(siehe %(REGISTRATION_FORM_DOWNLOAD_LINK)s ), lässt sie von deinen Eltern ausfüllen, unterschreiben und lädst ein Foto davon in unserem Anmeldeformular hoch. Das kannst du alles über folgenden Link erledigen: {link}