snapshot: preserve auth invite flow and password reset UX cleanup
This commit is contained in:
@@ -1,12 +1,44 @@
|
||||
from django.conf import settings
|
||||
from django.conf.urls.static import static
|
||||
from django.contrib import admin
|
||||
from django.contrib.auth import views as auth_views
|
||||
from django.urls import include, path
|
||||
|
||||
from workflows.forms import AppAuthenticationForm, AppPasswordResetForm, AppSetPasswordForm
|
||||
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
path('i18n/', include('django.conf.urls.i18n')),
|
||||
path('accounts/', include('django.contrib.auth.urls')),
|
||||
path(
|
||||
'accounts/login/',
|
||||
auth_views.LoginView.as_view(template_name='workflows/auth/login.html', authentication_form=AppAuthenticationForm),
|
||||
name='login',
|
||||
),
|
||||
path(
|
||||
'accounts/logout/',
|
||||
auth_views.LogoutView.as_view(),
|
||||
name='logout',
|
||||
),
|
||||
path(
|
||||
'accounts/password_reset/',
|
||||
auth_views.PasswordResetView.as_view(template_name='workflows/auth/password_reset_form.html', form_class=AppPasswordResetForm),
|
||||
name='password_reset',
|
||||
),
|
||||
path(
|
||||
'accounts/password_reset/done/',
|
||||
auth_views.PasswordResetDoneView.as_view(template_name='workflows/auth/password_reset_done.html'),
|
||||
name='password_reset_done',
|
||||
),
|
||||
path(
|
||||
'accounts/reset/<uidb64>/<token>/',
|
||||
auth_views.PasswordResetConfirmView.as_view(template_name='workflows/auth/password_reset_confirm.html', form_class=AppSetPasswordForm),
|
||||
name='password_reset_confirm',
|
||||
),
|
||||
path(
|
||||
'accounts/reset/done/',
|
||||
auth_views.PasswordResetCompleteView.as_view(template_name='workflows/auth/password_reset_complete.html'),
|
||||
name='password_reset_complete',
|
||||
),
|
||||
path('', include('workflows.urls')),
|
||||
]
|
||||
|
||||
|
||||
Binary file not shown.
@@ -2,7 +2,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: tubco-portal\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-26 09:06+0000\n"
|
||||
"POT-Creation-Date: 2026-03-26 09:25+0000\n"
|
||||
"PO-Revision-Date: 2026-03-24 00:00+0000\n"
|
||||
"Language: en\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@@ -55,52 +55,54 @@ msgstr ""
|
||||
msgid "Remote Backup in Nextcloud konnte nicht gelöscht werden."
|
||||
msgstr ""
|
||||
|
||||
#: workflows/forms.py:102
|
||||
msgid "Vorname"
|
||||
msgstr ""
|
||||
|
||||
#: workflows/forms.py:103
|
||||
msgid "Nachname"
|
||||
msgstr ""
|
||||
|
||||
#: workflows/forms.py:104 workflows/templates/workflows/user_management.html:81
|
||||
#: workflows/forms.py:103 workflows/forms.py:128
|
||||
#: workflows/templates/workflows/user_management.html:72
|
||||
msgid "Benutzername"
|
||||
msgstr ""
|
||||
|
||||
#: workflows/forms.py:105
|
||||
#: workflows/forms.py:104
|
||||
msgid "Passwort"
|
||||
msgstr "Password"
|
||||
|
||||
#: workflows/forms.py:108 workflows/forms.py:129
|
||||
#, fuzzy
|
||||
#| msgid "E-Mail"
|
||||
msgid "E-Mail-Adresse"
|
||||
msgstr "Email"
|
||||
|
||||
#: workflows/forms.py:106 workflows/templates/workflows/user_management.html:83
|
||||
#: workflows/templates/workflows/user_management.html:102
|
||||
#: workflows/forms.py:113 workflows/templates/workflows/user_management.html:77
|
||||
#: workflows/templates/workflows/user_management.html:108
|
||||
msgid "Neues Passwort"
|
||||
msgstr "New password"
|
||||
|
||||
#: workflows/forms.py:119
|
||||
msgid "Neues Passwort bestätigen"
|
||||
msgstr "Confirm new password"
|
||||
|
||||
#: workflows/forms.py:126
|
||||
msgid "Vorname"
|
||||
msgstr ""
|
||||
|
||||
#: workflows/forms.py:127
|
||||
msgid "Nachname"
|
||||
msgstr ""
|
||||
|
||||
#: workflows/forms.py:130 workflows/templates/workflows/user_management.html:74
|
||||
#: workflows/templates/workflows/user_management.html:93
|
||||
#, fuzzy
|
||||
#| msgid "Rolle:"
|
||||
msgid "Rolle"
|
||||
msgstr "Role:"
|
||||
|
||||
#: workflows/forms.py:107
|
||||
msgid "Passwort"
|
||||
msgstr "Password"
|
||||
|
||||
#: workflows/forms.py:108
|
||||
msgid "Passwort bestätigen"
|
||||
msgstr "Confirm password"
|
||||
|
||||
#: workflows/forms.py:121
|
||||
#: workflows/forms.py:143
|
||||
msgid "Dieser Benutzername ist bereits vergeben."
|
||||
msgstr "This username is already taken."
|
||||
|
||||
#: workflows/forms.py:130 workflows/views.py:433
|
||||
#: workflows/forms.py:152 workflows/views.py:472
|
||||
msgid "Ungültige Rolle."
|
||||
msgstr "Invalid role."
|
||||
|
||||
#: workflows/forms.py:138
|
||||
msgid "Die Passwörter stimmen nicht überein."
|
||||
msgstr "The passwords do not match."
|
||||
|
||||
#: workflows/forms.py:394
|
||||
#: workflows/forms.py:408
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Das Übergabedatum muss mindestens %(days)s Tage in der Zukunft liegen "
|
||||
@@ -465,28 +467,129 @@ msgstr "Handover / successor context reviewed: %(value)s"
|
||||
|
||||
#: workflows/templates/registration/login.html:4
|
||||
#: workflows/templates/registration/login.html:19
|
||||
#: workflows/templates/workflows/auth/login.html:4
|
||||
#: workflows/templates/workflows/auth/login.html:17
|
||||
msgid "Anmeldung"
|
||||
msgstr "Sign in"
|
||||
|
||||
#: workflows/templates/registration/login.html:20
|
||||
#: workflows/templates/workflows/auth/login.html:18
|
||||
msgid "Bitte melden Sie sich mit Ihrem Benutzerkonto an."
|
||||
msgstr "Please sign in with your user account."
|
||||
|
||||
#: workflows/templates/registration/login.html:30
|
||||
#: workflows/templates/workflows/auth/login.html:28
|
||||
#, fuzzy
|
||||
#| msgid "Fehlgeschlagen"
|
||||
msgid "Anmeldung fehlgeschlagen"
|
||||
msgstr "Failed"
|
||||
|
||||
#: workflows/templates/registration/login.html:31
|
||||
#: workflows/templates/workflows/auth/login.html:29
|
||||
msgid ""
|
||||
"Benutzername oder Passwort sind nicht korrekt. Bitte versuchen Sie es erneut."
|
||||
msgstr ""
|
||||
|
||||
#: workflows/templates/registration/login.html:37
|
||||
#: workflows/templates/workflows/auth/login.html:35
|
||||
msgid "Anmelden"
|
||||
msgstr "Sign in"
|
||||
|
||||
#: workflows/templates/registration/password_reset_complete.html:4
|
||||
#: workflows/templates/registration/password_reset_complete.html:17
|
||||
#: workflows/templates/workflows/auth/password_reset_complete.html:4
|
||||
#: workflows/templates/workflows/auth/password_reset_complete.html:17
|
||||
msgid "Passwort gespeichert"
|
||||
msgstr "Password saved"
|
||||
|
||||
#: workflows/templates/registration/password_reset_complete.html:18
|
||||
#: workflows/templates/workflows/auth/password_reset_complete.html:18
|
||||
msgid ""
|
||||
"Ihr Passwort wurde erfolgreich gesetzt. Sie können sich jetzt mit Ihrem "
|
||||
"Benutzerkonto anmelden."
|
||||
msgstr "Your password has been set successfully. You can now sign in with your account."
|
||||
|
||||
#: workflows/templates/registration/password_reset_complete.html:19
|
||||
#: workflows/templates/registration/password_reset_confirm.html:41
|
||||
#: workflows/templates/registration/password_reset_done.html:19
|
||||
#: workflows/templates/workflows/auth/password_reset_complete.html:19
|
||||
#: workflows/templates/workflows/auth/password_reset_confirm.html:44
|
||||
#: workflows/templates/workflows/auth/password_reset_done.html:19
|
||||
msgid "Zur Anmeldung"
|
||||
msgstr "Back to sign in"
|
||||
|
||||
#: workflows/templates/registration/password_reset_confirm.html:4
|
||||
#: workflows/templates/registration/password_reset_confirm.html:18
|
||||
#: workflows/templates/workflows/auth/password_reset_confirm.html:4
|
||||
#: workflows/templates/workflows/auth/password_reset_confirm.html:18
|
||||
msgid "Passwort festlegen"
|
||||
msgstr "Set password"
|
||||
|
||||
#: workflows/templates/registration/password_reset_confirm.html:19
|
||||
#: workflows/templates/workflows/auth/password_reset_confirm.html:19
|
||||
msgid "Bitte vergeben Sie jetzt ein neues Passwort für Ihr Konto."
|
||||
msgstr "Please set a new password for your account now."
|
||||
|
||||
#: workflows/templates/registration/password_reset_confirm.html:25
|
||||
#: workflows/templates/workflows/auth/password_reset_confirm.html:25
|
||||
msgid "Passwort konnte nicht gespeichert werden"
|
||||
msgstr "Password could not be saved"
|
||||
|
||||
#: workflows/templates/registration/password_reset_confirm.html:26
|
||||
#: workflows/templates/workflows/auth/password_reset_confirm.html:26
|
||||
msgid "Bitte prüfen Sie die beiden Passwortfelder und versuchen Sie es erneut."
|
||||
msgstr "Please check both password fields and try again."
|
||||
|
||||
#: workflows/templates/registration/password_reset_confirm.html:36
|
||||
#: workflows/templates/workflows/auth/password_reset_confirm.html:39
|
||||
msgid "Passwort speichern"
|
||||
msgstr "Save password"
|
||||
|
||||
#: workflows/templates/registration/password_reset_confirm.html:39
|
||||
#: workflows/templates/workflows/auth/password_reset_confirm.html:42
|
||||
msgid "Link ungültig"
|
||||
msgstr "Invalid link"
|
||||
|
||||
#: workflows/templates/registration/password_reset_confirm.html:40
|
||||
#: workflows/templates/workflows/auth/password_reset_confirm.html:43
|
||||
msgid ""
|
||||
"Dieser Link ist nicht mehr gültig. Bitte fordern Sie einen neuen Passwort-"
|
||||
"Link an."
|
||||
msgstr "This link is no longer valid. Please request a new password link."
|
||||
|
||||
#: workflows/templates/registration/password_reset_done.html:4
|
||||
#: workflows/templates/registration/password_reset_done.html:17
|
||||
#: workflows/templates/workflows/auth/password_reset_done.html:4
|
||||
#: workflows/templates/workflows/auth/password_reset_done.html:17
|
||||
msgid "E-Mail versendet"
|
||||
msgstr "Email sent"
|
||||
|
||||
#: workflows/templates/registration/password_reset_done.html:18
|
||||
#: workflows/templates/workflows/auth/password_reset_done.html:18
|
||||
msgid ""
|
||||
"Wenn ein passendes Konto existiert, wurde ein Passwort-Link an die "
|
||||
"hinterlegte E-Mail-Adresse verschickt."
|
||||
msgstr "If a matching account exists, a password link has been sent to the stored email address."
|
||||
|
||||
#: workflows/templates/registration/password_reset_form.html:4
|
||||
#: workflows/templates/registration/password_reset_form.html:17
|
||||
#: workflows/templates/workflows/auth/password_reset_form.html:4
|
||||
#: workflows/templates/workflows/auth/password_reset_form.html:17
|
||||
msgid "Passwort zurücksetzen"
|
||||
msgstr "Reset password"
|
||||
|
||||
#: workflows/templates/registration/password_reset_form.html:18
|
||||
#: workflows/templates/workflows/auth/password_reset_form.html:18
|
||||
msgid ""
|
||||
"Geben Sie Ihre E-Mail-Adresse ein. Wenn ein Konto vorhanden ist, erhalten "
|
||||
"Sie einen Passwort-Link."
|
||||
msgstr "Enter your email address. If an account exists, you will receive a password link."
|
||||
|
||||
#: workflows/templates/registration/password_reset_form.html:24
|
||||
#: workflows/templates/workflows/auth/password_reset_form.html:25
|
||||
msgid "Link anfordern"
|
||||
msgstr "Request link"
|
||||
|
||||
#: workflows/templates/workflows/audit_log.html:4
|
||||
#: workflows/templates/workflows/audit_log.html:15
|
||||
#: workflows/templates/workflows/home.html:132
|
||||
@@ -596,7 +699,7 @@ msgid ""
|
||||
msgstr "Create database and media backups and verify existing bundles safely."
|
||||
|
||||
#: workflows/templates/workflows/backup_recovery.html:20
|
||||
#: workflows/templates/workflows/user_management.html:87
|
||||
#: workflows/templates/workflows/user_management.html:78
|
||||
msgid "Aktionen"
|
||||
msgstr "Actions"
|
||||
|
||||
@@ -716,7 +819,7 @@ msgstr "Delete this backup bundle?"
|
||||
#: workflows/templates/workflows/intro_builder.html:66
|
||||
#: workflows/templates/workflows/intro_builder.html:102
|
||||
#: workflows/templates/workflows/requests_dashboard.html:286
|
||||
#: workflows/templates/workflows/user_management.html:136
|
||||
#: workflows/templates/workflows/user_management.html:127
|
||||
#: workflows/templates/workflows/welcome_emails.html:70
|
||||
msgid "Löschen"
|
||||
msgstr "Delete"
|
||||
@@ -817,7 +920,7 @@ msgstr "Label (EN)"
|
||||
#: workflows/templates/workflows/form_builder.html:91
|
||||
#: workflows/templates/workflows/integrations_setup.html:263
|
||||
#: workflows/templates/workflows/intro_builder.html:65
|
||||
#: workflows/templates/workflows/user_management.html:84
|
||||
#: workflows/templates/workflows/user_management.html:75
|
||||
msgid "Aktiv"
|
||||
msgstr "Active"
|
||||
|
||||
@@ -1033,13 +1136,13 @@ msgstr "Nextcloud:"
|
||||
|
||||
#: workflows/templates/workflows/home.html:40
|
||||
#: workflows/templates/workflows/integrations_setup.html:60
|
||||
#: workflows/templates/workflows/user_management.html:112
|
||||
#: workflows/templates/workflows/user_management.html:103
|
||||
msgid "aktiv"
|
||||
msgstr "active"
|
||||
|
||||
#: workflows/templates/workflows/home.html:40
|
||||
#: workflows/templates/workflows/integrations_setup.html:60
|
||||
#: workflows/templates/workflows/user_management.html:112
|
||||
#: workflows/templates/workflows/user_management.html:103
|
||||
msgid "inaktiv"
|
||||
msgstr "inactive"
|
||||
|
||||
@@ -1774,7 +1877,7 @@ msgstr "Employee"
|
||||
|
||||
#: workflows/templates/workflows/onboarding_intro_session.html:27
|
||||
#: workflows/templates/workflows/request_timeline.html:66
|
||||
#: workflows/templates/workflows/user_management.html:80
|
||||
#: workflows/templates/workflows/user_management.html:71
|
||||
msgid "Name"
|
||||
msgstr "Name"
|
||||
|
||||
@@ -1787,7 +1890,7 @@ msgid "Dienstliche E-Mail"
|
||||
msgstr "Work email"
|
||||
|
||||
#: workflows/templates/workflows/onboarding_intro_session.html:31
|
||||
#: workflows/views.py:688
|
||||
#: workflows/views.py:708
|
||||
msgid "Vertragsbeginn"
|
||||
msgstr "Contract start"
|
||||
|
||||
@@ -2047,7 +2150,7 @@ msgstr ""
|
||||
|
||||
#: workflows/templates/workflows/request_timeline.html:74
|
||||
#: workflows/templates/workflows/requests_dashboard.html:190
|
||||
#: workflows/templates/workflows/user_management.html:82
|
||||
#: workflows/templates/workflows/user_management.html:73
|
||||
msgid "E-Mail"
|
||||
msgstr "Email"
|
||||
|
||||
@@ -2234,60 +2337,63 @@ msgstr "Super admins manage user accounts, roles, and active access."
|
||||
msgid "Benutzer anlegen"
|
||||
msgstr "Create user"
|
||||
|
||||
#: workflows/templates/workflows/user_management.html:64
|
||||
msgid "Benutzer erstellen"
|
||||
#: workflows/templates/workflows/user_management.html:23
|
||||
msgid ""
|
||||
"Nach dem Anlegen wird automatisch eine Zugangseinladung mit Passwort-Link "
|
||||
"per E-Mail versendet."
|
||||
msgstr ""
|
||||
|
||||
#: workflows/templates/workflows/user_management.html:55
|
||||
#, fuzzy
|
||||
#| msgid "Benutzer anlegen"
|
||||
msgid "Benutzer anlegen und einladen"
|
||||
msgstr "Create user"
|
||||
|
||||
#: workflows/templates/workflows/user_management.html:72
|
||||
#: workflows/templates/workflows/user_management.html:63
|
||||
msgid "Benutzerübersicht"
|
||||
msgstr "User overview"
|
||||
|
||||
#: workflows/templates/workflows/user_management.html:73
|
||||
#: workflows/templates/workflows/user_management.html:64
|
||||
msgid "Rollen ändern, Zugriffe sperren oder ein neues Passwort setzen."
|
||||
msgstr "Change roles, block access, or set a new password."
|
||||
|
||||
#: workflows/templates/workflows/user_management.html:85
|
||||
#: workflows/templates/workflows/user_management.html:76
|
||||
msgid "Letzte Anmeldung"
|
||||
msgstr "Last login"
|
||||
|
||||
#: workflows/templates/workflows/user_management.html:86
|
||||
#: workflows/templates/workflows/user_management.html:117
|
||||
msgid "Neues Passwort"
|
||||
msgstr "New password"
|
||||
|
||||
#: workflows/templates/workflows/user_management.html:96
|
||||
#: workflows/templates/workflows/user_management.html:87
|
||||
msgid "Sie selbst"
|
||||
msgstr "You"
|
||||
|
||||
#: workflows/templates/workflows/user_management.html:118
|
||||
#: workflows/templates/workflows/user_management.html:109
|
||||
msgid "Optional"
|
||||
msgstr "Optional"
|
||||
|
||||
#: workflows/templates/workflows/user_management.html:124
|
||||
#: workflows/templates/workflows/user_management.html:115
|
||||
msgid "Speichern"
|
||||
msgstr "Save"
|
||||
|
||||
#: workflows/templates/workflows/user_management.html:128
|
||||
#: workflows/templates/workflows/user_management.html:119
|
||||
msgid "Reset-Link senden"
|
||||
msgstr ""
|
||||
|
||||
#: workflows/templates/workflows/user_management.html:131
|
||||
#: workflows/templates/workflows/user_management.html:122
|
||||
#, fuzzy
|
||||
#| msgid "Welcome E-Mails"
|
||||
msgid "Keine E-Mail"
|
||||
msgstr "Welcome Emails"
|
||||
|
||||
#: workflows/templates/workflows/user_management.html:136
|
||||
#: workflows/templates/workflows/user_management.html:127
|
||||
#, fuzzy
|
||||
#| msgid "Option wirklich löschen?"
|
||||
msgid "Benutzer wirklich löschen?"
|
||||
msgstr "Delete this option?"
|
||||
|
||||
#: workflows/templates/workflows/user_management.html:143
|
||||
#: workflows/templates/workflows/user_management.html:134
|
||||
msgid "Es sind noch keine Benutzer vorhanden."
|
||||
msgstr "No users exist yet."
|
||||
|
||||
#: workflows/templates/workflows/user_management.html:149
|
||||
#: workflows/templates/workflows/user_management.html:140
|
||||
msgid ""
|
||||
"Hinweis: Der aktuell angemeldete Super Admin kann sich hier nicht selbst "
|
||||
"deaktivieren oder auf eine niedrigere Rolle setzen."
|
||||
@@ -2397,7 +2503,7 @@ msgstr "Devices, software, and access"
|
||||
msgid "Notizen und Freigabe"
|
||||
msgstr "Notes and approval"
|
||||
|
||||
#: workflows/views.py:128 workflows/views.py:774 workflows/views.py:779
|
||||
#: workflows/views.py:128 workflows/views.py:794 workflows/views.py:799
|
||||
msgid "Sie haben keine Berechtigung für diese Aktion."
|
||||
msgstr "You do not have permission for this action."
|
||||
|
||||
@@ -2609,48 +2715,35 @@ msgstr "Request saved"
|
||||
msgid "Backup-Einstellungen gespeichert"
|
||||
msgstr "Save welcome settings"
|
||||
|
||||
#: workflows/views.py:407
|
||||
msgid "Benutzer konnte nicht erstellt werden. Bitte prüfen Sie die Eingaben."
|
||||
msgstr "User could not be created. Please check the input."
|
||||
|
||||
#: workflows/views.py:419
|
||||
#, python-format
|
||||
msgid "Benutzer wurde erstellt: %(username)s"
|
||||
msgstr "User created: %(username)s"
|
||||
|
||||
#: workflows/views.py:437
|
||||
msgid ""
|
||||
"Der aktuell angemeldete Super Admin kann sich hier nicht selbst sperren oder "
|
||||
"herabstufen."
|
||||
msgstr ""
|
||||
"The currently signed-in super admin cannot lock or downgrade themselves here."
|
||||
|
||||
#: workflows/views.py:440
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "Der aktuell angemeldete Super Admin kann sich hier nicht selbst sperren "
|
||||
#| "oder herabstufen."
|
||||
msgid ""
|
||||
"Der letzte aktive Super Admin kann nicht deaktiviert oder herabgestuft "
|
||||
"werden."
|
||||
msgstr ""
|
||||
"The currently signed-in super admin cannot lock or downgrade themselves here."
|
||||
|
||||
#: workflows/views.py:457
|
||||
#, python-format
|
||||
msgid "Benutzer wurde aktualisiert: %(username)s"
|
||||
msgstr "User updated: %(username)s"
|
||||
|
||||
#: workflows/views.py:468
|
||||
#: workflows/views.py:400
|
||||
msgid "Für diesen Benutzer ist keine E-Mail-Adresse hinterlegt."
|
||||
msgstr ""
|
||||
|
||||
#: workflows/views.py:477
|
||||
#: workflows/views.py:408
|
||||
#, python-format
|
||||
msgid "Zugangseinladung für %(username)s"
|
||||
msgstr ""
|
||||
|
||||
#: workflows/views.py:410
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Hallo %(name)s,\n"
|
||||
"\n"
|
||||
"für Sie wurde ein Benutzerkonto im TUBCO Onboarding- und Offboarding-Portal "
|
||||
"angelegt.\n"
|
||||
"Bitte öffnen Sie den folgenden Link, um Ihr Passwort zu setzen:\n"
|
||||
"%(url)s\n"
|
||||
"\n"
|
||||
"Wenn Sie diese Einladung nicht erwartet haben, melden Sie sich bitte bei "
|
||||
"Ihrem Administrator."
|
||||
msgstr ""
|
||||
|
||||
#: workflows/views.py:420
|
||||
#, python-format
|
||||
msgid "Passwort zurücksetzen für %(username)s"
|
||||
msgstr ""
|
||||
|
||||
#: workflows/views.py:479
|
||||
#: workflows/views.py:422
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Hallo %(name)s,\n"
|
||||
@@ -2663,13 +2756,46 @@ msgid ""
|
||||
"ignorieren."
|
||||
msgstr ""
|
||||
|
||||
#: workflows/views.py:498
|
||||
#: workflows/views.py:445
|
||||
msgid "Benutzer konnte nicht erstellt werden. Bitte prüfen Sie die Eingaben."
|
||||
msgstr "User could not be created. Please check the input."
|
||||
|
||||
#: workflows/views.py:458
|
||||
#, fuzzy, python-format
|
||||
#| msgid "Benutzer wurde erstellt: %(username)s"
|
||||
msgid "Benutzer wurde erstellt und eingeladen: %(username)s"
|
||||
msgstr "User created: %(username)s"
|
||||
|
||||
#: workflows/views.py:476
|
||||
msgid ""
|
||||
"Der aktuell angemeldete Super Admin kann sich hier nicht selbst sperren oder "
|
||||
"herabstufen."
|
||||
msgstr ""
|
||||
"The currently signed-in super admin cannot lock or downgrade themselves here."
|
||||
|
||||
#: workflows/views.py:479
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "Der aktuell angemeldete Super Admin kann sich hier nicht selbst sperren "
|
||||
#| "oder herabstufen."
|
||||
msgid ""
|
||||
"Der letzte aktive Super Admin kann nicht deaktiviert oder herabgestuft "
|
||||
"werden."
|
||||
msgstr ""
|
||||
"The currently signed-in super admin cannot lock or downgrade themselves here."
|
||||
|
||||
#: workflows/views.py:496
|
||||
#, python-format
|
||||
msgid "Benutzer wurde aktualisiert: %(username)s"
|
||||
msgstr "User updated: %(username)s"
|
||||
|
||||
#: workflows/views.py:518
|
||||
#, fuzzy, python-format
|
||||
#| msgid "Benutzer wurde erstellt: %(username)s"
|
||||
msgid "Passwort-Reset-Link wurde versendet: %(username)s"
|
||||
msgstr "User created: %(username)s"
|
||||
|
||||
#: workflows/views.py:509
|
||||
#: workflows/views.py:529
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "Der aktuell angemeldete Super Admin kann sich hier nicht selbst sperren "
|
||||
@@ -2679,7 +2805,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"The currently signed-in super admin cannot lock or downgrade themselves here."
|
||||
|
||||
#: workflows/views.py:512
|
||||
#: workflows/views.py:532
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "Der aktuell angemeldete Super Admin kann sich hier nicht selbst sperren "
|
||||
@@ -2688,124 +2814,130 @@ msgid "Der letzte aktive Super Admin kann nicht gelöscht werden."
|
||||
msgstr ""
|
||||
"The currently signed-in super admin cannot lock or downgrade themselves here."
|
||||
|
||||
#: workflows/views.py:525
|
||||
#: workflows/views.py:545
|
||||
#, fuzzy, python-format
|
||||
#| msgid "Benutzer wurde erstellt: %(username)s"
|
||||
msgid "Benutzer wurde gelöscht: %(username)s"
|
||||
msgstr "User created: %(username)s"
|
||||
|
||||
#: workflows/views.py:612
|
||||
#: workflows/views.py:632
|
||||
#, python-format
|
||||
msgid "Backup wurde erstellt: %(name)s"
|
||||
msgstr ""
|
||||
|
||||
#: workflows/views.py:614
|
||||
#: workflows/views.py:634
|
||||
#, python-format
|
||||
msgid "Backup konnte nicht erstellt werden: %(error)s"
|
||||
msgstr ""
|
||||
|
||||
#: workflows/views.py:630
|
||||
#: workflows/views.py:650
|
||||
#, python-format
|
||||
msgid "Backup wurde verifiziert: %(name)s"
|
||||
msgstr ""
|
||||
|
||||
#: workflows/views.py:632
|
||||
#: workflows/views.py:652
|
||||
#, python-format
|
||||
msgid "Backup-Verifikation fehlgeschlagen: %(error)s"
|
||||
msgstr ""
|
||||
|
||||
#: workflows/views.py:648
|
||||
#: workflows/views.py:668
|
||||
#, python-format
|
||||
msgid "Backup wurde gelöscht: %(name)s"
|
||||
msgstr ""
|
||||
|
||||
#: workflows/views.py:650
|
||||
#: workflows/views.py:670
|
||||
#, python-format
|
||||
msgid "Backup konnte nicht gelöscht werden: %(error)s"
|
||||
msgstr ""
|
||||
|
||||
#: workflows/views.py:676
|
||||
#: workflows/views.py:696
|
||||
#, fuzzy
|
||||
#| msgid "Anfrage gespeichert"
|
||||
msgid "Anfrage erstellt"
|
||||
msgstr "Request saved"
|
||||
|
||||
#: workflows/views.py:678
|
||||
#: workflows/views.py:698
|
||||
#, fuzzy, python-format
|
||||
#| msgid "Sitzungsstatus"
|
||||
msgid "Status: %(status)s"
|
||||
msgstr "Session status"
|
||||
|
||||
#: workflows/views.py:690
|
||||
#: workflows/views.py:710
|
||||
#, fuzzy
|
||||
#| msgid "Geplant für"
|
||||
msgid "Geplanter Start"
|
||||
msgstr "Scheduled for"
|
||||
|
||||
#: workflows/views.py:700
|
||||
#: workflows/views.py:720
|
||||
msgid "Geräteübergabe / Hardware-Abholung"
|
||||
msgstr ""
|
||||
|
||||
#: workflows/views.py:702
|
||||
#: workflows/views.py:722
|
||||
msgid "Geplanter Hardware-Termin"
|
||||
msgstr ""
|
||||
|
||||
#: workflows/views.py:711
|
||||
#: workflows/views.py:731
|
||||
#, fuzzy
|
||||
#| msgid "Noch nicht verfügbar"
|
||||
msgid "PDF verfügbar"
|
||||
msgstr "Not available yet"
|
||||
|
||||
#: workflows/views.py:737
|
||||
#: workflows/views.py:757
|
||||
#, fuzzy
|
||||
#| msgid "Einweisung"
|
||||
msgid "Einweisungssitzung"
|
||||
msgstr "Introduction"
|
||||
|
||||
#: workflows/views.py:749
|
||||
#: workflows/views.py:769
|
||||
#, fuzzy
|
||||
#| msgid "Welcome E-Mails"
|
||||
msgid "Welcome E-Mail"
|
||||
msgstr "Welcome Emails"
|
||||
|
||||
#: workflows/views.py:788
|
||||
#: workflows/views.py:808
|
||||
msgid "Keine Einträge ausgewählt."
|
||||
msgstr "No entries selected."
|
||||
|
||||
#: workflows/views.py:831
|
||||
#: workflows/views.py:851
|
||||
#, python-format
|
||||
msgid "%(count)s Eintrag/Einträge gelöscht."
|
||||
msgstr "%(count)s entry/entries deleted."
|
||||
|
||||
#: workflows/views.py:833
|
||||
#: workflows/views.py:853
|
||||
#, python-format
|
||||
msgid "%(count)s Auswahl(en) konnten nicht verarbeitet werden."
|
||||
msgstr "%(count)s selection(s) could not be processed."
|
||||
|
||||
#: workflows/views.py:835
|
||||
#: workflows/views.py:855
|
||||
msgid "Keine passenden Einträge gefunden."
|
||||
msgstr "No matching entries found."
|
||||
|
||||
#: workflows/views.py:1062
|
||||
#: workflows/views.py:1082
|
||||
msgid "Einweisungs- und Übergabeprotokoll wurde erzeugt."
|
||||
msgstr "Introduction and handover protocol was generated."
|
||||
|
||||
#: workflows/views.py:1079
|
||||
#: workflows/views.py:1099
|
||||
msgid "Einweisungsprotokoll aus Live-Status wurde erzeugt."
|
||||
msgstr "Introduction protocol from live status was generated."
|
||||
|
||||
#: workflows/views.py:1108
|
||||
#: workflows/views.py:1128
|
||||
msgid "Einweisung wurde zurückgesetzt."
|
||||
msgstr "Introduction was reset."
|
||||
|
||||
#: workflows/views.py:1122
|
||||
#: workflows/views.py:1142
|
||||
msgid "Einweisung wurde als abgeschlossen gespeichert."
|
||||
msgstr "Introduction was saved as completed."
|
||||
|
||||
#: workflows/views.py:1135
|
||||
#: workflows/views.py:1155
|
||||
msgid "Einweisung wurde als Entwurf gespeichert."
|
||||
msgstr "Introduction was saved as draft."
|
||||
|
||||
#~ msgid "Die Passwörter stimmen nicht überein."
|
||||
#~ msgstr "The passwords do not match."
|
||||
|
||||
#~ msgid "Benutzer erstellen"
|
||||
#~ msgstr "Create user"
|
||||
|
||||
#~ msgid "Backup läuft"
|
||||
#~ msgstr "Backup in progress"
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
from django import forms
|
||||
from pathlib import Path
|
||||
from datetime import timedelta
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth import get_user_model, password_validation
|
||||
from django.contrib.auth.forms import AuthenticationForm, PasswordResetForm, SetPasswordForm
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import get_language, gettext as _
|
||||
from django.utils.translation import get_language, gettext as _, gettext_lazy
|
||||
|
||||
from .form_builder import apply_form_field_config
|
||||
from .models import EmployeeProfile, FormOption, OffboardingRequest, OnboardingRequest, WorkflowConfig
|
||||
@@ -98,14 +99,35 @@ HARDWARE_EXTRA_CHOICES = [('Smartphone', 'Smartphone'), ('Anderes', 'Anderes')]
|
||||
SOFTWARE_EXTRA_CHOICES = [('Adobe Acrobat Pro (Abonnement: Zusätzliche Kosten)', 'Adobe Acrobat Pro (Abonnement: Zusätzliche Kosten)'), ('Anderes', 'Anderes')]
|
||||
|
||||
|
||||
class AppAuthenticationForm(AuthenticationForm):
|
||||
username = forms.CharField(label=gettext_lazy('Benutzername'))
|
||||
password = forms.CharField(label=gettext_lazy('Passwort'), strip=False, widget=forms.PasswordInput(attrs={'autocomplete': 'current-password'}))
|
||||
|
||||
|
||||
class AppPasswordResetForm(PasswordResetForm):
|
||||
email = forms.EmailField(label=gettext_lazy('E-Mail-Adresse'))
|
||||
|
||||
|
||||
class AppSetPasswordForm(SetPasswordForm):
|
||||
new_password1 = forms.CharField(
|
||||
label=gettext_lazy('Neues Passwort'),
|
||||
strip=False,
|
||||
widget=forms.PasswordInput(attrs={'autocomplete': 'new-password'}),
|
||||
help_text=password_validation.password_validators_help_text_html(),
|
||||
)
|
||||
new_password2 = forms.CharField(
|
||||
label=gettext_lazy('Neues Passwort bestätigen'),
|
||||
strip=False,
|
||||
widget=forms.PasswordInput(attrs={'autocomplete': 'new-password'}),
|
||||
)
|
||||
|
||||
|
||||
class UserManagementCreateForm(forms.Form):
|
||||
first_name = forms.CharField(label=_('Vorname'), max_length=150, required=False)
|
||||
last_name = forms.CharField(label=_('Nachname'), max_length=150, required=False)
|
||||
username = forms.CharField(label=_('Benutzername'), max_length=150)
|
||||
email = forms.EmailField(label=_('E-Mail-Adresse'))
|
||||
role_key = forms.ChoiceField(label=_('Rolle'))
|
||||
password1 = forms.CharField(label=_('Passwort'), widget=forms.PasswordInput())
|
||||
password2 = forms.CharField(label=_('Passwort bestätigen'), widget=forms.PasswordInput())
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
@@ -130,20 +152,12 @@ class UserManagementCreateForm(forms.Form):
|
||||
raise forms.ValidationError(_('Ungültige Rolle.'))
|
||||
return role_key
|
||||
|
||||
def clean(self):
|
||||
cleaned = super().clean()
|
||||
password1 = cleaned.get('password1')
|
||||
password2 = cleaned.get('password2')
|
||||
if password1 and password2 and password1 != password2:
|
||||
self.add_error('password2', _('Die Passwörter stimmen nicht überein.'))
|
||||
return cleaned
|
||||
|
||||
def save(self):
|
||||
user_model = get_user_model()
|
||||
user = user_model.objects.create_user(
|
||||
username=self.cleaned_data['username'],
|
||||
email=self.cleaned_data['email'],
|
||||
password=self.cleaned_data['password1'],
|
||||
password=None,
|
||||
first_name=self.cleaned_data.get('first_name', ''),
|
||||
last_name=self.cleaned_data.get('last_name', ''),
|
||||
is_active=True,
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
{% extends 'workflows/base_shell.html' %}
|
||||
{% load static i18n %}
|
||||
|
||||
{% block title %}{% trans "Passwort gespeichert" %}{% endblock %}
|
||||
|
||||
{% block shell_header %}
|
||||
{% include 'workflows/includes/app_header.html' with header_inside_shell=1 %}
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{% static 'workflows/css/login.css' %}" />
|
||||
{% endblock %}
|
||||
|
||||
{% block shell_body %}
|
||||
<section class="login-shell-body">
|
||||
<div class="login-card">
|
||||
<h1>{% trans "Passwort gespeichert" %}</h1>
|
||||
<p>{% trans "Ihr Passwort wurde erfolgreich gesetzt. Sie können sich jetzt mit Ihrem Benutzerkonto anmelden." %}</p>
|
||||
<a class="btn btn-primary" href="/accounts/login/">{% trans "Zur Anmeldung" %}</a>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,45 @@
|
||||
{% extends 'workflows/base_shell.html' %}
|
||||
{% load static i18n %}
|
||||
|
||||
{% block title %}{% trans "Passwort festlegen" %}{% endblock %}
|
||||
|
||||
{% block shell_header %}
|
||||
{% include 'workflows/includes/app_header.html' with header_inside_shell=1 %}
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{% static 'workflows/css/login.css' %}" />
|
||||
{% endblock %}
|
||||
|
||||
{% block shell_body %}
|
||||
<section class="login-shell-body">
|
||||
<div class="login-card">
|
||||
{% if validlink %}
|
||||
<h1>{% trans "Passwort festlegen" %}</h1>
|
||||
<p>{% trans "Bitte vergeben Sie jetzt ein neues Passwort für Ihr Konto." %}</p>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{% if form.errors %}
|
||||
<div class="app-alert app-alert-error" role="alert" aria-live="assertive">
|
||||
<div class="app-alert-body">
|
||||
<strong>{% trans "Passwort konnte nicht gespeichert werden" %}</strong><br />
|
||||
<span>{% trans "Bitte prüfen Sie die beiden Passwortfelder und versuchen Sie es erneut." %}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="field{% if form.new_password1.errors %} has-error{% endif %}">
|
||||
{{ form.new_password1.label_tag }}{{ form.new_password1 }}
|
||||
</div>
|
||||
<div class="field{% if form.new_password2.errors %} has-error{% endif %}">
|
||||
{{ form.new_password2.label_tag }}{{ form.new_password2 }}
|
||||
</div>
|
||||
<button class="btn btn-primary" type="submit">{% trans "Passwort speichern" %}</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<h1>{% trans "Link ungültig" %}</h1>
|
||||
<p>{% trans "Dieser Link ist nicht mehr gültig. Bitte fordern Sie einen neuen Passwort-Link an." %}</p>
|
||||
<a class="btn btn-primary" href="/accounts/login/">{% trans "Zur Anmeldung" %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,22 @@
|
||||
{% extends 'workflows/base_shell.html' %}
|
||||
{% load static i18n %}
|
||||
|
||||
{% block title %}{% trans "E-Mail versendet" %}{% endblock %}
|
||||
|
||||
{% block shell_header %}
|
||||
{% include 'workflows/includes/app_header.html' with header_inside_shell=1 %}
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{% static 'workflows/css/login.css' %}" />
|
||||
{% endblock %}
|
||||
|
||||
{% block shell_body %}
|
||||
<section class="login-shell-body">
|
||||
<div class="login-card">
|
||||
<h1>{% trans "E-Mail versendet" %}</h1>
|
||||
<p>{% trans "Wenn ein passendes Konto existiert, wurde ein Passwort-Link an die hinterlegte E-Mail-Adresse verschickt." %}</p>
|
||||
<a class="btn btn-primary" href="/accounts/login/">{% trans "Zur Anmeldung" %}</a>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,28 @@
|
||||
{% extends 'workflows/base_shell.html' %}
|
||||
{% load static i18n %}
|
||||
|
||||
{% block title %}{% trans "Passwort zurücksetzen" %}{% endblock %}
|
||||
|
||||
{% block shell_header %}
|
||||
{% include 'workflows/includes/app_header.html' with header_inside_shell=1 %}
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{% static 'workflows/css/login.css' %}" />
|
||||
{% endblock %}
|
||||
|
||||
{% block shell_body %}
|
||||
<section class="login-shell-body">
|
||||
<div class="login-card">
|
||||
<h1>{% trans "Passwort zurücksetzen" %}</h1>
|
||||
<p>{% trans "Geben Sie Ihre E-Mail-Adresse ein. Wenn ein Konto vorhanden ist, erhalten Sie einen Passwort-Link." %}</p>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="field{% if form.email.errors %} has-error{% endif %}">
|
||||
{{ form.email.label_tag }}{{ form.email }}
|
||||
</div>
|
||||
<button class="btn btn-primary" type="submit">{% trans "Link anfordern" %}</button>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
39
backend/workflows/templates/workflows/auth/login.html
Normal file
39
backend/workflows/templates/workflows/auth/login.html
Normal file
@@ -0,0 +1,39 @@
|
||||
{% extends 'workflows/base_shell.html' %}
|
||||
{% load static i18n %}
|
||||
|
||||
{% block title %}{% trans "Anmeldung" %}{% endblock %}
|
||||
|
||||
{% block shell_header %}
|
||||
{% include 'workflows/includes/app_header.html' with header_show_lang=1 header_inside_shell=1 %}
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{% static 'workflows/css/login.css' %}" />
|
||||
{% endblock %}
|
||||
|
||||
{% block shell_body %}
|
||||
<section class="login-shell-body">
|
||||
<div class="login-card">
|
||||
<h1>{% trans "Anmeldung" %}</h1>
|
||||
<p>{% trans "Bitte melden Sie sich mit Ihrem Benutzerkonto an." %}</p>
|
||||
|
||||
<form method="post" action="/accounts/login/">
|
||||
{% csrf_token %}
|
||||
{% if next %}
|
||||
<input type="hidden" name="next" value="{{ next }}" />
|
||||
{% endif %}
|
||||
{% if form.errors %}
|
||||
<div class="app-alert app-alert-error" role="alert" aria-live="assertive">
|
||||
<div class="app-alert-body">
|
||||
<strong>{% trans "Anmeldung fehlgeschlagen" %}</strong><br />
|
||||
<span>{% trans "Benutzername oder Passwort sind nicht korrekt. Bitte versuchen Sie es erneut." %}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="field{% if form.errors %} has-error{% endif %}">{{ form.username.label_tag }}{{ form.username }}</div>
|
||||
<div class="field{% if form.errors %} has-error{% endif %}">{{ form.password.label_tag }}{{ form.password }}</div>
|
||||
<button class="btn btn-primary" type="submit">{% trans "Anmelden" %}</button>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,22 @@
|
||||
{% extends 'workflows/base_shell.html' %}
|
||||
{% load static i18n %}
|
||||
|
||||
{% block title %}{% trans "Passwort gespeichert" %}{% endblock %}
|
||||
|
||||
{% block shell_header %}
|
||||
{% include 'workflows/includes/app_header.html' with header_show_lang=1 header_inside_shell=1 %}
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{% static 'workflows/css/login.css' %}" />
|
||||
{% endblock %}
|
||||
|
||||
{% block shell_body %}
|
||||
<section class="login-shell-body">
|
||||
<div class="login-card">
|
||||
<h1>{% trans "Passwort gespeichert" %}</h1>
|
||||
<p>{% trans "Ihr Passwort wurde erfolgreich gesetzt. Sie können sich jetzt mit Ihrem Benutzerkonto anmelden." %}</p>
|
||||
<a class="btn btn-primary" href="/accounts/login/">{% trans "Zur Anmeldung" %}</a>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,47 @@
|
||||
{% extends 'workflows/base_shell.html' %}
|
||||
{% load static i18n %}
|
||||
|
||||
{% block title %}{% trans "Passwort festlegen" %}{% endblock %}
|
||||
|
||||
{% block shell_header %}
|
||||
{% include 'workflows/includes/app_header.html' with header_show_lang=1 header_inside_shell=1 %}
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{% static 'workflows/css/login.css' %}" />
|
||||
{% endblock %}
|
||||
|
||||
{% block shell_body %}
|
||||
<section class="login-shell-body">
|
||||
<div class="login-card">
|
||||
{% if validlink %}
|
||||
<h1>{% trans "Passwort festlegen" %}</h1>
|
||||
<p>{% trans "Bitte vergeben Sie jetzt ein neues Passwort für Ihr Konto." %}</p>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{% if form.errors %}
|
||||
<div class="app-alert app-alert-error" role="alert" aria-live="assertive">
|
||||
<div class="app-alert-body">
|
||||
<strong>{% trans "Passwort konnte nicht gespeichert werden" %}</strong><br />
|
||||
<span>{% trans "Bitte prüfen Sie die beiden Passwortfelder und versuchen Sie es erneut." %}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="field{% if form.new_password1.errors %} has-error{% endif %}">
|
||||
{{ form.new_password1.label_tag }}{{ form.new_password1 }}
|
||||
{% for error in form.new_password1.errors %}<div class="hint">{{ error }}</div>{% endfor %}
|
||||
</div>
|
||||
<div class="field{% if form.new_password2.errors %} has-error{% endif %}">
|
||||
{{ form.new_password2.label_tag }}{{ form.new_password2 }}
|
||||
{% for error in form.new_password2.errors %}<div class="hint">{{ error }}</div>{% endfor %}
|
||||
</div>
|
||||
<button class="btn btn-primary" type="submit">{% trans "Passwort speichern" %}</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<h1>{% trans "Link ungültig" %}</h1>
|
||||
<p>{% trans "Dieser Link ist nicht mehr gültig. Bitte fordern Sie einen neuen Passwort-Link an." %}</p>
|
||||
<a class="btn btn-primary" href="/accounts/login/">{% trans "Zur Anmeldung" %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,22 @@
|
||||
{% extends 'workflows/base_shell.html' %}
|
||||
{% load static i18n %}
|
||||
|
||||
{% block title %}{% trans "E-Mail versendet" %}{% endblock %}
|
||||
|
||||
{% block shell_header %}
|
||||
{% include 'workflows/includes/app_header.html' with header_show_lang=1 header_inside_shell=1 %}
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{% static 'workflows/css/login.css' %}" />
|
||||
{% endblock %}
|
||||
|
||||
{% block shell_body %}
|
||||
<section class="login-shell-body">
|
||||
<div class="login-card">
|
||||
<h1>{% trans "E-Mail versendet" %}</h1>
|
||||
<p>{% trans "Wenn ein passendes Konto existiert, wurde ein Passwort-Link an die hinterlegte E-Mail-Adresse verschickt." %}</p>
|
||||
<a class="btn btn-primary" href="/accounts/login/">{% trans "Zur Anmeldung" %}</a>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,29 @@
|
||||
{% extends 'workflows/base_shell.html' %}
|
||||
{% load static i18n %}
|
||||
|
||||
{% block title %}{% trans "Passwort zurücksetzen" %}{% endblock %}
|
||||
|
||||
{% block shell_header %}
|
||||
{% include 'workflows/includes/app_header.html' with header_show_lang=1 header_inside_shell=1 %}
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{% static 'workflows/css/login.css' %}" />
|
||||
{% endblock %}
|
||||
|
||||
{% block shell_body %}
|
||||
<section class="login-shell-body">
|
||||
<div class="login-card">
|
||||
<h1>{% trans "Passwort zurücksetzen" %}</h1>
|
||||
<p>{% trans "Geben Sie Ihre E-Mail-Adresse ein. Wenn ein Konto vorhanden ist, erhalten Sie einen Passwort-Link." %}</p>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="field{% if form.email.errors %} has-error{% endif %}">
|
||||
{{ form.email.label_tag }}{{ form.email }}
|
||||
{% for error in form.email.errors %}<div class="hint">{{ error }}</div>{% endfor %}
|
||||
</div>
|
||||
<button class="btn btn-primary" type="submit">{% trans "Link anfordern" %}</button>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -107,7 +107,7 @@ docker compose exec -T web python manage.py check</code></pre>
|
||||
<li>Capability checks are centralized in <code>workflows.roles.CAPABILITIES</code>.</li>
|
||||
<li>Use <code>_require_capability(...)</code> in views instead of flat <code>is_staff</code> checks.</li>
|
||||
<li>Templates receive permission flags from <code>workflows.context_processors.role_context</code>.</li>
|
||||
<li>Super-admin-only user management lives at <code>/admin-tools/users/</code> and is the preferred path for normal role assignment, account activation, password-reset mail dispatch, and controlled user deletion.</li>
|
||||
<li>Super-admin-only user management lives at <code>/admin-tools/users/</code> and is the preferred path for normal role assignment, account activation, invitation mail dispatch, password-reset mail dispatch, and controlled user deletion.</li>
|
||||
<li>Backward-compatibility rule: authenticated legacy users with <code>is_staff=True</code> but no explicit role group currently fall back to the <code>Admin</code> capability set.</li>
|
||||
<li><code>superuser</code> accounts resolve to <code>Super Admin</code>.</li>
|
||||
<li>When adding a new operational page or action, define the capability in <code>roles.py</code>, gate the view, and hide the UI affordance when the capability is absent.</li>
|
||||
|
||||
@@ -178,7 +178,7 @@
|
||||
<li><strong>Form Builder:</strong> manage field visibility/order/options.</li>
|
||||
<li><strong>Einweisungs-Builder:</strong> manage custom checklist items for the intro PDF and live introduction checklist, including section, visibility, and conditional display logic.</li>
|
||||
<li><strong>Integrations:</strong> Nextcloud, SMTP, default routing addresses, notification rules, workflow rules, and remote backup target settings.</li>
|
||||
<li><strong>Benutzer & Rollen:</strong> super-admin-only page for creating users, assigning roles, activating/deactivating access, sending password-reset links, and deleting accounts when appropriate.</li>
|
||||
<li><strong>Benutzer & Rollen:</strong> super-admin-only page for creating users, assigning roles, activating/deactivating access, sending access or password-reset links by email, and deleting accounts when appropriate.</li>
|
||||
<li><strong>Welcome Emails:</strong> scheduled jobs, pause/resume/cancel/trigger now.</li>
|
||||
<li><strong>Audit Log:</strong> staff-only trace of important admin changes such as builder edits, settings updates, PDF generation, welcome-email operations, and request deletions. Supports filtering by action, user, and date range.</li>
|
||||
<li><strong>Requests Dashboard:</strong> search records, open PDFs, delete records (single/bulk for staff).</li>
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
<section class="card">
|
||||
<h2>{% trans "Benutzer anlegen" %}</h2>
|
||||
<p class="sub">{% trans "Nach dem Anlegen wird automatisch eine Zugangseinladung mit Passwort-Link per E-Mail versendet." %}</p>
|
||||
<form method="post" action="{% url 'create_user_from_admin' %}">
|
||||
{% csrf_token %}
|
||||
<div class="grid">
|
||||
@@ -48,20 +49,10 @@
|
||||
{{ create_form.role_key }}
|
||||
{% for error in create_form.role_key.errors %}<div class="hint">{{ error }}</div>{% endfor %}
|
||||
</div>
|
||||
<div>
|
||||
<label for="{{ create_form.password1.id_for_label }}">{{ create_form.password1.label }}</label>
|
||||
{{ create_form.password1 }}
|
||||
{% for error in create_form.password1.errors %}<div class="hint">{{ error }}</div>{% endfor %}
|
||||
</div>
|
||||
<div>
|
||||
<label for="{{ create_form.password2.id_for_label }}">{{ create_form.password2.label }}</label>
|
||||
{{ create_form.password2 }}
|
||||
{% for error in create_form.password2.errors %}<div class="hint">{{ error }}</div>{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% for error in create_form.non_field_errors %}<div class="hint">{{ error }}</div>{% endfor %}
|
||||
<div class="actions">
|
||||
<button class="btn btn-primary" type="submit">{% trans "Benutzer erstellen" %}</button>
|
||||
<button class="btn btn-primary" type="submit">{% trans "Benutzer anlegen und einladen" %}</button>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
@@ -394,6 +394,44 @@ def _would_remove_last_super_admin(user, new_role_key: str | None = None, new_is
|
||||
return False
|
||||
|
||||
|
||||
def _send_user_access_email(request, target_user, *, invitation: bool) -> None:
|
||||
email = (target_user.email or '').strip()
|
||||
if not email:
|
||||
raise ValueError(_('Für diesen Benutzer ist keine E-Mail-Adresse hinterlegt.'))
|
||||
|
||||
uid = urlsafe_base64_encode(force_bytes(target_user.pk))
|
||||
token = default_token_generator.make_token(target_user)
|
||||
reset_path = reverse('password_reset_confirm', kwargs={'uidb64': uid, 'token': token})
|
||||
reset_url = request.build_absolute_uri(reset_path)
|
||||
|
||||
if invitation:
|
||||
subject = _('Zugangseinladung für %(username)s') % {'username': target_user.username}
|
||||
body = _(
|
||||
'Hallo %(name)s,\n\n'
|
||||
'für Sie wurde ein Benutzerkonto im TUBCO Onboarding- und Offboarding-Portal angelegt.\n'
|
||||
'Bitte öffnen Sie den folgenden Link, um Ihr Passwort zu setzen:\n'
|
||||
'%(url)s\n\n'
|
||||
'Wenn Sie diese Einladung nicht erwartet haben, melden Sie sich bitte bei Ihrem Administrator.'
|
||||
) % {
|
||||
'name': _display_user_name(target_user),
|
||||
'url': reset_url,
|
||||
}
|
||||
else:
|
||||
subject = _('Passwort zurücksetzen für %(username)s') % {'username': target_user.username}
|
||||
body = _(
|
||||
'Hallo %(name)s,\n\n'
|
||||
'für Ihr Konto wurde ein Link zum Zurücksetzen des Passworts erstellt.\n'
|
||||
'Bitte öffnen Sie den folgenden Link:\n'
|
||||
'%(url)s\n\n'
|
||||
'Wenn Sie diese Anfrage nicht erwartet haben, können Sie diese E-Mail ignorieren.'
|
||||
) % {
|
||||
'name': _display_user_name(target_user),
|
||||
'url': reset_url,
|
||||
}
|
||||
|
||||
send_system_email(subject=subject, body=body, to=[email])
|
||||
|
||||
|
||||
@_require_capability('manage_users')
|
||||
def user_management_page(request):
|
||||
return _render_user_management(request)
|
||||
@@ -408,15 +446,16 @@ def create_user_from_admin(request):
|
||||
return _render_user_management(request, create_form=form, status_code=400)
|
||||
|
||||
user = form.save()
|
||||
_send_user_access_email(request, user, invitation=True)
|
||||
_audit(
|
||||
request,
|
||||
'user_created',
|
||||
target_type='user',
|
||||
target_id=user.id,
|
||||
target_label=_display_user_name(user),
|
||||
details={'username': user.username, 'role': get_user_role_key(user)},
|
||||
details={'username': user.username, 'role': get_user_role_key(user), 'invitation_sent': True},
|
||||
)
|
||||
messages.success(request, _('Benutzer wurde erstellt: %(username)s') % {'username': user.username})
|
||||
messages.success(request, _('Benutzer wurde erstellt und eingeladen: %(username)s') % {'username': user.username})
|
||||
return redirect('user_management_page')
|
||||
|
||||
|
||||
@@ -463,37 +502,18 @@ def update_user_from_admin(request, user_id: int):
|
||||
def send_password_reset_from_admin(request, user_id: int):
|
||||
user_model = get_user_model()
|
||||
target_user = get_object_or_404(user_model, id=user_id)
|
||||
email = (target_user.email or '').strip()
|
||||
if not email:
|
||||
messages.error(request, _('Für diesen Benutzer ist keine E-Mail-Adresse hinterlegt.'))
|
||||
try:
|
||||
_send_user_access_email(request, target_user, invitation=False)
|
||||
except ValueError as exc:
|
||||
messages.error(request, str(exc))
|
||||
return redirect('user_management_page')
|
||||
|
||||
uid = urlsafe_base64_encode(force_bytes(target_user.pk))
|
||||
token = default_token_generator.make_token(target_user)
|
||||
reset_path = reverse('password_reset_confirm', kwargs={'uidb64': uid, 'token': token})
|
||||
reset_url = request.build_absolute_uri(reset_path)
|
||||
|
||||
send_system_email(
|
||||
subject=_('Passwort zurücksetzen für %(username)s') % {'username': target_user.username},
|
||||
body=_(
|
||||
'Hallo %(name)s,\n\n'
|
||||
'für Ihr Konto wurde ein Link zum Zurücksetzen des Passworts erstellt.\n'
|
||||
'Bitte öffnen Sie den folgenden Link:\n'
|
||||
'%(url)s\n\n'
|
||||
'Wenn Sie diese Anfrage nicht erwartet haben, können Sie diese E-Mail ignorieren.'
|
||||
) % {
|
||||
'name': _display_user_name(target_user),
|
||||
'url': reset_url,
|
||||
},
|
||||
to=[email],
|
||||
)
|
||||
_audit(
|
||||
request,
|
||||
'user_password_reset_sent',
|
||||
target_type='user',
|
||||
target_id=target_user.id,
|
||||
target_label=_display_user_name(target_user),
|
||||
details={'username': target_user.username, 'email': email},
|
||||
details={'username': target_user.username, 'email': target_user.email},
|
||||
)
|
||||
messages.success(request, _('Passwort-Reset-Link wurde versendet: %(username)s') % {'username': target_user.username})
|
||||
return redirect('user_management_page')
|
||||
|
||||
Reference in New Issue
Block a user