Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e55434f406 | ||
|
|
a889071b71 |
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@govoplan/access-webui",
|
"name": "@govoplan/access-webui",
|
||||||
"version": "0.1.21",
|
"version": "0.1.23",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "webui/src/index.ts",
|
"main": "webui/src/index.ts",
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "govoplan-access"
|
name = "govoplan-access"
|
||||||
version = "0.1.21"
|
version = "0.1.23"
|
||||||
description = "GovOPlaN access platform module with identity, auth, RBAC, and scope primitives."
|
description = "GovOPlaN access platform module with identity, auth, RBAC, and scope primitives."
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
"""GovOPlaN access platform module."""
|
"""GovOPlaN access platform module."""
|
||||||
|
|
||||||
__version__ = "0.1.21"
|
__version__ = "0.1.23"
|
||||||
|
|||||||
@@ -0,0 +1,326 @@
|
|||||||
|
"""German translations for public structured documentation metadata."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
|
GERMAN_STRUCTURED_TRANSLATIONS: dict[str, dict[str, Any]] = {'access.reference.admin-access-fields': {'fields': [{'admin_description': 'Auf dem Konto und den '
|
||||||
|
'Mitglieder-Payloads '
|
||||||
|
'gespeichert. Es muss '
|
||||||
|
'normalisiert und '
|
||||||
|
'eindeutig für das '
|
||||||
|
'entsprechende '
|
||||||
|
'Login-Konto sein.',
|
||||||
|
'api_field': 'email',
|
||||||
|
'api_path': '/api/v1/admin/users',
|
||||||
|
'field_id': 'access.user.email',
|
||||||
|
'label': 'E-Mail',
|
||||||
|
'permission_scope': 'access:membership:create',
|
||||||
|
'provenance': 'Mandantenmitgliedschaft oder '
|
||||||
|
'Kontosuche.',
|
||||||
|
'user_description': 'Die Adresse, die '
|
||||||
|
'verwendet wird, um die '
|
||||||
|
'Person zu '
|
||||||
|
'identifizieren, wenn '
|
||||||
|
'sie sich anmelden.',
|
||||||
|
'validation': 'Muss eine gültige '
|
||||||
|
'E-Mail-Adresse sein.'},
|
||||||
|
{'admin_description': 'Wird, sofern verfügbar, '
|
||||||
|
'in Benutzer- und '
|
||||||
|
'Kontoantworten als '
|
||||||
|
'display_name ausgegeben.',
|
||||||
|
'api_field': 'display_name',
|
||||||
|
'api_path': '/api/v1/admin/users',
|
||||||
|
'field_id': 'access.user.display_name',
|
||||||
|
'label': 'Anzeigename',
|
||||||
|
'permission_scope': 'access:membership:update',
|
||||||
|
'provenance': 'Profil der '
|
||||||
|
'Mandantenmitgliedschaft.',
|
||||||
|
'user_description': 'Der lesbare Name, der '
|
||||||
|
'in Benutzerlisten und '
|
||||||
|
'Bewertungsbildschirmen '
|
||||||
|
'angezeigt wird.',
|
||||||
|
'validation': 'Menschenlesbarer Text; Halten '
|
||||||
|
'Sie ihn für Administratoren '
|
||||||
|
'erkennbar.'},
|
||||||
|
{'admin_description': 'Wird beim Aktualisieren '
|
||||||
|
'einer Benutzer- oder '
|
||||||
|
'Gruppenmitgliedschaft '
|
||||||
|
'als group_ids übertragen.',
|
||||||
|
'api_field': 'group_ids',
|
||||||
|
'api_path': '/api/v1/admin/users/{user_id}',
|
||||||
|
'field_id': 'access.user.groups',
|
||||||
|
'label': 'Gruppen',
|
||||||
|
'permission_scope': 'access:group:manage_members',
|
||||||
|
'provenance': 'Benutzergruppenmitgliedschaftszeilen.',
|
||||||
|
'user_description': 'Gemeinsame Zugriffsbündel, '
|
||||||
|
'die Rollen für viele '
|
||||||
|
'Personen gleichzeitig '
|
||||||
|
'hinzufügen können.',
|
||||||
|
'validation': 'Gruppen müssen zum gleichen '
|
||||||
|
'Mandant gehören.'},
|
||||||
|
{'admin_description': 'Wird bei '
|
||||||
|
'Aktualisierungsanforderungen '
|
||||||
|
'für Benutzer- und '
|
||||||
|
'Gruppenrollen als role_ids '
|
||||||
|
'übertragen.',
|
||||||
|
'api_field': 'role_ids',
|
||||||
|
'api_path': '/api/v1/admin/users/{user_id}',
|
||||||
|
'field_id': 'access.user.roles',
|
||||||
|
'label': 'Rollen',
|
||||||
|
'permission_scope': 'access:role:assign',
|
||||||
|
'provenance': 'Direkte Benutzerrollen plus '
|
||||||
|
'Gruppenrollenvererbung.',
|
||||||
|
'user_description': 'Direktzugangszuschüsse, '
|
||||||
|
'die einer Person '
|
||||||
|
'zugewiesen oder von '
|
||||||
|
'Gruppen geerbt wurden.',
|
||||||
|
'validation': 'Rollen müssen zuordenbar sein '
|
||||||
|
'und dürfen das '
|
||||||
|
'Delegationslimit der '
|
||||||
|
'handelnden Person nicht '
|
||||||
|
'überschreiten.'},
|
||||||
|
{'admin_description': 'Bildet Scopes beim '
|
||||||
|
'Erstellen eines '
|
||||||
|
'API-Schlüssel zu und '
|
||||||
|
'wird mit den aktuellen '
|
||||||
|
'Berechtigungen des '
|
||||||
|
'Besitzers geschnitten.',
|
||||||
|
'api_field': 'scopes',
|
||||||
|
'api_path': '/api/v1/admin/api-keys',
|
||||||
|
'field_id': 'access.api_key.scopes',
|
||||||
|
'label': 'Anwendungsbereiche',
|
||||||
|
'permission_scope': 'access:api_key:create',
|
||||||
|
'provenance': 'API-Schlüssel Grant plus '
|
||||||
|
'Eigentümerdelegation.',
|
||||||
|
'user_description': 'Die Aktionen, die ein '
|
||||||
|
'API-Schlüssel ausführen '
|
||||||
|
'kann.',
|
||||||
|
'validation': 'Verwenden Sie möglichst enge '
|
||||||
|
'Berechtigungsbereiche.'}]},
|
||||||
|
'access.reference.personal-navigation': {'outcome': 'Die Seitenschiene des Benutzers spiegelt die '
|
||||||
|
'persönlichen Präferenzen wider, während '
|
||||||
|
'verschlossene und unzugängliche Einträge '
|
||||||
|
'durch übergeordnete Richtlinien geregelt '
|
||||||
|
'bleiben.'},
|
||||||
|
'access.workflow.configuration-packages': {'limitations': ['Die Paketübernahme installiert keine '
|
||||||
|
'fehlenden Module.',
|
||||||
|
'Die anbieterübergreifende Übernahme ist keine atomar '
|
||||||
|
'verteilte Transaktion.',
|
||||||
|
'Generisches Rollback hängt von einem '
|
||||||
|
'beibehaltenen '
|
||||||
|
'vor der Übernahme erstellten Datenbank-Snapshot ab.'],
|
||||||
|
'operational_consequences': ['Ein abgestandener oder '
|
||||||
|
'blockierter Preflight '
|
||||||
|
'muss vor der Anwendung '
|
||||||
|
'erneut durchgeführt '
|
||||||
|
'werden.',
|
||||||
|
'Eine teilweise Anwendung '
|
||||||
|
'erfordert eine '
|
||||||
|
'Wiederherstellung, bevor '
|
||||||
|
'das Paket erneut '
|
||||||
|
'getestet wird.',
|
||||||
|
'Geheimwerte bleiben '
|
||||||
|
'außerhalb tragbarer '
|
||||||
|
'Fragmente und '
|
||||||
|
'Herkunft.']},
|
||||||
|
'access.workflow.data-subject-request': {'limitations': ['Module ohne DSAR-Anbieter werden als '
|
||||||
|
'Deckungslücken gemeldet.',
|
||||||
|
'Globale Konten und Identitäten werden '
|
||||||
|
'nicht automatisch gelöscht.']},
|
||||||
|
'access.workflow.grant-user-access': {'outcome': 'Eine Person kann sich beim Mandant anmelden und '
|
||||||
|
'erhält den beabsichtigten Zugang durch Gruppen '
|
||||||
|
'und Rollen.',
|
||||||
|
'prerequisites': ['Sie können Admin öffnen.',
|
||||||
|
'Sie können Benutzer, Gruppen und Rollen '
|
||||||
|
'lesen.',
|
||||||
|
'Schreib- oder Zuweisungsaktionen '
|
||||||
|
'erfordern übereinstimmende '
|
||||||
|
'Verwaltungsberechtigungen.'],
|
||||||
|
'result': 'Die Mitgliedschaft hat die beabsichtigten '
|
||||||
|
'effektiven Berechtigungen und keine breiteren '
|
||||||
|
'Rollen als nötig.',
|
||||||
|
'steps': ['Öffnen Sie Admin und gehen Sie zu Benutzern.',
|
||||||
|
'Finden Sie die bestehende Person oder erstellen '
|
||||||
|
'Sie eine Mitgliedschaft mit ihrer E-Mail-Adresse '
|
||||||
|
'und dem Anzeigenamen.',
|
||||||
|
'Überprüfen Sie aktuelle Gruppen und direkte '
|
||||||
|
'Rollen, bevor Sie etwas ändern.',
|
||||||
|
'Fügen Sie die Person der kleinsten Gruppe hinzu, '
|
||||||
|
'die den erforderlichen gemeinsamen Zugriff '
|
||||||
|
'gewährt.',
|
||||||
|
'Weisen Sie direkte Rollen nur zu, wenn eine '
|
||||||
|
'Gruppe nicht mit dem Fall übereinstimmt.',
|
||||||
|
'Speichern und überprüfen Sie eine '
|
||||||
|
'Blockernachricht, bevor Sie einen System- oder '
|
||||||
|
'Mandantbesitzer um Hilfe bitten.'],
|
||||||
|
'verification': 'Öffnen Sie den Benutzer erneut und '
|
||||||
|
'vergleichen Sie Gruppen, direkte Rollen '
|
||||||
|
'und effektive Berechtigungen mit der '
|
||||||
|
'Anforderung.'},
|
||||||
|
'access.workflow.manage-api-keys': {'consequences': ['Der Widerruf lehnt nachfolgende Anfragen, '
|
||||||
|
'die mit dem Schlüssel gestellt wurden, '
|
||||||
|
'sofort ab.',
|
||||||
|
'Durch das Entfernen von Berechtigungen vom '
|
||||||
|
'Besitzer wird der effektive '
|
||||||
|
'Schlüsselzugriff sofort eingeschränkt.'],
|
||||||
|
'limitations': ['Ein einmaliges Geheimnis kann nach dem '
|
||||||
|
'Schließen des Erstellungsdialogs nicht '
|
||||||
|
'angezeigt oder wiederhergestellt werden.',
|
||||||
|
'Ändern des Besitzers, Ablauf oder Scopes '
|
||||||
|
'erfordert einen Ersatzschlüssel.',
|
||||||
|
'Der Widerruf aktualisiert keine externen '
|
||||||
|
'Clients; die Betreiber müssen bei Bedarf '
|
||||||
|
'einen Ersatz installieren.'],
|
||||||
|
'outcome': 'Der Automatisierungsclient verfügt über einen '
|
||||||
|
'zeitlich begrenzten Berechtigungsnachweis, dessen '
|
||||||
|
'effektiver Zugriff weder seine gespeicherten '
|
||||||
|
'Berechtigungsbereiche noch die aktuellen '
|
||||||
|
'Berechtigungen seines Besitzers überschreiten '
|
||||||
|
'kann.',
|
||||||
|
'prerequisites': ['Der Mandant erlaubt '
|
||||||
|
'API-Anmeldeinformationen.',
|
||||||
|
'Die handelnde Person kann API-Schlüssel '
|
||||||
|
'erstellen oder widerrufen und jeden '
|
||||||
|
'ausgewählten Bereich delegieren.',
|
||||||
|
'Ein zugelassener externer Geheimmanager '
|
||||||
|
'und rechenschaftspflichtiger Eigentümer '
|
||||||
|
'sind bekannt.'],
|
||||||
|
'steps': ['Wählen Sie den verantwortlichen Eigentümer und die '
|
||||||
|
'engsten erforderlichen Berechtigungsbereiche.',
|
||||||
|
'Legen Sie den kürzesten praktischen Ablauf fest, '
|
||||||
|
'bevor Sie den Schlüssel erstellen.',
|
||||||
|
'Übertragen Sie das einmalige Geheimnis direkt in '
|
||||||
|
'den genehmigten Geheimmanager.',
|
||||||
|
'Widerrufen Sie den Schlüssel, wenn sein Client, '
|
||||||
|
'Eigentümer oder Zweck nicht mehr gültig ist.'],
|
||||||
|
'verification': 'Laden Sie das Schlüsselverzeichnis neu, '
|
||||||
|
'überprüfen Sie Eigentümer, Präfix, '
|
||||||
|
'Berechtigungsumfang, Ablauf und Status und '
|
||||||
|
'testen Sie dann den beabsichtigten Client, '
|
||||||
|
'ohne geheimes Material in Nachweise zu '
|
||||||
|
'kopieren.'},
|
||||||
|
'access.workflow.manage-reusable-credentials': {'limitations': ['GovOPlaN kann ein konfiguriertes '
|
||||||
|
'Geheimnis nicht anzeigen oder '
|
||||||
|
'wiederherstellen.',
|
||||||
|
'Eine leere Modul- oder '
|
||||||
|
'Serverbeschränkung bedeutet '
|
||||||
|
'jeden Wert, der nach '
|
||||||
|
'Berechtigungsumfang zulässig '
|
||||||
|
'ist.',
|
||||||
|
'Das Löschen oder Leeren eines '
|
||||||
|
'Geheimnisses schreibt keine '
|
||||||
|
'abhängigen Verbindungsreferenzen '
|
||||||
|
'neu.'],
|
||||||
|
'outcome': 'Die Zugangsdaten bleiben '
|
||||||
|
'schreibgeschützt und sind nur '
|
||||||
|
'innerhalb seines aktiven '
|
||||||
|
'Berechtigungsumfangs, Moduls, Servers '
|
||||||
|
'und Autorisierungsgrenzen verwendbar.',
|
||||||
|
'prerequisites': ['Der beabsichtigte '
|
||||||
|
'Berechtigungsinhaber wird '
|
||||||
|
'ausgewählt.',
|
||||||
|
'Die handelnde Person kann '
|
||||||
|
'Anmeldeinformationen lesen und '
|
||||||
|
'hat Schreibautorität für '
|
||||||
|
'Mutationen.',
|
||||||
|
'Der externe '
|
||||||
|
'Secret-Manager-Eigentümer und '
|
||||||
|
'abhängige Verbindungen sind '
|
||||||
|
'bekannt.'],
|
||||||
|
'steps': ['Wählen Sie den engsten Besitzumfang '
|
||||||
|
'und Anmeldetyp.',
|
||||||
|
'Beschränken Sie Module und Server '
|
||||||
|
'explizit, wenn eine breite Nutzung '
|
||||||
|
'nicht beabsichtigt ist.',
|
||||||
|
'Speichern Sie ein neues oder '
|
||||||
|
'Ersatzgeheimnis, ohne zu erwarten, '
|
||||||
|
'dass es erneut angezeigt wird.',
|
||||||
|
'Überprüfen Sie abhängige Verbindungen '
|
||||||
|
'vor der Deaktivierung, geheimen '
|
||||||
|
'Löschung oder Löschung.'],
|
||||||
|
'verification': 'Laden Sie die Liste der '
|
||||||
|
'Zugangsdaten neu, bestätigen Sie '
|
||||||
|
'deren Berechtigungsumfang und '
|
||||||
|
'Verfügbarkeit und testen Sie '
|
||||||
|
'dann jede beabsichtigte '
|
||||||
|
'abhängige Verbindung, ohne das '
|
||||||
|
'Geheimnis zu enthüllen.'},
|
||||||
|
'access.workflow.manage-service-account-credentials': {'consequences': ['Rotation widerruft den '
|
||||||
|
'vorherigen Nachweis in '
|
||||||
|
'der gleichen '
|
||||||
|
'Transaktion, die seinen '
|
||||||
|
'Ersatz schafft.',
|
||||||
|
'Der Widerruf, die '
|
||||||
|
'Deaktivierung des Kontos '
|
||||||
|
'und der Ruhestand lehnen '
|
||||||
|
'betroffene '
|
||||||
|
'Kundenanfragen sofort '
|
||||||
|
'ab.',
|
||||||
|
'Eine veraltete Revision '
|
||||||
|
'wird abgelehnt, so dass '
|
||||||
|
'ein gleichzeitiger '
|
||||||
|
'Verwaltungswechsel nicht '
|
||||||
|
'überschrieben wird.'],
|
||||||
|
'limitations': ['Einmalige '
|
||||||
|
'Anmeldegeheimnisse können '
|
||||||
|
'nach dem Schließen des '
|
||||||
|
'Erstellungsdialogs nicht '
|
||||||
|
'angezeigt oder '
|
||||||
|
'wiederhergestellt werden.',
|
||||||
|
'Deaktivierung und eine '
|
||||||
|
'reduzierte '
|
||||||
|
'Berechtigungsumfangsobergrenze '
|
||||||
|
'betreffen Clients sofort, '
|
||||||
|
'schreiben ihre externe '
|
||||||
|
'Konfiguration jedoch '
|
||||||
|
'nicht neu.',
|
||||||
|
'Der Ruhestand widerruft '
|
||||||
|
'alle aktiven '
|
||||||
|
'Anmeldeinformationen und '
|
||||||
|
'erfordert ein neues '
|
||||||
|
'Servicekonto für die '
|
||||||
|
'spätere '
|
||||||
|
'Wiederverwendung.'],
|
||||||
|
'outcome': 'Der Automatisierungsprinzipal '
|
||||||
|
'bleibt nicht interaktiv und '
|
||||||
|
'kann sich nur durch einen '
|
||||||
|
'aktiven Berechtigungsnachweis '
|
||||||
|
'authentifizieren, dessen '
|
||||||
|
'Gewährung innerhalb der '
|
||||||
|
'aktuellen '
|
||||||
|
'Berechtigungsumfangsobergrenze '
|
||||||
|
'des Kontos liegt.',
|
||||||
|
'prerequisites': ['Der Mandant erlaubt '
|
||||||
|
'API-Anmeldeinformationen.',
|
||||||
|
'Sie haben eine '
|
||||||
|
'Service-Account-Schreibberechtigung '
|
||||||
|
'und können jeden '
|
||||||
|
'ausgewählten Bereich '
|
||||||
|
'delegieren.'],
|
||||||
|
'steps': ['Erstellen Sie ein Servicekonto '
|
||||||
|
'und definieren Sie die engste '
|
||||||
|
'Nutzumfangsobergrenze.',
|
||||||
|
'Öffnen Sie das Konto und '
|
||||||
|
'erstellen Sie einen '
|
||||||
|
'Berechtigungsnachweis mit einem '
|
||||||
|
'gleichen oder engeren '
|
||||||
|
'Berechtigungsumfang.',
|
||||||
|
'Notieren Sie das einmalige '
|
||||||
|
'Geheimnis in einem externen '
|
||||||
|
'Geheimmanager.',
|
||||||
|
'Anmeldeinformationen vor Ablauf '
|
||||||
|
'drehen und Anmeldeinformationen '
|
||||||
|
'widerrufen, die nicht mehr '
|
||||||
|
'verwendet werden.'],
|
||||||
|
'verification': 'Die Verwaltungstabelle '
|
||||||
|
'zeigt die erwartete '
|
||||||
|
'Anzahl der aktiven '
|
||||||
|
'Anmeldeinformationen, den '
|
||||||
|
'Zeitstempel für die '
|
||||||
|
'letzte Verwendung, die '
|
||||||
|
'Revision und die '
|
||||||
|
'Audit-Ereignisse, ohne '
|
||||||
|
'geheimes Material '
|
||||||
|
'preiszugeben.'}}
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from govoplan_core.core.modules import with_documentation_structured_translations
|
||||||
|
from govoplan_access.backend.german_structured_documentation import GERMAN_STRUCTURED_TRANSLATIONS
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from govoplan_access.backend.configuration_provider import (
|
from govoplan_access.backend.configuration_provider import (
|
||||||
@@ -859,6 +862,44 @@ ACCESS_DOCUMENTATION: tuple[DocumentationTopic, ...] = (
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
DocumentationTopic(
|
||||||
|
id="access.reference.authentication-fields",
|
||||||
|
title="Authentication and password fields",
|
||||||
|
summary="Understand which credentials are used for interactive sign-in, initial account enrollment, administrative re-authorization, and automation.",
|
||||||
|
body=(
|
||||||
|
"The sign-in email identifies the account and the password authenticates only that account. Initial passwords entered by administrators are transmitted only for account creation; leaving the field empty asks the server to generate a one-time temporary password. Requiring a password change prevents that temporary credential from becoming the long-term credential. Current-password prompts re-authorize a sensitive action and never target the selected user's password. The automation API key in local settings is used only when no interactive browser session token is available; it should be a narrowly scoped, revocable key and must not be shared with other users. Generated passwords are not applied until Use password is selected."
|
||||||
|
),
|
||||||
|
layer="always",
|
||||||
|
documentation_types=("admin", "user"),
|
||||||
|
audience=("user", "tenant_admin", "access_admin", "operator"),
|
||||||
|
order=29,
|
||||||
|
conditions=(DocumentationCondition(required_modules=("access",)),),
|
||||||
|
links=(
|
||||||
|
DocumentationLink(label="Sign in", href="/", kind="runtime"),
|
||||||
|
DocumentationLink(label="Access administration", href="/admin", kind="runtime"),
|
||||||
|
DocumentationLink(label="Local connection settings", href="/settings", kind="runtime"),
|
||||||
|
),
|
||||||
|
translations={
|
||||||
|
"de": {
|
||||||
|
"title": "Authentifizierungs- und Passwortfelder",
|
||||||
|
"summary": "Einordnen, welche Zugangsdaten für die interaktive Anmeldung, die erste Kontoeinrichtung, die erneute administrative Autorisierung und Automatisierung verwendet werden.",
|
||||||
|
"body": (
|
||||||
|
"Die Anmelde-E-Mail identifiziert das Konto; das Passwort authentifiziert ausschließlich dieses Konto. Von Administrierenden eingegebene Anfangspasswörter werden nur zur Kontoerstellung übertragen. Bleibt das Feld leer, erzeugt der Server ein einmaliges temporäres Passwort. Die Pflicht zum Passwortwechsel verhindert, dass diese temporäre Zugangsdaten dauerhaft verwendet werden. Die Abfrage des aktuellen Passworts autorisiert eine sensible Aktion erneut und meint niemals das Passwort der ausgewählten Person. Der Automatisierungs-API-Schlüssel in den lokalen Einstellungen wird nur verwendet, wenn kein interaktives Browser-Sitzungstoken verfügbar ist; er sollte eng begrenzt, widerrufbar und nicht mit anderen Personen geteilt sein. Generierte Passwörter werden erst mit „Passwort verwenden“ übernommen."
|
||||||
|
),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
metadata={
|
||||||
|
"kind": "reference",
|
||||||
|
"help_contexts": [
|
||||||
|
"access.authentication.email",
|
||||||
|
"access.authentication.password",
|
||||||
|
"access.settings.automation-api-key",
|
||||||
|
"access.admin.system-users.initial-password",
|
||||||
|
"access.admin.tenant-users.initial-password",
|
||||||
|
"access.admin.tenant-users.require-password-change",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
),
|
||||||
DocumentationTopic(
|
DocumentationTopic(
|
||||||
id="access.workflow.grant-user-access",
|
id="access.workflow.grant-user-access",
|
||||||
title="Grant a person access",
|
title="Grant a person access",
|
||||||
@@ -1528,6 +1569,7 @@ ACCESS_DOCUMENTATION: tuple[DocumentationTopic, ...] = (
|
|||||||
"access.sessions.action.revoke",
|
"access.sessions.action.revoke",
|
||||||
"access.sessions.action.revoke-others",
|
"access.sessions.action.revoke-others",
|
||||||
"access.admin.user-sessions",
|
"access.admin.user-sessions",
|
||||||
|
"access.sessions.field.current-password",
|
||||||
],
|
],
|
||||||
"api_paths": [
|
"api_paths": [
|
||||||
"/api/v1/auth/sessions",
|
"/api/v1/auth/sessions",
|
||||||
@@ -1918,7 +1960,7 @@ def _people_search(context: ModuleContext) -> object:
|
|||||||
manifest = ModuleManifest(
|
manifest = ModuleManifest(
|
||||||
id="access",
|
id="access",
|
||||||
name="Access",
|
name="Access",
|
||||||
version="0.1.21",
|
version="0.1.23",
|
||||||
optional_dependencies=("identity", "organizations", "tenancy", "idm"),
|
optional_dependencies=("identity", "organizations", "tenancy", "idm"),
|
||||||
provides_interfaces=(
|
provides_interfaces=(
|
||||||
ModuleInterfaceProvider(name=CAPABILITY_ACCESS_PEOPLE_SEARCH, version="0.1.0"),
|
ModuleInterfaceProvider(name=CAPABILITY_ACCESS_PEOPLE_SEARCH, version="0.1.0"),
|
||||||
@@ -2153,5 +2195,10 @@ manifest = ModuleManifest(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
manifest = with_documentation_structured_translations(
|
||||||
|
manifest, locale="de", translations=GERMAN_STRUCTURED_TRANSLATIONS
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_manifest() -> ModuleManifest:
|
def get_manifest() -> ModuleManifest:
|
||||||
return manifest
|
return manifest
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@govoplan/access-webui",
|
"name": "@govoplan/access-webui",
|
||||||
"version": "0.1.21",
|
"version": "0.1.23",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -239,8 +239,10 @@ export default function SystemUsersPanel({
|
|||||||
<FormField label="i18n:govoplan-access.email.84add5b2"><input value={draft.email} disabled={editing !== "new"} onChange={(event) => setDraft({ ...draft, email: event.target.value })} /></FormField>
|
<FormField label="i18n:govoplan-access.email.84add5b2"><input value={draft.email} disabled={editing !== "new"} onChange={(event) => setDraft({ ...draft, email: event.target.value })} /></FormField>
|
||||||
<FormField label="i18n:govoplan-access.display_name.c7874aaa"><input value={draft.displayName} disabled={editing !== "new" && !canUpdate} onChange={(event) => setDraft({ ...draft, displayName: event.target.value })} /></FormField>
|
<FormField label="i18n:govoplan-access.display_name.c7874aaa"><input value={draft.displayName} disabled={editing !== "new" && !canUpdate} onChange={(event) => setDraft({ ...draft, displayName: event.target.value })} /></FormField>
|
||||||
{editing === "new" &&
|
{editing === "new" &&
|
||||||
<FormField label="i18n:govoplan-access.initial_password.2278be8c">
|
<FormField label="i18n:govoplan-access.initial_password.2278be8c" helpContextId="access.admin.system-users.initial-password" helpModuleId="access">
|
||||||
<PasswordField
|
<PasswordField
|
||||||
|
helpContextId="access.admin.system-users.initial-password"
|
||||||
|
helpModuleId="access"
|
||||||
value={draft.password}
|
value={draft.password}
|
||||||
placeholder="i18n:govoplan-access.leave_empty_to_generate.e58222d8"
|
placeholder="i18n:govoplan-access.leave_empty_to_generate.e58222d8"
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
|
|||||||
@@ -249,6 +249,8 @@ export default function UsersPanel({ settings, auth, canCreate, canUpdate, canSu
|
|||||||
id: "revoke-session",
|
id: "revoke-session",
|
||||||
label: "i18n:govoplan-access.revoke_session.5e551007",
|
label: "i18n:govoplan-access.revoke_session.5e551007",
|
||||||
variant: "danger",
|
variant: "danger",
|
||||||
|
helpContextId: "access.sessions.action.revoke",
|
||||||
|
helpModuleId: "access",
|
||||||
applicable: !row.current,
|
applicable: !row.current,
|
||||||
disabled: busy || !canRevokeSessions,
|
disabled: busy || !canRevokeSessions,
|
||||||
disabledReason: !canRevokeSessions ? "i18n:govoplan-access.session_revocation_permission_required.5e551016" : busy ? ACCESS_INTERFACE_I18N.operationInProgress : undefined,
|
disabledReason: !canRevokeSessions ? "i18n:govoplan-access.session_revocation_permission_required.5e551016" : busy ? ACCESS_INTERFACE_I18N.operationInProgress : undefined,
|
||||||
@@ -283,8 +285,10 @@ export default function UsersPanel({ settings, auth, canCreate, canUpdate, canSu
|
|||||||
<FormField label="i18n:govoplan-access.email.84add5b2"><input value={draft.email} disabled={editing !== "new"} onChange={(event) => setDraft({ ...draft, email: event.target.value })} /></FormField>
|
<FormField label="i18n:govoplan-access.email.84add5b2"><input value={draft.email} disabled={editing !== "new"} onChange={(event) => setDraft({ ...draft, email: event.target.value })} /></FormField>
|
||||||
<FormField label="i18n:govoplan-access.display_name.c7874aaa"><input value={draft.displayName} disabled={editing !== "new" && !canUpdate} onChange={(event) => setDraft({ ...draft, displayName: event.target.value })} /></FormField>
|
<FormField label="i18n:govoplan-access.display_name.c7874aaa"><input value={draft.displayName} disabled={editing !== "new" && !canUpdate} onChange={(event) => setDraft({ ...draft, displayName: event.target.value })} /></FormField>
|
||||||
{editing === "new" &&
|
{editing === "new" &&
|
||||||
<FormField label="i18n:govoplan-access.initial_password.2278be8c">
|
<FormField label="i18n:govoplan-access.initial_password.2278be8c" helpContextId="access.admin.tenant-users.initial-password" helpModuleId="access">
|
||||||
<PasswordField
|
<PasswordField
|
||||||
|
helpContextId="access.admin.tenant-users.initial-password"
|
||||||
|
helpModuleId="access"
|
||||||
value={draft.password}
|
value={draft.password}
|
||||||
placeholder="i18n:govoplan-access.leave_empty_to_generate.e58222d8"
|
placeholder="i18n:govoplan-access.leave_empty_to_generate.e58222d8"
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
@@ -294,7 +298,7 @@ export default function UsersPanel({ settings, auth, canCreate, canUpdate, canSu
|
|||||||
}
|
}
|
||||||
<FormField label="i18n:govoplan-access.membership_status.b77fc732"><select value={draft.isActive ? "active" : "inactive"} disabled={Boolean(editing && editing !== "new" && (!canSuspend || editing.is_last_active_owner))} onChange={(event) => setDraft({ ...draft, isActive: event.target.value === "active" })}><option value="active">i18n:govoplan-access.active.a733b809</option><option value="inactive">i18n:govoplan-access.inactive.09af574c</option></select></FormField>
|
<FormField label="i18n:govoplan-access.membership_status.b77fc732"><select value={draft.isActive ? "active" : "inactive"} disabled={Boolean(editing && editing !== "new" && (!canSuspend || editing.is_last_active_owner))} onChange={(event) => setDraft({ ...draft, isActive: event.target.value === "active" })}><option value="active">i18n:govoplan-access.active.a733b809</option><option value="inactive">i18n:govoplan-access.inactive.09af574c</option></select></FormField>
|
||||||
</FormGrid>
|
</FormGrid>
|
||||||
{editing === "new" && <ToggleSwitch label="i18n:govoplan-access.require_password_change_when_account_settings_ar.69bce7a3" checked={draft.passwordResetRequired} onChange={(passwordResetRequired) => setDraft({ ...draft, passwordResetRequired })} />}
|
{editing === "new" && <ToggleSwitch label="i18n:govoplan-access.require_password_change_when_account_settings_ar.69bce7a3" checked={draft.passwordResetRequired} helpContextId="access.admin.tenant-users.require-password-change" helpModuleId="access" onChange={(passwordResetRequired) => setDraft({ ...draft, passwordResetRequired })} />}
|
||||||
{editing && editing !== "new" && editing.is_last_active_owner && <p className="admin-protection-note">i18n:govoplan-access.this_membership_is_the_tenant_s_last_active_oper.072b247f</p>}
|
{editing && editing !== "new" && editing.is_last_active_owner && <p className="admin-protection-note">i18n:govoplan-access.this_membership_is_the_tenant_s_last_active_oper.072b247f</p>}
|
||||||
<ContentGrid columns={2} spacing="block" collapseAt="wide">
|
<ContentGrid columns={2} spacing="block" collapseAt="wide">
|
||||||
<div><span className="form-label">i18n:govoplan-access.groups.ae9629f4</span><AdminSelectionList options={groups.filter((group) => group.is_active).map((group) => ({ id: group.id, label: group.name, description: group.description, disabled: !canManageGroups }))} selected={draft.groupIds} onChange={(groupIds) => setDraft({ ...draft, groupIds })} emptyText="i18n:govoplan-access.no_groups_exist_yet.9cd029f6" /></div>
|
<div><span className="form-label">i18n:govoplan-access.groups.ae9629f4</span><AdminSelectionList options={groups.filter((group) => group.is_active).map((group) => ({ id: group.id, label: group.name, description: group.description, disabled: !canManageGroups }))} selected={draft.groupIds} onChange={(groupIds) => setDraft({ ...draft, groupIds })} emptyText="i18n:govoplan-access.no_groups_exist_yet.9cd029f6" /></div>
|
||||||
@@ -320,11 +324,11 @@ export default function UsersPanel({ settings, auth, canCreate, canUpdate, canSu
|
|||||||
</>}
|
</>}
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
<Dialog variant="administration" size="large" open={Boolean(revokingSession)} title="i18n:govoplan-access.revoke_session.5e551007" onClose={() => !busy && setRevokingSession(null)} className="" footer={<><Button onClick={() => setRevokingSession(null)} disabled={busy}>i18n:govoplan-access.cancel.77dfd213</Button><Button variant="danger" onClick={() => void revokeSelectedSession()} disabled={busy || !reauthorizationPassword} disabledReason={!reauthorizationPassword ? "i18n:govoplan-access.current_password_required.5e551019" : busy ? ACCESS_INTERFACE_I18N.operationInProgress : undefined}>i18n:govoplan-access.revoke_session.5e551007</Button></>}>
|
<Dialog variant="administration" size="large" open={Boolean(revokingSession)} title="i18n:govoplan-access.revoke_session.5e551007" helpContextId="access.sessions.action.revoke" helpModuleId="access" onClose={() => !busy && setRevokingSession(null)} className="" footer={<><Button onClick={() => setRevokingSession(null)} disabled={busy}>i18n:govoplan-access.cancel.77dfd213</Button><Button variant="danger" helpContextId="access.sessions.action.revoke" helpModuleId="access" onClick={() => void revokeSelectedSession()} disabled={busy || !reauthorizationPassword} disabledReason={!reauthorizationPassword ? "i18n:govoplan-access.current_password_required.5e551019" : busy ? ACCESS_INTERFACE_I18N.operationInProgress : undefined}>i18n:govoplan-access.revoke_session.5e551007</Button></>}>
|
||||||
{sessionError && <p className="admin-protection-note">{sessionError}</p>}
|
{sessionError && <p className="admin-protection-note">{sessionError}</p>}
|
||||||
<p>i18n:govoplan-access.admin_session_revocation_confirmation.5e551020</p>
|
<p>i18n:govoplan-access.admin_session_revocation_confirmation.5e551020</p>
|
||||||
<FormField label="i18n:govoplan-access.current_password.5e551021">
|
<FormField label="i18n:govoplan-access.current_password.5e551021" helpContextId="access.sessions.field.current-password" helpModuleId="access">
|
||||||
<PasswordField value={reauthorizationPassword} autoComplete="current-password" onValueChange={setReauthorizationPassword} />
|
<PasswordField helpContextId="access.sessions.field.current-password" helpModuleId="access" value={reauthorizationPassword} autoComplete="current-password" onValueChange={setReauthorizationPassword} />
|
||||||
</FormField>
|
</FormField>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
|
|||||||
@@ -132,6 +132,8 @@ export default function SessionSettingsPanel({
|
|||||||
id: "revoke",
|
id: "revoke",
|
||||||
label: "i18n:govoplan-access.revoke_session.5e551007",
|
label: "i18n:govoplan-access.revoke_session.5e551007",
|
||||||
variant: "danger",
|
variant: "danger",
|
||||||
|
helpContextId: "access.sessions.action.revoke",
|
||||||
|
helpModuleId: "access",
|
||||||
applicable: !row.current,
|
applicable: !row.current,
|
||||||
disabled: busy,
|
disabled: busy,
|
||||||
disabledReason: busy
|
disabledReason: busy
|
||||||
@@ -208,6 +210,8 @@ export default function SessionSettingsPanel({
|
|||||||
destructiveActions={
|
destructiveActions={
|
||||||
<Button
|
<Button
|
||||||
variant="danger"
|
variant="danger"
|
||||||
|
helpContextId="access.sessions.action.revoke-others"
|
||||||
|
helpModuleId="access"
|
||||||
disabled={busy || sessions.filter((item) => !item.current).length === 0}
|
disabled={busy || sessions.filter((item) => !item.current).length === 0}
|
||||||
disabledReason={
|
disabledReason={
|
||||||
busy
|
busy
|
||||||
@@ -243,6 +247,8 @@ export default function SessionSettingsPanel({
|
|||||||
confirmLabel="i18n:govoplan-access.revoke_session.5e551007"
|
confirmLabel="i18n:govoplan-access.revoke_session.5e551007"
|
||||||
tone="danger"
|
tone="danger"
|
||||||
busy={busy}
|
busy={busy}
|
||||||
|
helpContextId="access.sessions.action.revoke"
|
||||||
|
helpModuleId="access"
|
||||||
onCancel={() => setRevoking(null)}
|
onCancel={() => setRevoking(null)}
|
||||||
onConfirm={() => void revokeOne()}
|
onConfirm={() => void revokeOne()}
|
||||||
/>
|
/>
|
||||||
@@ -253,6 +259,8 @@ export default function SessionSettingsPanel({
|
|||||||
confirmLabel="i18n:govoplan-access.revoke_all_other_sessions.5e551012"
|
confirmLabel="i18n:govoplan-access.revoke_all_other_sessions.5e551012"
|
||||||
tone="danger"
|
tone="danger"
|
||||||
busy={busy}
|
busy={busy}
|
||||||
|
helpContextId="access.sessions.action.revoke-others"
|
||||||
|
helpModuleId="access"
|
||||||
onCancel={() => setRevokingOthers(false)}
|
onCancel={() => setRevokingOthers(false)}
|
||||||
onConfirm={() => void revokeOthers()}
|
onConfirm={() => void revokeOthers()}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user