From 358a71230dbc249281e2ceaa6bdf0ac9dcb632e6 Mon Sep 17 00:00:00 2001 From: Md Bayazid Bostame Date: Fri, 27 Mar 2026 02:06:52 +0100 Subject: [PATCH] snapshot: preserve account profile inline editing and avatar flow --- backend/locale/en/LC_MESSAGES/django.mo | Bin 35017 -> 35906 bytes backend/locale/en/LC_MESSAGES/django.po | 882 +++++++++++------- backend/workflows/forms.py | 81 +- .../workflows/migrations/0048_userprofile.py | 42 + backend/workflows/models.py | 24 + backend/workflows/roles.py | 7 + backend/workflows/signals.py | 10 +- .../static/workflows/css/account.css | 486 ++++++++++ .../static/workflows/css/app_chrome.css | 17 +- .../templates/workflows/account_profile.html | 241 ++++- .../workflows/includes/app_header.html | 10 +- backend/workflows/tests/test_account_ui.py | 31 + backend/workflows/views.py | 29 +- 13 files changed, 1462 insertions(+), 398 deletions(-) create mode 100644 backend/workflows/migrations/0048_userprofile.py create mode 100644 backend/workflows/static/workflows/css/account.css diff --git a/backend/locale/en/LC_MESSAGES/django.mo b/backend/locale/en/LC_MESSAGES/django.mo index 0c041f30cf54646f6d475f46d65e9982ffa38a3f..b04c453eb33e3cc5418cc628d73ad740258afb9f 100644 GIT binary patch delta 10320 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 diff --git a/backend/locale/en/LC_MESSAGES/django.po b/backend/locale/en/LC_MESSAGES/django.po index 3068da9..a94e56c 100644 --- a/backend/locale/en/LC_MESSAGES/django.po +++ b/backend/locale/en/LC_MESSAGES/django.po @@ -2,21 +2,21 @@ msgid "" msgstr "" "Project-Id-Version: tubco-portal\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-03-26 23:25+0000\n" +"POT-Creation-Date: 2026-03-27 01:04+0000\n" "PO-Revision-Date: 2026-03-24 00:00+0000\n" "Language: en\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: workflows/app_registry.py:32 workflows/models.py:349 workflows/models.py:430 +#: workflows/app_registry.py:35 workflows/models.py:373 workflows/models.py:454 #: workflows/templates/workflows/onboarding_form.html:25 #: workflows/templates/workflows/requests_dashboard.html:68 #: workflows/templates/workflows/requests_dashboard.html:131 msgid "Onboarding" msgstr "Onboarding" -#: workflows/app_registry.py:33 +#: workflows/app_registry.py:36 msgid "" "Neue Mitarbeitende erfassen, PDF mit Briefkopf erstellen, Benachrichtigungen " "senden und in Nextcloud ablegen." @@ -24,25 +24,25 @@ msgstr "" "Capture new employees, generate a PDF with letterhead, send notifications, " "and store it in Nextcloud." -#: workflows/app_registry.py:34 +#: workflows/app_registry.py:37 msgid "Onboarding starten" msgstr "Start onboarding" -#: workflows/app_registry.py:36 +#: workflows/app_registry.py:39 msgid "Mehrschritt-Formular" msgstr "Multi-step form" -#: workflows/app_registry.py:36 +#: workflows/app_registry.py:39 msgid "E-Mail Routing" msgstr "Email routing" -#: workflows/app_registry.py:43 workflows/models.py:350 workflows/models.py:431 +#: workflows/app_registry.py:46 workflows/models.py:374 workflows/models.py:455 #: workflows/templates/workflows/requests_dashboard.html:78 #: workflows/templates/workflows/requests_dashboard.html:132 msgid "Offboarding" msgstr "Offboarding" -#: workflows/app_registry.py:44 +#: workflows/app_registry.py:47 msgid "" "Mitarbeitende suchen, Daten vorbefüllen, Offboarding-Dokumente erzeugen und " "Rückgabe-Prozess starten." @@ -50,29 +50,29 @@ msgstr "" "Search employees, prefill data, generate offboarding documents, and start " "the return process." -#: workflows/app_registry.py:45 +#: workflows/app_registry.py:48 msgid "Offboarding starten" msgstr "Start offboarding" -#: workflows/app_registry.py:47 +#: workflows/app_registry.py:50 msgid "Profile-Suche" msgstr "Profile search" -#: workflows/app_registry.py:47 +#: workflows/app_registry.py:50 msgid "Hardware-Liste" msgstr "Hardware list" -#: workflows/app_registry.py:47 +#: workflows/app_registry.py:50 msgid "IT-Rückgabe" msgstr "IT return" -#: workflows/app_registry.py:54 +#: workflows/app_registry.py:57 #: workflows/templates/workflows/requests_dashboard.html:4 #: workflows/templates/workflows/requests_dashboard.html:33 msgid "Anfragen Dashboard" msgstr "Requests Dashboard" -#: workflows/app_registry.py:55 +#: workflows/app_registry.py:58 msgid "" "Status, Suchfunktion, PDF-Links und Verlauf aller Onboarding-/Offboarding-" "Anfragen." @@ -80,16 +80,16 @@ msgstr "" "Status, search, PDF links, and history of all onboarding/offboarding " "requests." -#: workflows/app_registry.py:56 +#: workflows/app_registry.py:59 msgid "Dashboard öffnen" msgstr "Open dashboard" -#: workflows/app_registry.py:59 +#: workflows/app_registry.py:62 #: workflows/templates/workflows/app_registry.html:27 msgid "Suche" msgstr "Search" -#: workflows/app_registry.py:59 +#: workflows/app_registry.py:62 #: workflows/templates/workflows/app_registry.html:31 #: workflows/templates/workflows/backup_recovery.html:72 #: workflows/templates/workflows/job_monitor.html:29 @@ -103,287 +103,288 @@ msgstr "Search" msgid "Status" msgstr "Status" -#: workflows/app_registry.py:59 +#: workflows/app_registry.py:62 msgid "PDF Zugriff" msgstr "PDF access" -#: workflows/app_registry.py:65 +#: workflows/app_registry.py:68 #: workflows/templates/workflows/company_config.html:4 #: workflows/templates/workflows/company_config.html:12 msgid "Company Config" msgstr "" -#: workflows/app_registry.py:66 +#: workflows/app_registry.py:69 msgid "" "Rechtliche Firmendaten, Kontaktpunkte und öffentliche Unternehmenslinks " "pflegen." msgstr "" -#: workflows/app_registry.py:67 workflows/app_registry.py:76 -#: workflows/app_registry.py:85 workflows/app_registry.py:94 -#: workflows/app_registry.py:103 workflows/app_registry.py:112 -#: workflows/app_registry.py:121 workflows/app_registry.py:130 -#: workflows/app_registry.py:139 workflows/app_registry.py:148 -#: workflows/app_registry.py:157 workflows/app_registry.py:166 -#: workflows/app_registry.py:175 workflows/app_registry.py:184 +#: workflows/app_registry.py:70 workflows/app_registry.py:79 +#: workflows/app_registry.py:88 workflows/app_registry.py:97 +#: workflows/app_registry.py:106 workflows/app_registry.py:115 +#: workflows/app_registry.py:124 workflows/app_registry.py:133 +#: workflows/app_registry.py:142 workflows/app_registry.py:151 +#: workflows/app_registry.py:160 workflows/app_registry.py:169 +#: workflows/app_registry.py:178 workflows/app_registry.py:187 msgid "Öffnen" msgstr "Open" -#: workflows/app_registry.py:74 +#: workflows/app_registry.py:77 #: workflows/templates/workflows/trial_management.html:4 #: workflows/templates/workflows/trial_management.html:12 msgid "Trial Management" msgstr "" -#: workflows/app_registry.py:75 +#: workflows/app_registry.py:78 msgid "" "Testlaufzeit, Banner und sichere Einschränkungen für Demo-Umgebungen steuern." msgstr "" -#: workflows/app_registry.py:83 +#: workflows/app_registry.py:86 #: workflows/templates/workflows/branding_settings.html:4 #: workflows/templates/workflows/branding_settings.html:12 msgid "Branding" msgstr "Branding" -#: workflows/app_registry.py:84 +#: workflows/app_registry.py:87 msgid "Logo, Portalname, Farben und PDF-Briefkopf verwalten." msgstr "Manage logo, portal name, colors, and PDF letterhead." -#: workflows/app_registry.py:92 +#: workflows/app_registry.py:95 #: workflows/templates/workflows/app_registry.html:5 #: workflows/templates/workflows/app_registry.html:13 msgid "App Registry" msgstr "" -#: workflows/app_registry.py:93 +#: workflows/app_registry.py:96 msgid "Apps zentral aktivieren, sortieren und für Kundenauftritte vorbereiten." msgstr "" -#: workflows/app_registry.py:101 +#: workflows/app_registry.py:104 msgid "Integrationen" msgstr "Integrations" -#: workflows/app_registry.py:102 +#: workflows/app_registry.py:105 msgid "Nextcloud- und E-Mail-Setup." msgstr "Nextcloud and email setup." -#: workflows/app_registry.py:110 +#: workflows/app_registry.py:113 #: workflows/templates/workflows/job_monitor.html:4 #: workflows/templates/workflows/job_monitor.html:12 msgid "Job Monitor" msgstr "" -#: workflows/app_registry.py:111 +#: workflows/app_registry.py:114 msgid "Asynchrone Aufgaben, Fehler und letzte Worker-Läufe prüfen." msgstr "" -#: workflows/app_registry.py:119 +#: workflows/app_registry.py:122 #: workflows/templates/workflows/user_management.html:4 #: workflows/templates/workflows/user_management.html:14 msgid "Benutzer & Rollen" msgstr "Users & roles" -#: workflows/app_registry.py:120 +#: workflows/app_registry.py:123 msgid "Benutzer anlegen, Rollen zuweisen und Zugriffe steuern." msgstr "Create users, assign roles, and control access." -#: workflows/app_registry.py:128 workflows/templates/workflows/audit_log.html:4 +#: workflows/app_registry.py:131 workflows/templates/workflows/audit_log.html:4 #: workflows/templates/workflows/audit_log.html:15 msgid "Audit Log" msgstr "" -#: workflows/app_registry.py:129 +#: workflows/app_registry.py:132 msgid "Wichtige Admin-Aktionen nachvollziehen und prüfen." msgstr "" -#: workflows/app_registry.py:137 +#: workflows/app_registry.py:140 #: workflows/templates/workflows/backup_recovery.html:4 #: workflows/templates/workflows/backup_recovery.html:12 msgid "Backup & Recovery" msgstr "Backup & Recovery" -#: workflows/app_registry.py:138 +#: workflows/app_registry.py:141 msgid "Backups erstellen und sicher verifizieren." msgstr "" -#: workflows/app_registry.py:146 +#: workflows/app_registry.py:149 #: workflows/templates/workflows/welcome_emails.html:4 msgid "Welcome E-Mails" msgstr "Welcome Emails" -#: workflows/app_registry.py:147 +#: workflows/app_registry.py:150 msgid "Geplante Welcome Mails verwalten." msgstr "Manage scheduled welcome emails." -#: workflows/app_registry.py:155 +#: workflows/app_registry.py:158 #: workflows/templates/workflows/form_builder.html:4 #: workflows/templates/workflows/form_builder.html:14 msgid "Form Builder" msgstr "Form Builder" -#: workflows/app_registry.py:156 +#: workflows/app_registry.py:159 msgid "Felder, Schritte und Optionen verwalten." msgstr "Manage fields, steps, and options." -#: workflows/app_registry.py:164 +#: workflows/app_registry.py:167 #: workflows/templates/workflows/intro_builder.html:4 #: workflows/templates/workflows/intro_builder.html:17 msgid "Einweisungs-Builder" msgstr "Introduction Builder" -#: workflows/app_registry.py:165 +#: workflows/app_registry.py:168 msgid "Checklistenpunkte für das Einweisungsprotokoll konfigurieren." msgstr "Configure checklist items for the introduction protocol." -#: workflows/app_registry.py:173 workflows/templates/workflows/handbook.html:4 +#: workflows/app_registry.py:176 workflows/templates/workflows/handbook.html:4 #: workflows/templates/workflows/handbook.html:15 msgid "Handbook" msgstr "Handbook" -#: workflows/app_registry.py:174 +#: workflows/app_registry.py:177 msgid "Project wiki and developer documentation in one place." msgstr "Project wiki and developer documentation in one place." -#: workflows/app_registry.py:182 +#: workflows/app_registry.py:185 msgid "Django Admin" msgstr "Django Admin" -#: workflows/app_registry.py:183 +#: workflows/app_registry.py:186 msgid "Vollständige Datenverwaltung." msgstr "Full data management." -#: workflows/app_registry.py:304 +#: workflows/app_registry.py:309 msgid "Nur Platform" msgstr "" -#: workflows/app_registry.py:306 +#: workflows/app_registry.py:311 #: workflows/templates/workflows/app_registry.html:85 msgid "Alle Firmenrollen" msgstr "" -#: workflows/app_registry.py:312 workflows/models.py:126 +#: workflows/app_registry.py:317 workflows/models.py:150 #: workflows/templates/workflows/app_registry.html:43 #: workflows/templates/workflows/app_registry.html:78 msgid "Apps" msgstr "Apps" -#: workflows/app_registry.py:313 +#: workflows/app_registry.py:318 msgid "Wählen Sie den gewünschten Prozess." msgstr "Choose the desired process." -#: workflows/app_registry.py:318 workflows/models.py:127 +#: workflows/app_registry.py:323 workflows/models.py:151 #: workflows/templates/workflows/app_registry.html:44 #: workflows/templates/workflows/app_registry.html:74 msgid "Platform Apps" msgstr "" -#: workflows/app_registry.py:319 +#: workflows/app_registry.py:324 #, fuzzy #| msgid "Konfiguration, Tests und Steuerung." msgid "Produktweite Konfiguration und Produktsteuerung." msgstr "Configuration, tests, and controls." -#: workflows/app_registry.py:324 workflows/models.py:128 +#: workflows/app_registry.py:329 workflows/models.py:152 #: workflows/templates/workflows/app_registry.html:45 #: workflows/templates/workflows/app_registry.html:76 msgid "Admin Apps" msgstr "Admin Apps" -#: workflows/app_registry.py:325 +#: workflows/app_registry.py:330 msgid "Konfiguration, Tests und Steuerung." msgstr "Configuration, tests, and controls." -#: workflows/backup_ops.py:122 +#: workflows/backup_ops.py:127 #, fuzzy #| msgid "Noch keine Vorgänge vorhanden." msgid "Kein Backup vorhanden" msgstr "No backup bundles available yet." -#: workflows/backup_ops.py:123 +#: workflows/backup_ops.py:128 #, fuzzy #| msgid "Noch keine Vorgänge vorhanden." msgid "Es wurde noch kein Backup-Bundle erstellt." msgstr "No backup bundles available yet." -#: workflows/backup_ops.py:137 +#: workflows/backup_ops.py:142 #, fuzzy #| msgid "Verifiziert" msgid "Nicht verifiziert" msgstr "Verified" -#: workflows/backup_ops.py:138 +#: workflows/backup_ops.py:143 msgid "Das neueste Backup-Bundle wurde noch nicht erfolgreich verifiziert." msgstr "" -#: workflows/backup_ops.py:149 +#: workflows/backup_ops.py:154 #, fuzzy #| msgid "Verifiziert" msgid "Verifikation veraltet" msgstr "Verified" -#: workflows/backup_ops.py:150 +#: workflows/backup_ops.py:155 #, python-format msgid "" "Die letzte erfolgreiche Backup-Verifikation ist älter als %(hours)s Stunden." msgstr "" -#: workflows/backup_ops.py:158 +#: workflows/backup_ops.py:163 msgid "Verifikation aktuell" msgstr "" -#: workflows/backup_ops.py:159 +#: workflows/backup_ops.py:164 msgid "" "Das neueste Backup-Bundle wurde erfolgreich und rechtzeitig verifiziert." msgstr "" -#: workflows/backup_ops.py:191 +#: workflows/backup_ops.py:196 msgid "Remote Backup ist deaktiviert." msgstr "" -#: workflows/backup_ops.py:196 +#: workflows/backup_ops.py:201 #, python-format msgid "Zieltyp %(target)s ist vorbereitet, aber noch nicht implementiert." msgstr "" -#: workflows/backup_ops.py:202 +#: workflows/backup_ops.py:207 msgid "Nextcloud Backup-Verzeichnis fehlt." msgstr "" -#: workflows/backup_ops.py:220 +#: workflows/backup_ops.py:225 #, python-format msgid "Upload nach Nextcloud fehlgeschlagen bei %(file)s." msgstr "" -#: workflows/backup_ops.py:226 +#: workflows/backup_ops.py:231 #, python-format msgid "Nach Nextcloud hochgeladen: %(count)s Datei(en)." msgstr "" -#: workflows/backup_ops.py:289 workflows/backup_ops.py:366 +#: workflows/backup_ops.py:294 workflows/backup_ops.py:371 msgid "Backup-Dateien nicht gefunden." msgstr "" -#: workflows/backup_ops.py:337 +#: workflows/backup_ops.py:342 msgid "Media-Archiv enthält kein media/-Verzeichnis." msgstr "" -#: workflows/backup_ops.py:339 +#: workflows/backup_ops.py:344 #, python-format msgid "" "%(tables)s Tabellen, %(onboarding)s Onboarding, %(offboarding)s Offboarding, " "%(media)s Mediendateien geprüft." msgstr "" -#: workflows/backup_ops.py:364 +#: workflows/backup_ops.py:369 msgid "Ungültiger Backup-Pfad." msgstr "" -#: workflows/backup_ops.py:371 +#: workflows/backup_ops.py:376 msgid "Remote Backup in Nextcloud konnte nicht gelöscht werden." msgstr "" -#: workflows/forms.py:104 workflows/forms.py:129 +#: workflows/forms.py:104 workflows/forms.py:227 +#: workflows/templates/workflows/account_profile.html:66 #: workflows/templates/workflows/user_management.html:72 #: workflows/templates/workflows/user_management.html:170 msgid "Benutzername" @@ -393,30 +394,86 @@ msgstr "" msgid "Passwort" msgstr "Password" -#: workflows/forms.py:109 workflows/forms.py:130 +#: workflows/forms.py:109 workflows/forms.py:173 workflows/forms.py:228 #, fuzzy #| msgid "E-Mail" msgid "E-Mail-Adresse" msgstr "Email" -#: workflows/forms.py:114 workflows/templates/workflows/user_management.html:77 +#: workflows/forms.py:114 workflows/forms.py:133 +#: workflows/templates/workflows/user_management.html:77 #: workflows/templates/workflows/user_management.html:108 msgid "Neues Passwort" msgstr "New password" -#: workflows/forms.py:120 +#: workflows/forms.py:120 workflows/forms.py:139 msgid "Neues Passwort bestätigen" msgstr "Confirm new password" -#: workflows/forms.py:127 +#: workflows/forms.py:128 +#, fuzzy +#| msgid "Neues Passwort" +msgid "Aktuelles Passwort" +msgstr "New password" + +#: workflows/forms.py:150 workflows/templates/workflows/account_profile.html:36 +#: workflows/templates/workflows/includes/app_header.html:27 +msgid "Profilbild" +msgstr "" + +#: workflows/forms.py:166 +msgid "Das Profilbild darf maximal 5 MB groß sein." +msgstr "" + +#: workflows/forms.py:171 workflows/forms.py:225 +#: workflows/templates/workflows/account_profile.html:112 msgid "Vorname" msgstr "" -#: workflows/forms.py:128 +#: workflows/forms.py:172 workflows/forms.py:226 +#: workflows/templates/workflows/account_profile.html:116 msgid "Nachname" msgstr "" -#: workflows/forms.py:131 workflows/templates/workflows/user_management.html:74 +#: workflows/forms.py:174 +#: workflows/templates/workflows/account_profile.html:120 +msgid "Telefon" +msgstr "" + +#: workflows/forms.py:175 +#: workflows/templates/workflows/account_profile.html:124 +msgid "Mobil" +msgstr "" + +#: workflows/forms.py:176 workflows/templates/workflows/account_profile.html:70 +#: workflows/templates/workflows/account_profile.html:128 +#, fuzzy +#| msgid "Produktion" +msgid "Position" +msgstr "Production" + +#: workflows/forms.py:177 workflows/models.py:334 +#: workflows/templates/workflows/account_profile.html:74 +#: workflows/templates/workflows/account_profile.html:132 +#: workflows/templates/workflows/onboarding_intro_session.html:28 +#: workflows/templates/workflows/requests_dashboard.html:145 +msgid "Abteilung" +msgstr "Department" + +#: workflows/forms.py:178 +#: workflows/templates/workflows/account_profile.html:136 +msgid "Standort" +msgstr "" + +#: workflows/forms.py:180 +#: workflows/templates/workflows/account_profile.html:140 +#, fuzzy +#| msgid "Einweisung" +msgid "Hinweise" +msgstr "Introduction" + +#: workflows/forms.py:229 workflows/templates/workflows/account_profile.html:62 +#: workflows/templates/workflows/user_management.html:74 #: workflows/templates/workflows/user_management.html:93 #: workflows/templates/workflows/user_management.html:171 #, fuzzy @@ -424,205 +481,205 @@ msgstr "" msgid "Rolle" msgstr "Role:" -#: workflows/forms.py:145 +#: workflows/forms.py:243 msgid "Dieser Benutzername ist bereits vergeben." msgstr "This username is already taken." -#: workflows/forms.py:154 workflows/views.py:770 +#: workflows/forms.py:252 workflows/views.py:807 msgid "Ungültige Rolle." msgstr "Invalid role." -#: workflows/forms.py:156 workflows/views.py:773 +#: workflows/forms.py:254 workflows/views.py:810 msgid "Nur Platform Owner dürfen diese Rolle vergeben." msgstr "" -#: workflows/forms.py:195 +#: workflows/forms.py:293 msgid "Portal-Titel" msgstr "Portal title" -#: workflows/forms.py:196 +#: workflows/forms.py:294 msgid "Firmenname" msgstr "Company name" -#: workflows/forms.py:197 +#: workflows/forms.py:295 #, fuzzy #| msgid "Firmenname" msgid "Firmen-Domain" msgstr "Company name" -#: workflows/forms.py:198 +#: workflows/forms.py:296 msgid "Support-E-Mail" msgstr "Support email" -#: workflows/forms.py:199 +#: workflows/forms.py:297 msgid "Absender-Anzeigename" msgstr "" -#: workflows/forms.py:200 +#: workflows/forms.py:298 msgid "Login-Untertitel" msgstr "" -#: workflows/forms.py:201 +#: workflows/forms.py:299 msgid "Footer-Text DE" msgstr "" -#: workflows/forms.py:202 +#: workflows/forms.py:300 msgid "Footer-Text EN" msgstr "" -#: workflows/forms.py:203 +#: workflows/forms.py:301 msgid "Rechtlicher Hinweis DE" msgstr "" -#: workflows/forms.py:204 +#: workflows/forms.py:302 msgid "Rechtlicher Hinweis EN" msgstr "" -#: workflows/forms.py:205 +#: workflows/forms.py:303 msgid "Standardsprache" msgstr "Default language" -#: workflows/forms.py:206 +#: workflows/forms.py:304 msgid "Logo" msgstr "Logo" -#: workflows/forms.py:207 +#: workflows/forms.py:305 msgid "PDF-Briefkopf" msgstr "PDF letterhead" -#: workflows/forms.py:208 +#: workflows/forms.py:306 msgid "Favicon" msgstr "" -#: workflows/forms.py:209 +#: workflows/forms.py:307 #: workflows/templates/workflows/branding_settings.html:94 msgid "Primärfarbe" msgstr "Primary color" -#: workflows/forms.py:210 +#: workflows/forms.py:308 #: workflows/templates/workflows/branding_settings.html:95 msgid "Sekundärfarbe" msgstr "Secondary color" -#: workflows/forms.py:227 +#: workflows/forms.py:325 msgid "Das Logo darf maximal 5 MB groß sein." msgstr "" -#: workflows/forms.py:235 +#: workflows/forms.py:333 msgid "Der PDF-Briefkopf darf maximal 10 MB groß sein." msgstr "" -#: workflows/forms.py:243 +#: workflows/forms.py:341 msgid "Das Favicon darf maximal 2 MB groß sein." msgstr "" -#: workflows/forms.py:267 +#: workflows/forms.py:365 #, fuzzy #| msgid "Firmenname" msgid "Rechtlicher Firmenname" msgstr "Company name" -#: workflows/forms.py:268 +#: workflows/forms.py:366 msgid "Straße und Hausnummer" msgstr "" -#: workflows/forms.py:269 +#: workflows/forms.py:367 msgid "Postleitzahl" msgstr "" -#: workflows/forms.py:270 +#: workflows/forms.py:368 msgid "Stadt" msgstr "" -#: workflows/forms.py:271 +#: workflows/forms.py:369 msgid "Land" msgstr "" -#: workflows/forms.py:272 workflows/templates/workflows/base_shell.html:64 +#: workflows/forms.py:370 workflows/templates/workflows/base_shell.html:64 msgid "Website" msgstr "" -#: workflows/forms.py:273 +#: workflows/forms.py:371 msgid "Impressum-URL" msgstr "" -#: workflows/forms.py:274 +#: workflows/forms.py:372 msgid "Datenschutz-URL" msgstr "" -#: workflows/forms.py:275 +#: workflows/forms.py:373 msgid "HR-Kontakt" msgstr "" -#: workflows/forms.py:276 +#: workflows/forms.py:374 msgid "IT-Kontakt" msgstr "" -#: workflows/forms.py:277 +#: workflows/forms.py:375 #, fuzzy #| msgid "Operations" msgid "Operations-Kontakt" msgstr "Operations" -#: workflows/forms.py:278 +#: workflows/forms.py:376 msgid "Zentrale Telefonnummer" msgstr "" -#: workflows/forms.py:279 +#: workflows/forms.py:377 msgid "USt-IdNr." msgstr "" -#: workflows/forms.py:280 +#: workflows/forms.py:378 msgid "Register- oder Handelsnummer" msgstr "" -#: workflows/forms.py:297 +#: workflows/forms.py:395 msgid "Trial-Modus aktiv" msgstr "" -#: workflows/forms.py:298 +#: workflows/forms.py:396 msgid "Trial-Beginn" msgstr "" -#: workflows/forms.py:299 +#: workflows/forms.py:397 msgid "Trial-Ende" msgstr "" -#: workflows/forms.py:300 +#: workflows/forms.py:398 msgid "Produktive Integrationen begrenzen" msgstr "" -#: workflows/forms.py:301 +#: workflows/forms.py:399 msgid "Cleanup nach Ablauf zulassen" msgstr "" -#: workflows/forms.py:302 +#: workflows/forms.py:400 msgid "Banner-Text DE" msgstr "" -#: workflows/forms.py:303 +#: workflows/forms.py:401 msgid "Banner-Text EN" msgstr "" -#: workflows/forms.py:323 +#: workflows/forms.py:421 msgid "Bitte ein Trial-Ende festlegen." msgstr "" -#: workflows/forms.py:325 +#: workflows/forms.py:423 msgid "Das Trial-Ende muss nach dem Trial-Beginn liegen." msgstr "" -#: workflows/forms.py:464 workflows/forms.py:649 +#: workflows/forms.py:562 workflows/forms.py:747 #, python-format msgid "Bitte nutzen Sie das Format name@%(domain)s." msgstr "" -#: workflows/forms.py:486 workflows/forms.py:663 +#: workflows/forms.py:584 workflows/forms.py:761 #, python-format msgid "Bitte verwenden Sie eine @%(domain)s E-Mail-Adresse." msgstr "" -#: workflows/forms.py:571 +#: workflows/forms.py:669 #, python-format msgid "" "Das Übergabedatum muss mindestens %(days)s Tage in der Zukunft liegen " @@ -658,363 +715,373 @@ msgstr "" msgid "Backup erfolgreich verifiziert: %(name)s" msgstr "Backup is being verified" -#: workflows/models.py:175 workflows/views.py:383 +#: workflows/middleware.py:96 +msgid "Zu viele Anfragen. Bitte versuchen Sie es in wenigen Minuten erneut." +msgstr "" + +#: workflows/middleware.py:156 +msgid "" +"Ihre Sitzung ist wegen Inaktivität abgelaufen. Bitte melden Sie sich erneut " +"an." +msgstr "" + +#: workflows/middleware.py:165 +msgid "" +"Bitte bestätigen Sie Ihre Identität erneut, bevor Sie diese sensible Aktion " +"ausführen." +msgstr "" + +#: workflows/models.py:199 workflows/views.py:420 #, fuzzy #| msgid "Gesamtbestand" msgid "Gestartet" msgstr "Total records" -#: workflows/models.py:176 workflows/views.py:383 +#: workflows/models.py:200 workflows/views.py:420 #, fuzzy #| msgid "Eingereicht" msgid "Erfolgreich" msgstr "Submitted" -#: workflows/models.py:177 workflows/models.py:230 workflows/models.py:484 +#: workflows/models.py:201 workflows/models.py:254 workflows/models.py:508 #: workflows/templates/workflows/backup_recovery.html:102 #: workflows/templates/workflows/requests_dashboard.html:222 -#: workflows/templates/workflows/welcome_emails.html:108 workflows/views.py:209 -#: workflows/views.py:383 +#: workflows/templates/workflows/welcome_emails.html:108 workflows/views.py:246 +#: workflows/views.py:420 msgid "Fehlgeschlagen" msgstr "Failed" -#: workflows/models.py:227 workflows/views.py:206 +#: workflows/models.py:251 workflows/views.py:243 msgid "Eingereicht" msgstr "Submitted" -#: workflows/models.py:228 workflows/views.py:207 +#: workflows/models.py:252 workflows/views.py:244 msgid "In Bearbeitung" msgstr "Processing" -#: workflows/models.py:229 workflows/models.py:544 workflows/views.py:208 +#: workflows/models.py:253 workflows/models.py:568 workflows/views.py:245 msgid "Abgeschlossen" msgstr "Completed" -#: workflows/models.py:237 +#: workflows/models.py:261 msgid "Herr" msgstr "" -#: workflows/models.py:237 +#: workflows/models.py:261 msgid "Frau" msgstr "" -#: workflows/models.py:237 +#: workflows/models.py:261 msgid "Divers" msgstr "" -#: workflows/models.py:247 +#: workflows/models.py:271 msgid "befristet" msgstr "" -#: workflows/models.py:247 +#: workflows/models.py:271 msgid "unbefristet" msgstr "" -#: workflows/models.py:310 -#: workflows/templates/workflows/onboarding_intro_session.html:28 -#: workflows/templates/workflows/requests_dashboard.html:145 -msgid "Abteilung" -msgstr "Department" - -#: workflows/models.py:311 +#: workflows/models.py:335 msgid "Geräte" msgstr "" -#: workflows/models.py:312 +#: workflows/models.py:336 msgid "Software" msgstr "" -#: workflows/models.py:313 +#: workflows/models.py:337 #, fuzzy #| msgid "Vorgänge" msgid "Zugänge" msgstr "Requests" -#: workflows/models.py:314 +#: workflows/models.py:338 msgid "Workspace-Gruppen" msgstr "" -#: workflows/models.py:315 +#: workflows/models.py:339 msgid "Ressourcen" msgstr "" -#: workflows/models.py:316 +#: workflows/models.py:340 msgid "Telefonnummern" msgstr "" -#: workflows/models.py:342 +#: workflows/models.py:366 msgid "Automatisch" msgstr "" -#: workflows/models.py:343 workflows/views.py:101 +#: workflows/models.py:367 workflows/views.py:101 msgid "Stammdaten" msgstr "Master data" -#: workflows/models.py:344 workflows/views.py:102 +#: workflows/models.py:368 workflows/views.py:102 msgid "Vertrag" msgstr "Contract" -#: workflows/models.py:345 workflows/views.py:103 +#: workflows/models.py:369 workflows/views.py:103 msgid "IT-Setup" msgstr "IT setup" -#: workflows/models.py:346 workflows/views.py:104 +#: workflows/models.py:370 workflows/views.py:104 msgid "Abschluss" msgstr "Finish" -#: workflows/models.py:388 +#: workflows/models.py:412 #, fuzzy #| msgid "Onboarding" msgid "Onboarding: IT" msgstr "Onboarding" -#: workflows/models.py:389 +#: workflows/models.py:413 #, fuzzy #| msgid "Offboarding-Anfrage speichern" msgid "Onboarding: Allgemeine Info" msgstr "Save offboarding request" -#: workflows/models.py:390 +#: workflows/models.py:414 #, fuzzy #| msgid "Onboarding starten" msgid "Onboarding: Visitenkarte" msgstr "Start onboarding" -#: workflows/models.py:391 +#: workflows/models.py:415 #, fuzzy #| msgid "Onboarding" msgid "Onboarding: HR Works" msgstr "Onboarding" -#: workflows/models.py:392 +#: workflows/models.py:416 #, fuzzy #| msgid "Onboarding starten" msgid "Onboarding: Schlüssel" msgstr "Start onboarding" -#: workflows/models.py:393 +#: workflows/models.py:417 msgid "Onboarding: Referenz Anfordernde Person" msgstr "" -#: workflows/models.py:394 +#: workflows/models.py:418 #, fuzzy #| msgid "Welcome E-Mails" msgid "Onboarding: Welcome E-Mail" msgstr "Welcome Emails" -#: workflows/models.py:395 +#: workflows/models.py:419 #, fuzzy #| msgid "Offboarding" msgid "Offboarding: IT" msgstr "Offboarding" -#: workflows/models.py:396 +#: workflows/models.py:420 #, fuzzy #| msgid "Offboarding-Anfrage speichern" msgid "Offboarding: Allgemeine Info" msgstr "Save offboarding request" -#: workflows/models.py:397 +#: workflows/models.py:421 #, fuzzy #| msgid "Offboarding starten" msgid "Offboarding: HR Works Deaktivierung" msgstr "Start offboarding" -#: workflows/models.py:398 +#: workflows/models.py:422 msgid "Offboarding: Referenz Anfordernde Person" msgstr "" -#: workflows/models.py:434 +#: workflows/models.py:458 msgid "Immer" msgstr "" -#: workflows/models.py:435 workflows/models.py:513 +#: workflows/models.py:459 workflows/models.py:537 msgid "Enthält" msgstr "" -#: workflows/models.py:436 workflows/models.py:514 +#: workflows/models.py:460 workflows/models.py:538 msgid "Ist gleich" msgstr "" -#: workflows/models.py:437 +#: workflows/models.py:461 msgid "Ist aktiv/Ja" msgstr "" -#: workflows/models.py:438 +#: workflows/models.py:462 #, fuzzy #| msgid "inaktiv" msgid "Ist inaktiv/Nein" msgstr "inactive" -#: workflows/models.py:480 +#: workflows/models.py:504 #: workflows/templates/workflows/welcome_emails.html:100 msgid "Geplant" msgstr "Scheduled" -#: workflows/models.py:481 +#: workflows/models.py:505 #: workflows/templates/workflows/welcome_emails.html:102 msgid "Pausiert" msgstr "Paused" -#: workflows/models.py:482 +#: workflows/models.py:506 #: workflows/templates/workflows/welcome_emails.html:104 msgid "Abgebrochen" msgstr "Cancelled" -#: workflows/models.py:483 +#: workflows/models.py:507 #: workflows/templates/workflows/welcome_emails.html:106 msgid "Gesendet" msgstr "Sent" -#: workflows/models.py:506 workflows/tasks.py:597 +#: workflows/models.py:530 workflows/tasks.py:600 msgid "Geräte und Arbeitsplatz" msgstr "Devices and workplace" -#: workflows/models.py:507 workflows/tasks.py:598 +#: workflows/models.py:531 workflows/tasks.py:601 msgid "Konten und Berechtigungen" msgstr "Accounts and permissions" -#: workflows/models.py:508 workflows/tasks.py:599 +#: workflows/models.py:532 workflows/tasks.py:602 msgid "Software und Tools" msgstr "Software and tools" -#: workflows/models.py:509 workflows/tasks.py:600 +#: workflows/models.py:533 workflows/tasks.py:603 msgid "Prozesse und Hinweise" msgstr "Processes and notes" -#: workflows/models.py:512 +#: workflows/models.py:536 msgid "Immer anzeigen" msgstr "Always show" -#: workflows/models.py:515 +#: workflows/models.py:539 msgid "Ist Ja / aktiv" msgstr "Is yes / active" -#: workflows/models.py:516 +#: workflows/models.py:540 msgid "Ist Nein / inaktiv" msgstr "Is no / inactive" -#: workflows/models.py:543 +#: workflows/models.py:567 msgid "Entwurf" msgstr "Draft" -#: workflows/models.py:563 +#: workflows/models.py:587 #, fuzzy #| msgid "Nextcloud:" msgid "Nextcloud" msgstr "Nextcloud:" -#: workflows/models.py:564 +#: workflows/models.py:588 msgid "S3" msgstr "" -#: workflows/models.py:565 +#: workflows/models.py:589 msgid "NFS" msgstr "" -#: workflows/roles.py:22 +#: workflows/roles.py:26 msgid "Platform Owner" msgstr "" -#: workflows/roles.py:23 workflows/templates/workflows/app_registry.html:88 +#: workflows/roles.py:27 workflows/templates/workflows/app_registry.html:88 #: workflows/templates/workflows/app_registry.html:114 msgid "Super Admin" msgstr "Super Admin" -#: workflows/roles.py:24 workflows/templates/workflows/app_registry.html:89 +#: workflows/roles.py:28 workflows/templates/workflows/app_registry.html:89 #: workflows/templates/workflows/app_registry.html:118 msgid "Admin" msgstr "Admin" -#: workflows/roles.py:25 workflows/templates/workflows/app_registry.html:90 +#: workflows/roles.py:29 workflows/templates/workflows/app_registry.html:90 #: workflows/templates/workflows/app_registry.html:122 msgid "IT Staff" msgstr "IT Staff" -#: workflows/roles.py:26 +#: workflows/roles.py:30 msgid "Mitarbeiter" msgstr "Staff" -#: workflows/tasks.py:613 +#: workflows/tasks.py:616 #, python-format msgid "%(item)s übergeben und Grundfunktionen erklärt" msgstr "%(item)s handed over and basic functions explained" -#: workflows/tasks.py:615 +#: workflows/tasks.py:618 #, python-format msgid "%(item)s gezeigt bzw. Nutzung erklärt" msgstr "%(item)s shown or usage explained" -#: workflows/tasks.py:617 +#: workflows/tasks.py:620 #, python-format msgid "Telefonnummer / Direktwahl erklärt: %(value)s" msgstr "Phone number / direct extension explained: %(value)s" -#: workflows/tasks.py:619 +#: workflows/tasks.py:622 msgid "Arbeitsplatz, Geräte und allgemeine Nutzung besprochen" msgstr "Workplace, devices, and general usage reviewed" -#: workflows/tasks.py:621 +#: workflows/tasks.py:624 #, python-format msgid "%(item)s Zugang erklärt" msgstr "%(item)s access explained" -#: workflows/tasks.py:622 +#: workflows/tasks.py:625 #, python-format msgid "%(item)s Gruppe / Berechtigung erläutert" msgstr "%(item)s group / permission explained" -#: workflows/tasks.py:624 +#: workflows/tasks.py:627 #, python-format msgid "Dienstliche E-Mail-Adresse erläutert: %(value)s" msgstr "Work email address explained: %(value)s" -#: workflows/tasks.py:626 +#: workflows/tasks.py:629 #, python-format msgid "Gruppenpostfach erklärt: %(item)s" msgstr "Group mailbox explained: %(item)s" -#: workflows/tasks.py:628 +#: workflows/tasks.py:631 msgid "Zugänge, Konten und Anmeldelogik besprochen" msgstr "Accesses, accounts, and login logic reviewed" -#: workflows/tasks.py:630 +#: workflows/tasks.py:633 #, python-format msgid "%(item)s Einführung durchgeführt" msgstr "%(item)s introduction completed" -#: workflows/tasks.py:631 +#: workflows/tasks.py:634 #, python-format msgid "%(item)s zusätzlich besprochen" msgstr "%(item)s discussed additionally" -#: workflows/tasks.py:633 +#: workflows/tasks.py:636 msgid "Benötigte Standardsoftware und tägliche Nutzung erklärt" msgstr "Required standard software and daily usage explained" -#: workflows/tasks.py:636 +#: workflows/tasks.py:639 msgid "Passwortregeln und sicherer Umgang besprochen" msgstr "Password rules and secure handling reviewed" -#: workflows/tasks.py:637 +#: workflows/tasks.py:640 msgid "Dateiablage, Nextcloud und Freigaben erklärt" msgstr "File storage, Nextcloud, and sharing explained" -#: workflows/tasks.py:638 +#: workflows/tasks.py:641 msgid "Kommunikationswege und Support-Prozess erklärt" msgstr "Communication channels and support process explained" -#: workflows/tasks.py:641 +#: workflows/tasks.py:644 #, python-format msgid "%(item)s als zusätzliche Ausstattung besprochen" msgstr "%(item)s discussed as additional equipment" -#: workflows/tasks.py:643 +#: workflows/tasks.py:646 #, python-format msgid "Zusätzlicher Zugang besprochen: %(item)s" msgstr "Additional access discussed: %(item)s" -#: workflows/tasks.py:645 +#: workflows/tasks.py:648 #, python-format msgid "Übergabe-/Nachfolgekontext besprochen: %(value)s" msgstr "Handover / successor context reviewed: %(value)s" @@ -1097,6 +1164,7 @@ 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_change_form.html:33 #: workflows/templates/workflows/auth/password_reset_confirm.html:38 msgid "Passwort speichern" msgstr "Save password" @@ -1150,6 +1218,102 @@ msgstr "" msgid "Link anfordern" msgstr "Request link" +#: workflows/templates/workflows/account_profile.html:4 +#: workflows/templates/workflows/account_profile.html:20 +#: workflows/templates/workflows/includes/app_header.html:47 +msgid "Profil" +msgstr "Profile" + +#: workflows/templates/workflows/account_profile.html:19 +msgid "Konto" +msgstr "Account" + +#: workflows/templates/workflows/account_profile.html:21 +msgid "Ihre aktuelle Workdock-Kontoübersicht und wichtige Sicherheitsaktionen." +msgstr "Your current Workdock account overview and important security actions." + +#: workflows/templates/workflows/account_profile.html:54 +msgid "Klicken Sie auf das Bild, um ein neues Profilbild auszuwählen." +msgstr "Click the image to choose a new profile picture." + +#: workflows/templates/workflows/account_profile.html:78 +#: workflows/templates/workflows/user_management.html:76 +msgid "Letzte Anmeldung" +msgstr "Last login" + +#: workflows/templates/workflows/account_profile.html:88 +msgid "Kontodaten" +msgstr "Account details" + +#: workflows/templates/workflows/account_profile.html:89 +msgid "Die wichtigsten Stammdaten Ihres aktuellen Kontos." +msgstr "The most important master data of your current account." + +#: workflows/templates/workflows/account_profile.html:97 +#, fuzzy +#| msgid "In Bearbeitung" +msgid "Bearbeiten" +msgstr "Processing" + +#: workflows/templates/workflows/account_profile.html:104 +#: workflows/templates/workflows/onboarding_intro_session.html:27 +#: workflows/templates/workflows/request_timeline.html:66 +#: workflows/templates/workflows/user_management.html:71 +msgid "Name" +msgstr "Name" + +#: workflows/templates/workflows/account_profile.html:108 +#: workflows/templates/workflows/request_timeline.html:74 +#: workflows/templates/workflows/requests_dashboard.html:190 +#: workflows/templates/workflows/user_management.html:73 +#: workflows/templates/workflows/user_management.html:172 +msgid "E-Mail" +msgstr "Email" + +#: workflows/templates/workflows/account_profile.html:165 +#: workflows/templates/workflows/user_management.html:115 +msgid "Speichern" +msgstr "Save" + +#: workflows/templates/workflows/account_profile.html:166 +#: workflows/templates/workflows/base_shell.html:79 +#: workflows/templates/workflows/welcome_emails.html:134 +msgid "Abbrechen" +msgstr "Cancel" + +#: workflows/templates/workflows/account_profile.html:173 +msgid "Sicherheit & Aktionen" +msgstr "Security & actions" + +#: workflows/templates/workflows/account_profile.html:174 +msgid "Direkte Aktionen für Ihr Workdock-Konto." +msgstr "Direct actions for your Workdock account." + +#: workflows/templates/workflows/account_profile.html:179 +#: workflows/templates/workflows/account_profile.html:190 +#: workflows/templates/workflows/auth/password_change_form.html:4 +#: workflows/templates/workflows/auth/password_change_form.html:17 +#: workflows/templates/workflows/includes/app_header.html:48 +msgid "Passwort ändern" +msgstr "Change password" + +#: workflows/templates/workflows/account_profile.html:180 +msgid "Aktualisieren Sie Ihr Passwort direkt im Konto." +msgstr "Update your password directly in your account." + +#: workflows/templates/workflows/account_profile.html:184 +msgid "Sitzung" +msgstr "Session" + +#: workflows/templates/workflows/account_profile.html:185 +msgid "Sie können sich jederzeit sicher vom aktuellen Gerät abmelden." +msgstr "" + +#: workflows/templates/workflows/account_profile.html:193 +#: workflows/templates/workflows/includes/app_header.html:51 +msgid "Abmelden" +msgstr "Log out" + #: workflows/templates/workflows/app_registry.html:3 #, fuzzy #| msgid "Letzte Änderung" @@ -1430,6 +1594,28 @@ msgstr "" msgid "Noch keine Audit-Einträge vorhanden." msgstr "No requests available yet." +#: workflows/templates/workflows/auth/password_change_done.html:4 +#: workflows/templates/workflows/auth/password_change_done.html:17 +#: workflows/templates/workflows/user_management.html:174 +#, fuzzy +#| msgid "Passwort gespeichert" +msgid "Passwort geändert" +msgstr "Password saved" + +#: workflows/templates/workflows/auth/password_change_done.html:18 +msgid "Ihr Passwort wurde erfolgreich aktualisiert." +msgstr "" + +#: workflows/templates/workflows/auth/password_change_done.html:19 +msgid "Zum Profil" +msgstr "" + +#: workflows/templates/workflows/auth/password_change_form.html:18 +#, fuzzy +#| msgid "Bitte vergeben Sie jetzt ein neues Passwort für Ihr Konto." +msgid "Vergeben Sie ein neues Passwort für Ihr Konto." +msgstr "Please set a new password for your account now." + #: workflows/templates/workflows/backup_recovery.html:13 msgid "" "Datenbank- und Media-Backups erstellen und vorhandene Bundles sicher " @@ -1624,11 +1810,6 @@ msgstr "" msgid "Bitte bestätigen" msgstr "" -#: workflows/templates/workflows/base_shell.html:79 -#: workflows/templates/workflows/welcome_emails.html:134 -msgid "Abbrechen" -msgstr "Cancel" - #: workflows/templates/workflows/base_shell.html:80 msgid "Bestätigen" msgstr "" @@ -2024,16 +2205,12 @@ msgstr "" msgid "Open Release Checklist" msgstr "" -#: workflows/templates/workflows/home.html:26 -msgid "Abmelden" -msgstr "Log out" - -#: workflows/templates/workflows/home.html:34 +#: workflows/templates/workflows/home.html:18 #: workflows/templates/workflows/requests_dashboard.html:32 msgid "Operations Console" msgstr "Operations Console" -#: workflows/templates/workflows/home.html:36 +#: workflows/templates/workflows/home.html:20 msgid "" "Zentrale Arbeitsfläche für Anfragen, PDF-Generierung, E-Mail-Workflows und " "Ablage in Nextcloud." @@ -2041,48 +2218,48 @@ msgstr "" "Central workspace for requests, PDF generation, email workflows, and storage " "in Nextcloud." -#: workflows/templates/workflows/home.html:39 +#: workflows/templates/workflows/home.html:23 msgid "Rolle:" msgstr "Role:" -#: workflows/templates/workflows/home.html:41 +#: workflows/templates/workflows/home.html:25 msgid "Nextcloud:" msgstr "Nextcloud:" -#: workflows/templates/workflows/home.html:41 +#: workflows/templates/workflows/home.html:25 #: workflows/templates/workflows/integrations_setup.html:60 #: workflows/templates/workflows/user_management.html:103 msgid "aktiv" msgstr "active" -#: workflows/templates/workflows/home.html:41 +#: workflows/templates/workflows/home.html:25 #: workflows/templates/workflows/integrations_setup.html:60 #: workflows/templates/workflows/user_management.html:103 msgid "inaktiv" msgstr "inactive" -#: workflows/templates/workflows/home.html:44 +#: workflows/templates/workflows/home.html:28 #: workflows/templates/workflows/offboarding_success.html:20 #: workflows/templates/workflows/onboarding_success.html:20 msgid "E-Mail:" msgstr "Email:" -#: workflows/templates/workflows/home.html:44 +#: workflows/templates/workflows/home.html:28 #: workflows/templates/workflows/integrations_setup.html:122 #: workflows/templates/workflows/trial_management.html:49 msgid "Testmodus" msgstr "Test mode" -#: workflows/templates/workflows/home.html:44 +#: workflows/templates/workflows/home.html:28 #: workflows/templates/workflows/integrations_setup.html:122 msgid "Produktion" msgstr "Production" -#: workflows/templates/workflows/home.html:46 +#: workflows/templates/workflows/home.html:30 msgid "PDF + E-Mail Workflow bereit" msgstr "PDF + Email Workflow Ready" -#: workflows/templates/workflows/home.html:96 +#: workflows/templates/workflows/home.html:80 msgid "Tipp: Die letzten Vorgänge sehen Sie jederzeit im Anfragen Dashboard." msgstr "Tip: You can always see the latest requests in the Requests Dashboard." @@ -2661,12 +2838,6 @@ msgstr "" msgid "Mitarbeitende Person" msgstr "Employee" -#: workflows/templates/workflows/onboarding_intro_session.html:27 -#: workflows/templates/workflows/request_timeline.html:66 -#: workflows/templates/workflows/user_management.html:71 -msgid "Name" -msgstr "Name" - #: workflows/templates/workflows/onboarding_intro_session.html:29 msgid "Berufsbezeichnung" msgstr "Job title" @@ -2676,7 +2847,7 @@ msgid "Dienstliche E-Mail" msgstr "Work email" #: workflows/templates/workflows/onboarding_intro_session.html:31 -#: workflows/views.py:1025 +#: workflows/views.py:1062 msgid "Vertragsbeginn" msgstr "Contract start" @@ -2945,13 +3116,6 @@ msgstr "" msgid "Request Timeline" msgstr "" -#: workflows/templates/workflows/request_timeline.html:74 -#: workflows/templates/workflows/requests_dashboard.html:190 -#: workflows/templates/workflows/user_management.html:73 -#: workflows/templates/workflows/user_management.html:172 -msgid "E-Mail" -msgstr "Email" - #: workflows/templates/workflows/request_timeline.html:78 msgid "Hardware-Übergabetermin" msgstr "Hardware handover date" @@ -3325,10 +3489,6 @@ msgstr "User overview" 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:76 -msgid "Letzte Anmeldung" -msgstr "Last login" - #: workflows/templates/workflows/user_management.html:87 msgid "Sie selbst" msgstr "You" @@ -3337,10 +3497,6 @@ msgstr "You" msgid "Optional" msgstr "Optional" -#: workflows/templates/workflows/user_management.html:115 -msgid "Speichern" -msgstr "Save" - #: workflows/templates/workflows/user_management.html:119 msgid "Reset-Link senden" msgstr "" @@ -3403,12 +3559,6 @@ msgstr "" msgid "Einladung versendet" msgstr "Email sent" -#: workflows/templates/workflows/user_management.html:174 -#, fuzzy -#| msgid "Passwort gespeichert" -msgid "Passwort geändert" -msgstr "Password saved" - #: workflows/templates/workflows/user_management.html:180 #, fuzzy #| msgid "Es sind noch keine Benutzer vorhanden." @@ -3517,240 +3667,264 @@ msgstr "Devices, software, and access" msgid "Notizen und Freigabe" msgstr "Notes and approval" -#: workflows/views.py:135 workflows/views.py:1111 workflows/views.py:1116 +#: workflows/views.py:141 +#, fuzzy +#| msgid "Lokal gespeichert" +msgid "Profilbild gespeichert." +msgstr "Stored locally" + +#: workflows/views.py:143 +#, fuzzy +#| msgid "Passwort konnte nicht gespeichert werden" +msgid "Profilbild konnte nicht gespeichert werden." +msgstr "Password could not be saved" + +#: workflows/views.py:149 +#, fuzzy +#| msgid "Lokal gespeichert" +msgid "Profildaten gespeichert." +msgstr "Stored locally" + +#: workflows/views.py:151 +#, fuzzy +#| msgid "Passwort konnte nicht gespeichert werden" +msgid "Profildaten konnten nicht gespeichert werden." +msgstr "Password could not be saved" + +#: workflows/views.py:172 workflows/views.py:1148 workflows/views.py:1153 msgid "Sie haben keine Berechtigung für diese Aktion." msgstr "You do not have permission for this action." -#: workflows/views.py:216 +#: workflows/views.py:253 #, fuzzy #| msgid "Vorgänge" msgid "Vorgänge gelöscht" msgstr "Requests" -#: workflows/views.py:217 +#: workflows/views.py:254 msgid "Vorgang gelöscht" msgstr "" -#: workflows/views.py:218 +#: workflows/views.py:255 msgid "Vorgang erneut angestoßen" msgstr "" -#: workflows/views.py:219 +#: workflows/views.py:256 #, fuzzy #| msgid "Einweisung" msgid "Einweisungs-PDF erzeugt" msgstr "Introduction" -#: workflows/views.py:220 +#: workflows/views.py:257 #, fuzzy #| msgid "Live-Protokoll erzeugen" msgid "Live-Protokoll erzeugt" msgstr "Generate live protocol" -#: workflows/views.py:221 +#: workflows/views.py:258 #, fuzzy #| msgid "Einweisung wurde zurückgesetzt." msgid "Einweisung zurückgesetzt" msgstr "Introduction was reset." -#: workflows/views.py:222 +#: workflows/views.py:259 #, fuzzy #| msgid "Einweisung wurde als Entwurf gespeichert." msgid "Einweisung als Entwurf gespeichert" msgstr "Introduction was saved as draft." -#: workflows/views.py:223 +#: workflows/views.py:260 #, fuzzy #| msgid "Einweisung wurde als abgeschlossen gespeichert." msgid "Einweisung abgeschlossen" msgstr "Introduction was saved as completed." -#: workflows/views.py:224 +#: workflows/views.py:261 msgid "Formularoption gelöscht" msgstr "" -#: workflows/views.py:225 +#: workflows/views.py:262 #, fuzzy #| msgid "Optionen speichern" msgid "Formularoptionen gespeichert" msgstr "Save options" -#: workflows/views.py:226 +#: workflows/views.py:263 #, fuzzy #| msgid "Feldtexte speichern" msgid "Feldtexte gespeichert" msgstr "Save field text" -#: workflows/views.py:227 +#: workflows/views.py:264 #, fuzzy #| msgid "Offboarding-Anfrage speichern" msgid "Formularlayout gespeichert" msgstr "Save offboarding request" -#: workflows/views.py:228 +#: workflows/views.py:265 msgid "Einweisungs-Checkpunkt gelöscht" msgstr "" -#: workflows/views.py:229 +#: workflows/views.py:266 msgid "Einweisungs-Checkpunkt hinzugefügt" msgstr "" -#: workflows/views.py:230 +#: workflows/views.py:267 #, fuzzy #| msgid "Checkliste speichern" msgid "Einweisungs-Checkliste gespeichert" msgstr "Save checklist" -#: workflows/views.py:231 +#: workflows/views.py:268 #, fuzzy #| msgid "Welcome E-Mails" msgid "Welcome E-Mail sofort ausgelöst" msgstr "Welcome Emails" -#: workflows/views.py:232 +#: workflows/views.py:269 #, fuzzy #| msgid "Welcome-Einstellungen speichern" msgid "Welcome E-Mail Einstellungen gespeichert" msgstr "Save welcome settings" -#: workflows/views.py:233 +#: workflows/views.py:270 msgid "Welcome E-Mail Sammelaktion ausgeführt" msgstr "" -#: workflows/views.py:234 +#: workflows/views.py:271 #, fuzzy #| msgid "Welcome E-Mails" msgid "Welcome E-Mail pausiert" msgstr "Welcome Emails" -#: workflows/views.py:235 +#: workflows/views.py:272 #, fuzzy #| msgid "Welcome E-Mails" msgid "Welcome E-Mail fortgesetzt" msgstr "Welcome Emails" -#: workflows/views.py:236 +#: workflows/views.py:273 #, fuzzy #| msgid "Welcome E-Mails" msgid "Welcome E-Mail abgebrochen" msgstr "Welcome Emails" -#: workflows/views.py:237 +#: workflows/views.py:274 #, fuzzy #| msgid "SMTP-Test" msgid "SMTP-Test gesendet" msgstr "SMTP test" -#: workflows/views.py:238 +#: workflows/views.py:275 #, fuzzy #| msgid "Nextcloud-Test" msgid "Nextcloud-Testupload ausgeführt" msgstr "Nextcloud test" -#: workflows/views.py:239 +#: workflows/views.py:276 #, fuzzy #| msgid "Nextcloud schalten" msgid "Nextcloud-Modus umgeschaltet" msgstr "Toggle Nextcloud" -#: workflows/views.py:240 +#: workflows/views.py:277 msgid "E-Mail-Modus umgeschaltet" msgstr "" -#: workflows/views.py:241 +#: workflows/views.py:278 #, fuzzy #| msgid "Integrationen Setup" msgid "Integrationen gespeichert" msgstr "Integrations Setup" -#: workflows/views.py:242 +#: workflows/views.py:279 #, fuzzy #| msgid "Welcome-Einstellungen speichern" msgid "Nextcloud-Einstellungen gespeichert" msgstr "Save welcome settings" -#: workflows/views.py:243 +#: workflows/views.py:280 #, fuzzy #| msgid "Welcome-Einstellungen speichern" msgid "Mail-Einstellungen gespeichert" msgstr "Save welcome settings" -#: workflows/views.py:244 +#: workflows/views.py:281 #, fuzzy #| msgid "E-Mail Routing & Vorlagen speichern" msgid "E-Mail-Routing gespeichert" msgstr "Save email routing & templates" -#: workflows/views.py:245 +#: workflows/views.py:282 #, fuzzy #| msgid "Offboarding-Anfrage speichern" msgid "Benachrichtigungsregeln gespeichert" msgstr "Save offboarding request" -#: workflows/views.py:246 +#: workflows/views.py:283 #, fuzzy #| msgid "Anfrage gespeichert" msgid "Benutzer erstellt" msgstr "Request saved" -#: workflows/views.py:247 +#: workflows/views.py:284 msgid "Benutzer aktualisiert" msgstr "" -#: workflows/views.py:248 +#: workflows/views.py:285 msgid "Passwort-Reset-Link versendet" msgstr "" -#: workflows/views.py:249 +#: workflows/views.py:286 #, fuzzy #| msgid "Benutzerübersicht" msgid "Benutzer gelöscht" msgstr "User overview" -#: workflows/views.py:250 +#: workflows/views.py:287 #, fuzzy #| msgid "Anfrage gespeichert" msgid "Backup erstellt" msgstr "Request saved" -#: workflows/views.py:251 +#: workflows/views.py:288 msgid "Backup verifiziert" msgstr "" -#: workflows/views.py:252 +#: workflows/views.py:289 #, fuzzy #| msgid "Anfrage gespeichert" msgid "Backup gelöscht" msgstr "Request saved" -#: workflows/views.py:253 +#: workflows/views.py:290 #, fuzzy #| msgid "Welcome-Einstellungen speichern" msgid "Backup-Einstellungen gespeichert" msgstr "Save welcome settings" -#: workflows/views.py:254 +#: workflows/views.py:291 #, fuzzy #| msgid "Anfrage gespeichert" msgid "App-Registry gespeichert" msgstr "Request saved" -#: workflows/views.py:422 +#: workflows/views.py:459 #, fuzzy #| msgid "Anfrage gespeichert" msgid "App-Registry gespeichert." msgstr "Request saved" -#: workflows/views.py:521 +#: workflows/views.py:558 msgid "Für diesen Benutzer ist keine E-Mail-Adresse hinterlegt." msgstr "" -#: workflows/views.py:530 +#: workflows/views.py:567 #, python-format msgid "Zugangseinladung für %(username)s" msgstr "" -#: workflows/views.py:532 +#: workflows/views.py:569 #, python-format msgid "" "Hallo %(name)s,\n" @@ -3763,12 +3937,12 @@ msgid "" "Ihrem Administrator." msgstr "" -#: workflows/views.py:543 +#: workflows/views.py:580 #, python-format msgid "Passwort zurücksetzen für %(username)s" msgstr "" -#: workflows/views.py:545 +#: workflows/views.py:582 #, python-format msgid "" "Hallo %(name)s,\n" @@ -3781,7 +3955,7 @@ msgid "" "ignorieren." msgstr "" -#: workflows/views.py:583 +#: workflows/views.py:620 #, fuzzy #| msgid "" #| "Benutzer konnte nicht erstellt werden. Bitte prüfen Sie die Eingaben." @@ -3789,13 +3963,13 @@ msgid "" "Branding konnte nicht gespeichert werden. Bitte prüfen Sie die Eingaben." msgstr "User could not be created. Please check the input." -#: workflows/views.py:609 +#: workflows/views.py:646 #, fuzzy #| msgid "Offboarding-Anfrage speichern" msgid "Portal-Branding wurde gespeichert." msgstr "Save offboarding request" -#: workflows/views.py:640 +#: workflows/views.py:677 #, fuzzy #| msgid "" #| "Benutzer konnte nicht erstellt werden. Bitte prüfen Sie die Eingaben." @@ -3804,13 +3978,13 @@ msgid "" "Eingaben." msgstr "User could not be created. Please check the input." -#: workflows/views.py:667 +#: workflows/views.py:704 #, fuzzy #| msgid "Offboarding-Anfrage speichern" msgid "Firmenkonfiguration wurde gespeichert." msgstr "Save offboarding request" -#: workflows/views.py:699 +#: workflows/views.py:736 #, fuzzy #| msgid "" #| "Benutzer konnte nicht erstellt werden. Bitte prüfen Sie die Eingaben." @@ -3819,21 +3993,21 @@ msgid "" "Eingaben." msgstr "Trial configuration could not be saved. Please check the input." -#: workflows/views.py:726 +#: workflows/views.py:763 msgid "Trial-Konfiguration wurde gespeichert." msgstr "Trial configuration was saved." -#: workflows/views.py:743 +#: workflows/views.py:780 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:756 +#: workflows/views.py:793 #, 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:778 +#: workflows/views.py:815 #, fuzzy #| msgid "" #| "Der aktuell angemeldete Super Admin kann sich hier nicht selbst sperren " @@ -3844,14 +4018,14 @@ msgid "" msgstr "" "The currently signed-in super admin cannot lock or downgrade themselves here." -#: workflows/views.py:781 +#: workflows/views.py:818 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:784 +#: workflows/views.py:821 #, fuzzy #| msgid "" #| "Der aktuell angemeldete Super Admin kann sich hier nicht selbst sperren " @@ -3862,7 +4036,7 @@ msgid "" msgstr "" "The currently signed-in super admin cannot lock or downgrade themselves here." -#: workflows/views.py:787 +#: workflows/views.py:824 #, fuzzy #| msgid "" #| "Der aktuell angemeldete Super Admin kann sich hier nicht selbst sperren " @@ -3873,18 +4047,18 @@ msgid "" msgstr "" "The currently signed-in super admin cannot lock or downgrade themselves here." -#: workflows/views.py:804 +#: workflows/views.py:841 #, python-format msgid "Benutzer wurde aktualisiert: %(username)s" msgstr "User updated: %(username)s" -#: workflows/views.py:826 +#: workflows/views.py:863 #, 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:838 +#: workflows/views.py:875 #, fuzzy #| msgid "" #| "Der aktuell angemeldete Super Admin kann sich hier nicht selbst sperren " @@ -3894,7 +4068,7 @@ msgid "" msgstr "" "The currently signed-in super admin cannot lock or downgrade themselves here." -#: workflows/views.py:841 +#: workflows/views.py:878 #, fuzzy #| msgid "" #| "Der aktuell angemeldete Super Admin kann sich hier nicht selbst sperren " @@ -3904,7 +4078,7 @@ msgid "" msgstr "" "The currently signed-in super admin cannot lock or downgrade themselves here." -#: workflows/views.py:844 +#: workflows/views.py:881 #, fuzzy #| msgid "" #| "Der aktuell angemeldete Super Admin kann sich hier nicht selbst sperren " @@ -3913,7 +4087,7 @@ msgid "Der letzte aktive Platform Owner kann nicht gelöscht werden." msgstr "" "The currently signed-in super admin cannot lock or downgrade themselves here." -#: workflows/views.py:847 +#: workflows/views.py:884 #, fuzzy #| msgid "" #| "Der aktuell angemeldete Super Admin kann sich hier nicht selbst sperren " @@ -3922,121 +4096,121 @@ 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:860 +#: workflows/views.py:897 #, fuzzy, python-format #| msgid "Benutzer wurde erstellt: %(username)s" msgid "Benutzer wurde gelöscht: %(username)s" msgstr "User created: %(username)s" -#: workflows/views.py:949 +#: workflows/views.py:986 #, python-format msgid "Backup wurde erstellt: %(name)s" msgstr "" -#: workflows/views.py:951 +#: workflows/views.py:988 #, python-format msgid "Backup konnte nicht erstellt werden: %(error)s" msgstr "" -#: workflows/views.py:967 +#: workflows/views.py:1004 #, python-format msgid "Backup wurde verifiziert: %(name)s" msgstr "" -#: workflows/views.py:969 +#: workflows/views.py:1006 #, python-format msgid "Backup-Verifikation fehlgeschlagen: %(error)s" msgstr "" -#: workflows/views.py:985 +#: workflows/views.py:1022 #, python-format msgid "Backup wurde gelöscht: %(name)s" msgstr "" -#: workflows/views.py:987 +#: workflows/views.py:1024 #, python-format msgid "Backup konnte nicht gelöscht werden: %(error)s" msgstr "" -#: workflows/views.py:1013 +#: workflows/views.py:1050 #, fuzzy #| msgid "Anfrage gespeichert" msgid "Anfrage erstellt" msgstr "Request saved" -#: workflows/views.py:1015 +#: workflows/views.py:1052 #, fuzzy, python-format #| msgid "Sitzungsstatus" msgid "Status: %(status)s" msgstr "Session status" -#: workflows/views.py:1027 +#: workflows/views.py:1064 #, fuzzy #| msgid "Geplant für" msgid "Geplanter Start" msgstr "Scheduled for" -#: workflows/views.py:1037 +#: workflows/views.py:1074 msgid "Geräteübergabe / Hardware-Abholung" msgstr "" -#: workflows/views.py:1039 +#: workflows/views.py:1076 msgid "Geplanter Hardware-Termin" msgstr "" -#: workflows/views.py:1048 +#: workflows/views.py:1085 #, fuzzy #| msgid "Noch nicht verfügbar" msgid "PDF verfügbar" msgstr "Not available yet" -#: workflows/views.py:1074 +#: workflows/views.py:1111 #, fuzzy #| msgid "Einweisung" msgid "Einweisungssitzung" msgstr "Introduction" -#: workflows/views.py:1086 +#: workflows/views.py:1123 #, fuzzy #| msgid "Welcome E-Mails" msgid "Welcome E-Mail" msgstr "Welcome Emails" -#: workflows/views.py:1125 +#: workflows/views.py:1162 msgid "Keine Einträge ausgewählt." msgstr "No entries selected." -#: workflows/views.py:1168 +#: workflows/views.py:1205 #, python-format msgid "%(count)s Eintrag/Einträge gelöscht." msgstr "%(count)s entry/entries deleted." -#: workflows/views.py:1170 +#: workflows/views.py:1207 #, python-format msgid "%(count)s Auswahl(en) konnten nicht verarbeitet werden." msgstr "%(count)s selection(s) could not be processed." -#: workflows/views.py:1172 +#: workflows/views.py:1209 msgid "Keine passenden Einträge gefunden." msgstr "No matching entries found." -#: workflows/views.py:1400 +#: workflows/views.py:1437 msgid "Einweisungs- und Übergabeprotokoll wurde erzeugt." msgstr "Introduction and handover protocol was generated." -#: workflows/views.py:1417 +#: workflows/views.py:1454 msgid "Einweisungsprotokoll aus Live-Status wurde erzeugt." msgstr "Introduction protocol from live status was generated." -#: workflows/views.py:1446 +#: workflows/views.py:1483 msgid "Einweisung wurde zurückgesetzt." msgstr "Introduction was reset." -#: workflows/views.py:1460 +#: workflows/views.py:1497 msgid "Einweisung wurde als abgeschlossen gespeichert." msgstr "Introduction was saved as completed." -#: workflows/views.py:1473 +#: workflows/views.py:1510 msgid "Einweisung wurde als Entwurf gespeichert." msgstr "Introduction was saved as draft." diff --git a/backend/workflows/forms.py b/backend/workflows/forms.py index fa15b03..477a401 100644 --- a/backend/workflows/forms.py +++ b/backend/workflows/forms.py @@ -8,7 +8,7 @@ from django.utils.translation import get_language, gettext as _, gettext_lazy from .branding import get_company_email_domain from .form_builder import apply_form_field_config -from .models import EmployeeProfile, FormOption, OffboardingRequest, OnboardingRequest, PortalBranding, PortalCompanyConfig, PortalTrialConfig, WorkflowConfig +from .models import EmployeeProfile, FormOption, OffboardingRequest, OnboardingRequest, PortalBranding, PortalCompanyConfig, PortalTrialConfig, UserProfile, WorkflowConfig from .roles import ROLE_ADMIN, ROLE_GROUP_NAMES, ROLE_IT_STAFF, ROLE_LABELS, ROLE_PLATFORM_OWNER, ROLE_STAFF, ROLE_SUPER_ADMIN, assign_user_role @@ -142,6 +142,85 @@ class AppPasswordChangeForm(PasswordChangeForm): ) +class AccountAvatarForm(forms.ModelForm): + class Meta: + model = UserProfile + fields = ['avatar_image'] + labels = { + 'avatar_image': gettext_lazy('Profilbild'), + } + widgets = { + 'avatar_image': forms.ClearableFileInput( + attrs={ + 'accept': '.png,.jpg,.jpeg,.webp,.svg', + 'onchange': 'this.form.submit()', + } + ), + } + + def clean_avatar_image(self): + avatar = self.cleaned_data.get('avatar_image') + if not avatar: + return avatar + if getattr(avatar, 'size', 0) > 5 * 1024 * 1024: + raise forms.ValidationError(_('Das Profilbild darf maximal 5 MB groß sein.')) + return avatar + + +class AccountDetailsForm(forms.Form): + first_name = forms.CharField(label=gettext_lazy('Vorname'), max_length=150, required=False) + last_name = forms.CharField(label=gettext_lazy('Nachname'), max_length=150, required=False) + email = forms.EmailField(label=gettext_lazy('E-Mail-Adresse'), required=False) + phone_number = forms.CharField(label=gettext_lazy('Telefon'), max_length=80, required=False) + mobile_number = forms.CharField(label=gettext_lazy('Mobil'), max_length=80, required=False) + job_title = forms.CharField(label=gettext_lazy('Position'), max_length=255, required=False) + department = forms.CharField(label=gettext_lazy('Abteilung'), max_length=255, required=False) + location = forms.CharField(label=gettext_lazy('Standort'), max_length=255, required=False) + contact_notes = forms.CharField( + label=gettext_lazy('Hinweise'), + max_length=255, + required=False, + widget=forms.Textarea(attrs={'rows': 3}), + ) + + def __init__(self, *args, user=None, profile=None, **kwargs): + self.user = user + self.profile = profile + initial = kwargs.setdefault('initial', {}) + if user is not None and not args: + initial.setdefault('first_name', user.first_name) + initial.setdefault('last_name', user.last_name) + initial.setdefault('email', user.email) + if profile is not None and not args: + initial.setdefault('phone_number', profile.phone_number) + initial.setdefault('mobile_number', profile.mobile_number) + initial.setdefault('job_title', profile.job_title) + initial.setdefault('department', profile.department) + initial.setdefault('location', profile.location) + initial.setdefault('contact_notes', profile.contact_notes) + super().__init__(*args, **kwargs) + + def clean_email(self): + return (self.cleaned_data.get('email') or '').strip().lower() + + def save(self): + self.user.first_name = self.cleaned_data.get('first_name', '').strip() + self.user.last_name = self.cleaned_data.get('last_name', '').strip() + self.user.email = self.cleaned_data.get('email', '').strip() + self.user.save(update_fields=['first_name', 'last_name', 'email']) + + self.profile.phone_number = self.cleaned_data.get('phone_number', '').strip() + self.profile.mobile_number = self.cleaned_data.get('mobile_number', '').strip() + self.profile.job_title = self.cleaned_data.get('job_title', '').strip() + self.profile.department = self.cleaned_data.get('department', '').strip() + self.profile.location = self.cleaned_data.get('location', '').strip() + self.profile.contact_notes = self.cleaned_data.get('contact_notes', '').strip() + self.profile.save( + update_fields=['phone_number', 'mobile_number', 'job_title', 'department', 'location', 'contact_notes', 'updated_at'] + ) + return self.user, self.profile + + 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) diff --git a/backend/workflows/migrations/0048_userprofile.py b/backend/workflows/migrations/0048_userprofile.py new file mode 100644 index 0000000..a35af45 --- /dev/null +++ b/backend/workflows/migrations/0048_userprofile.py @@ -0,0 +1,42 @@ +from django.conf import settings +from django.core.validators import FileExtensionValidator +from django.db import migrations, models +import django.db.models.deletion + + +def create_profiles_for_existing_users(apps, schema_editor): + User = apps.get_model(*settings.AUTH_USER_MODEL.split('.')) + UserProfile = apps.get_model('workflows', 'UserProfile') + for user in User.objects.all().iterator(): + UserProfile.objects.get_or_create(user=user) + + +class Migration(migrations.Migration): + + dependencies = [ + ('workflows', '0046_alter_onboardingrequest_phone_number'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='UserProfile', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('avatar_image', models.FileField(blank=True, null=True, upload_to='profiles/', validators=[FileExtensionValidator(allowed_extensions=['png', 'jpg', 'jpeg', 'webp', 'svg'])])), + ('phone_number', models.CharField(blank=True, default='', max_length=80)), + ('mobile_number', models.CharField(blank=True, default='', max_length=80)), + ('job_title', models.CharField(blank=True, default='', max_length=255)), + ('department', models.CharField(blank=True, default='', max_length=255)), + ('location', models.CharField(blank=True, default='', max_length=255)), + ('contact_notes', models.CharField(blank=True, default='', max_length=255)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'User Profile', + 'verbose_name_plural': 'User Profiles', + }, + ), + migrations.RunPython(create_profiles_for_existing_users, migrations.RunPython.noop), + ] diff --git a/backend/workflows/models.py b/backend/workflows/models.py index 92a8a4d..1d2633c 100644 --- a/backend/workflows/models.py +++ b/backend/workflows/models.py @@ -25,6 +25,30 @@ class EmployeeProfile(models.Model): return f"{self.full_name} <{self.work_email}>" +class UserProfile(models.Model): + user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='profile') + avatar_image = models.FileField( + upload_to='profiles/', + blank=True, + null=True, + validators=[FileExtensionValidator(allowed_extensions=['png', 'jpg', 'jpeg', 'webp', 'svg'])], + ) + phone_number = models.CharField(max_length=80, blank=True, default='') + mobile_number = models.CharField(max_length=80, blank=True, default='') + job_title = models.CharField(max_length=255, blank=True, default='') + department = models.CharField(max_length=255, blank=True, default='') + location = models.CharField(max_length=255, blank=True, default='') + contact_notes = models.CharField(max_length=255, blank=True, default='') + updated_at = models.DateTimeField(auto_now=True) + + class Meta: + verbose_name = 'User Profile' + verbose_name_plural = 'User Profiles' + + def __str__(self) -> str: + return getattr(self.user, 'username', '') or str(self.user_id) + + class PortalBranding(models.Model): name = models.CharField(max_length=80, default='Default', unique=True) portal_title = models.CharField(max_length=255, default='Workdock') diff --git a/backend/workflows/roles.py b/backend/workflows/roles.py index 1c4d684..9686f3d 100644 --- a/backend/workflows/roles.py +++ b/backend/workflows/roles.py @@ -131,9 +131,16 @@ def user_has_capability(user, capability: str) -> bool: def template_role_context(user) -> dict[str, object]: role_key = get_user_role_key(user) + avatar_url = '' + if getattr(user, 'is_authenticated', False): + profile = getattr(user, 'profile', None) + avatar = getattr(profile, 'avatar_image', None) + if avatar: + avatar_url = getattr(avatar, 'url', '') or '' return { 'role_key': role_key, 'role_label': str(ROLE_LABELS[role_key]), + 'user_avatar_url': avatar_url, 'can_manage_product_branding': user_has_capability(user, 'manage_product_branding'), 'can_manage_company_config': user_has_capability(user, 'manage_company_config'), 'can_manage_trial_lifecycle': user_has_capability(user, 'manage_trial_lifecycle'), diff --git a/backend/workflows/signals.py b/backend/workflows/signals.py index d761dbb..ad2d5bc 100644 --- a/backend/workflows/signals.py +++ b/backend/workflows/signals.py @@ -1,6 +1,8 @@ -from django.db.models.signals import post_migrate +from django.conf import settings +from django.db.models.signals import post_migrate, post_save from django.dispatch import receiver +from .models import UserProfile from .roles import ensure_bootstrap_role_assignments, ensure_role_groups @@ -10,3 +12,9 @@ def workflows_post_migrate(sender, **kwargs): return ensure_role_groups() ensure_bootstrap_role_assignments() + + +@receiver(post_save, sender=settings.AUTH_USER_MODEL) +def ensure_user_profile(sender, instance, created, **kwargs): + if created: + UserProfile.objects.get_or_create(user=instance) diff --git a/backend/workflows/static/workflows/css/account.css b/backend/workflows/static/workflows/css/account.css new file mode 100644 index 0000000..4c5d8ba --- /dev/null +++ b/backend/workflows/static/workflows/css/account.css @@ -0,0 +1,486 @@ +body { + margin: 0; + min-height: 100vh; + font-family: "Segoe UI", "Helvetica Neue", Arial, sans-serif; + background: + radial-gradient(76% 96% at 8% 10%, rgba(0, 0, 120, 0.12), rgba(0, 0, 120, 0)), + radial-gradient(64% 86% at 92% 88%, rgba(163, 32, 32, 0.1), rgba(163, 32, 32, 0)), + linear-gradient(160deg, #eef3ff 0%, #f8fbff 52%, #edf4ff 100%); + padding: 24px; +} + +.shell { + background: rgba(255, 255, 255, 0.78); + backdrop-filter: blur(12px); + border: 1px solid rgba(217, 227, 238, 0.9); + border-radius: 28px; + box-shadow: 0 22px 48px rgba(18, 34, 56, 0.14); + overflow: hidden; +} + +.account-shell-body { + padding: 28px; + background: + radial-gradient(90% 120% at 10% 0%, rgba(31, 79, 214, 0.06), rgba(31, 79, 214, 0)), + linear-gradient(180deg, rgba(255,255,255,0.72), rgba(248,251,255,0.48)); +} + +.account-page { + width: min(1120px, 100%); + margin: 0 auto; + display: grid; + gap: 22px; +} + +.account-hero { + display: flex; + justify-content: space-between; + gap: 18px; + align-items: flex-start; + padding: 26px 28px; + border: 1px solid #d9e3f0; + border-radius: 24px; + background: + radial-gradient(circle at top right, rgba(30, 64, 175, 0.1), transparent 24%), + linear-gradient(135deg, rgba(255,255,255,0.96), rgba(244,248,255,0.9)); + box-shadow: 0 14px 34px rgba(28, 45, 79, 0.08); +} + +.account-kicker { + display: inline-flex; + margin-bottom: 10px; + padding: 6px 10px; + border-radius: 999px; + background: rgba(0, 0, 120, 0.08); + color: #203b74; + font-size: 11px; + font-weight: 800; + letter-spacing: 0.05em; + text-transform: uppercase; +} + +.account-hero h1 { + margin: 0 0 8px; + font-size: 32px; + color: #132238; +} + +.account-hero p { + margin: 0; + max-width: 620px; + color: #617389; + line-height: 1.55; +} + +.account-hero-badges { + display: flex; + gap: 10px; + flex-wrap: wrap; + justify-content: flex-end; +} + +.account-chip { + display: inline-flex; + align-items: center; + min-height: 38px; + padding: 0 14px; + border-radius: 999px; + background: #0f2e8a; + color: #fff; + font-size: 12px; + font-weight: 800; + letter-spacing: 0.03em; +} + +.account-chip-muted { + background: #edf3ff; + color: #35507e; + border: 1px solid #d5deee; +} + +.account-layout { + display: grid; + grid-template-columns: 320px minmax(0, 1fr); + gap: 22px; + align-items: start; +} + +.account-profile-card, +.account-panel { + border: 1px solid #d9e3f0; + border-radius: 22px; + background: rgba(255, 255, 255, 0.94); + box-shadow: 0 14px 32px rgba(28, 45, 79, 0.09); +} + +.account-profile-card { + padding: 24px; + position: sticky; + top: 24px; +} + +.account-avatar-form { + display: grid; + gap: 10px; +} + +.account-avatar-wrap { + position: relative; + display: inline-flex; + width: fit-content; + cursor: pointer; +} + +.account-avatar { + width: 84px; + height: 84px; + border-radius: 24px; + display: inline-flex; + align-items: center; + justify-content: center; + background: linear-gradient(180deg, #000078, #2943b6); + color: #fff; + font-size: 28px; + font-weight: 800; + letter-spacing: 0.04em; + text-transform: uppercase; + box-shadow: inset 0 1px 0 rgba(255,255,255,0.22); +} + +.account-avatar-image { + width: 84px; + height: 84px; + object-fit: cover; + display: block; + border-radius: 24px; + border: 1px solid #dce5f2; + box-shadow: 0 12px 24px rgba(18, 34, 56, 0.12); +} + +.account-avatar-edit { + position: absolute; + right: -4px; + bottom: -4px; + width: 30px; + height: 30px; + border-radius: 50%; + display: inline-flex; + align-items: center; + justify-content: center; + background: #132d8a; + color: #fff; + font-size: 14px; + font-weight: 800; + border: 2px solid #fff; + box-shadow: 0 8px 18px rgba(18, 34, 56, 0.16); +} + +.account-avatar-hint { + margin: 0; + color: #617389; + font-size: 12px; + line-height: 1.45; +} + +.account-avatar-error { + color: #ab1e1e; + font-size: 12px; + line-height: 1.4; +} + +.account-profile-copy { + margin-top: 18px; +} + +.account-profile-copy h2 { + margin: 0 0 6px; + font-size: 24px; + color: #132238; +} + +.account-profile-copy p { + margin: 0; + color: #617389; + line-height: 1.45; + word-break: break-word; +} + +.account-profile-meta { + display: grid; + gap: 12px; + margin-top: 22px; +} + +.account-profile-meta div { + padding: 12px 14px; + border-radius: 14px; + background: #f7faff; + border: 1px solid #dce6f2; +} + +.account-profile-meta span { + display: block; + margin-bottom: 4px; + color: #6b7a90; + font-size: 12px; +} + +.account-profile-meta strong { + color: #132238; + font-size: 14px; + line-height: 1.4; +} + +.account-main { + display: grid; + gap: 22px; +} + +.account-panel { + padding: 24px; +} + +.account-panel-head { + margin-bottom: 18px; + display: flex; + justify-content: space-between; + gap: 14px; + align-items: flex-start; +} + +.account-panel-head h2 { + margin: 0 0 6px; + font-size: 20px; + color: #132238; +} + +.account-panel-head p { + margin: 0; + color: #617389; + line-height: 1.5; +} + +.account-detail-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 14px; +} + +.account-detail-wide { + grid-column: 1 / -1; +} + +.account-detail { + padding: 14px 16px; + border-radius: 16px; + background: #f9fbff; + border: 1px solid #dbe5f2; +} + +.account-detail span { + display: block; + margin-bottom: 6px; + color: #6b7a90; + font-size: 12px; +} + +.account-detail strong { + color: #132238; + font-size: 14px; + line-height: 1.45; + word-break: break-word; +} + +.account-action-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 14px; + margin-bottom: 18px; +} + +.account-action-card { + display: grid; + gap: 6px; + padding: 16px 18px; + border-radius: 18px; + border: 1px solid #dbe5f2; + background: + radial-gradient(circle at top right, rgba(30, 64, 175, 0.08), transparent 28%), + #f9fbff; + color: inherit; + text-decoration: none; + transition: transform 160ms cubic-bezier(0.2, 0.8, 0.2, 1), box-shadow 160ms cubic-bezier(0.2, 0.8, 0.2, 1); +} + +.account-action-card:hover { + transform: translateY(-1px); + box-shadow: 0 10px 24px rgba(28, 45, 79, 0.08); +} + +.account-action-card strong { + color: #132238; + font-size: 15px; +} + +.account-action-card span { + color: #617389; + font-size: 13px; + line-height: 1.5; +} + +.account-action-card-muted { + cursor: default; +} + +.account-action-card-muted:hover { + transform: none; + box-shadow: none; +} + +.account-actions { + display: flex; + gap: 10px; +} + +.account-actions .btn { + width: auto; +} + +.account-actions form { + margin: 0; +} + +.account-inline-view.is-hidden, +.account-inline-form.is-hidden { + display: none; +} + +.account-inline-edit-trigger { + min-width: 112px; +} + +.account-form-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 14px; +} + +.account-form-field { + display: grid; + gap: 6px; +} + +.account-form-field-wide { + grid-column: 1 / -1; +} + +.account-form-field label { + color: #132238; + font-size: 13px; + font-weight: 700; +} + +.account-form-field input, +.account-form-field textarea { + width: 100%; + box-sizing: border-box; + padding: 10px 12px; + border: 1px solid #cbd5e1; + border-radius: 12px; + min-height: 44px; + font: inherit; + background: #fff; + transition: border-color 180ms cubic-bezier(0.2, 0.8, 0.2, 1), box-shadow 180ms cubic-bezier(0.2, 0.8, 0.2, 1); +} + +.account-form-field textarea { + min-height: 104px; + resize: vertical; +} + +.account-form-field input:focus, +.account-form-field textarea:focus { + outline: none; + border-color: rgba(0, 0, 120, 0.3); + box-shadow: 0 0 0 4px rgba(0, 0, 120, 0.08); +} + +.account-form-field.has-error input, +.account-form-field.has-error textarea { + border-color: #e3a3a3; + background: #fffafa; + box-shadow: 0 0 0 4px rgba(185, 28, 28, 0.06); +} + +.account-form-error { + color: #ab1e1e; + font-size: 12px; + line-height: 1.4; +} + +.account-inline-actions { + display: flex; + gap: 10px; + margin-top: 16px; +} + +@media (max-width: 980px) { + .account-layout { + grid-template-columns: 1fr; + } + + .account-profile-card { + position: static; + } +} + +@media (max-width: 760px) { + body { + padding: 14px; + } + + .account-shell-body { + padding: 16px; + } + + .account-hero, + .account-panel, + .account-profile-card { + padding: 18px; + border-radius: 18px; + } + + .account-hero { + flex-direction: column; + } + + .account-hero h1 { + font-size: 26px; + } + + .account-hero-badges { + justify-content: flex-start; + } + + .account-detail-grid, + .account-action-grid, + .account-form-grid { + grid-template-columns: 1fr; + } + + .account-actions { + flex-direction: column; + } + + .account-inline-actions { + flex-direction: column; + } + + .account-actions .btn { + width: 100%; + } + + .account-panel-head { + flex-direction: column; + } +} diff --git a/backend/workflows/static/workflows/css/app_chrome.css b/backend/workflows/static/workflows/css/app_chrome.css index aba6be6..addc72f 100644 --- a/backend/workflows/static/workflows/css/app_chrome.css +++ b/backend/workflows/static/workflows/css/app_chrome.css @@ -190,7 +190,7 @@ align-items: center; gap: 10px; min-height: 44px; - padding: 6px 10px 6px 6px; + padding: 6px 10px 6px 8px; border: 1px solid var(--app-line); border-radius: 999px; background: rgba(248, 251, 255, 0.92); @@ -217,18 +217,27 @@ } .app-user-avatar { - width: 32px; - height: 32px; + width: 28px; + height: 28px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; background: linear-gradient(180deg, var(--app-brand-blue), #1d3ca8); color: #fff; - font-size: 11px; + font-size: 10px; font-weight: 800; letter-spacing: 0.04em; text-transform: uppercase; + overflow: hidden; + flex: 0 0 28px; +} + +.app-user-avatar-image { + width: 100%; + height: 100%; + object-fit: cover; + display: block; } .app-user-copy { diff --git a/backend/workflows/templates/workflows/account_profile.html b/backend/workflows/templates/workflows/account_profile.html index f5dacb1..10a5202 100644 --- a/backend/workflows/templates/workflows/account_profile.html +++ b/backend/workflows/templates/workflows/account_profile.html @@ -8,45 +8,220 @@ {% endblock %} {% block extra_css %} - + {% endblock %} {% block shell_body %} -