feat(admin): user management — roles, suspend, delete + lifecycle emails

- New Users page tabs (Users & roles / Access requests / Demo) and a tab-ified Configuration
  page, both via a reusable Tabs component (persisted active tab).
- Admin can suspend/unsuspend (migration 0023 adds users.is_suspended) and delete accounts
  from the Users & roles tab, with guards (demo / self / last admin).
- Email notifications to the affected user: suspended (reactive, on a blocked sign-in),
  reinstated, role changed, and account deleted; the approval email now carries a clickable
  app link. The scheduled/manual demo reset also seeds sample channel subscriptions.
- Hide the 'unverified email' chip for Google accounts (Google attests the email).
This commit is contained in:
npeter83 2026-06-19 19:52:12 +02:00
parent 2aa13a6433
commit 4571800991
10 changed files with 461 additions and 32 deletions

View file

@ -1,4 +1,9 @@
{
"tabs": {
"roles": "Benutzer & Rollen",
"access": "Zugriffsanfragen",
"demo": "Demo"
},
"roles": {
"title": "Benutzer & Rollen",
"intro": "Alle, die sich anmelden können. Mache einen Benutzer zum Admin oder wieder zum normalen Benutzer.",
@ -6,16 +11,36 @@
"you": "du",
"admin": "Admin",
"demo": "Demo",
"suspended": "Gesperrt",
"pending": "Wartet auf Freigabe",
"unverified": "E-Mail nicht bestätigt",
"demoLocked": "Die Rolle des Demo-Kontos kann nicht geändert werden.",
"selfLocked": "Du kannst deine eigene Rolle nicht ändern.",
"makeAdmin": "Zum Admin machen",
"makeUser": "Zum Benutzer machen",
"updated": "Rolle aktualisiert",
"updated": "Rolle aktualisiert für {{email}}",
"promoteTitle": "Zum Admin machen?",
"demoteTitle": "Admin entfernen?",
"promoteConfirm": "{{email}} vollen Admin-Zugriff geben (Einstellungen, Planer, Benutzerverwaltung)?",
"demoteConfirm": "{{email}} den Admin-Zugriff entziehen? Wird zum normalen Benutzer."
},
"suspend": {
"action": "Sperren",
"undoAction": "Entsperren",
"title": "Konto sperren?",
"undoTitle": "Konto entsperren?",
"confirm": "{{email}} sperren? Eine Anmeldung (per Passwort oder Google) ist erst nach dem Entsperren wieder möglich, und jede aktive Sitzung endet.",
"undoConfirm": "{{email}} entsperren? Eine Anmeldung ist dann wieder möglich.",
"done": "{{email}} gesperrt",
"undone": "{{email}} entsperrt",
"demoLocked": "Das Demo-Konto kann nicht gesperrt werden.",
"selfLocked": "Du kannst dein eigenes Konto nicht sperren."
},
"delete": {
"action": "Löschen",
"locked": "Dieses Konto kann hier nicht gelöscht werden.",
"title": "Konto löschen?",
"confirm": "{{email}} und alle zugehörigen Daten endgültig löschen — Abos, Tags, Wiedergabeverlauf, Playlists und Einstellungen? Das kann nicht rückgängig gemacht werden.",
"done": "{{email}} gelöscht"
}
}

View file

@ -1,4 +1,9 @@
{
"tabs": {
"roles": "Users & roles",
"access": "Access requests",
"demo": "Demo"
},
"roles": {
"title": "Users & roles",
"intro": "Everyone who can sign in. Promote a user to admin, or back to a regular user.",
@ -6,16 +11,36 @@
"you": "you",
"admin": "Admin",
"demo": "Demo",
"suspended": "Suspended",
"pending": "Pending approval",
"unverified": "Unverified email",
"demoLocked": "The demo account's role can't be changed.",
"selfLocked": "You can't change your own role.",
"makeAdmin": "Make admin",
"makeUser": "Make user",
"updated": "Role updated",
"updated": "Role updated for {{email}}",
"promoteTitle": "Make admin?",
"demoteTitle": "Remove admin?",
"promoteConfirm": "Give {{email}} full admin access (settings, scheduler, user management)?",
"demoteConfirm": "Remove admin access from {{email}}? They'll become a regular user."
},
"suspend": {
"action": "Suspend",
"undoAction": "Unsuspend",
"title": "Suspend account?",
"undoTitle": "Unsuspend account?",
"confirm": "Suspend {{email}}? They won't be able to sign in (by password or Google) until you unsuspend them, and any active session ends.",
"undoConfirm": "Unsuspend {{email}}? They'll be able to sign in again.",
"done": "{{email}} suspended",
"undone": "{{email}} unsuspended",
"demoLocked": "The demo account can't be suspended.",
"selfLocked": "You can't suspend your own account."
},
"delete": {
"action": "Delete",
"locked": "This account can't be deleted here.",
"title": "Delete account?",
"confirm": "Permanently delete {{email}} and all their data — subscriptions, tags, watch history, playlists and settings? This can't be undone.",
"done": "{{email}} deleted"
}
}

View file

@ -1,4 +1,9 @@
{
"tabs": {
"roles": "Felhasználók és szerepek",
"access": "Hozzáférési kérések",
"demo": "Demo"
},
"roles": {
"title": "Felhasználók és szerepek",
"intro": "Mindenki, aki be tud lépni. Léptess egy felhasználót adminná, vagy vissza sima felhasználóvá.",
@ -6,16 +11,36 @@
"you": "te",
"admin": "Admin",
"demo": "Demo",
"suspended": "Felfüggesztve",
"pending": "Jóváhagyásra vár",
"unverified": "Nem igazolt e-mail",
"demoLocked": "A demo fiók szerepe nem módosítható.",
"selfLocked": "A saját szerepedet nem módosíthatod.",
"makeAdmin": "Adminná tesz",
"makeUser": "Felhasználóvá tesz",
"updated": "Szerep frissítve",
"updated": "Szerep frissítve: {{email}}",
"promoteTitle": "Adminná teszed?",
"demoteTitle": "Elveszed az admin jogot?",
"promoteConfirm": "Teljes admin hozzáférést adsz neki: {{email}} (beállítások, ütemező, felhasználókezelés)?",
"demoteConfirm": "Elveszed az admin jogot tőle: {{email}}? Sima felhasználó lesz."
},
"suspend": {
"action": "Felfüggeszt",
"undoAction": "Feloldás",
"title": "Felfüggeszted a fiókot?",
"undoTitle": "Feloldod a felfüggesztést?",
"confirm": "Felfüggeszted: {{email}}? Nem fog tudni belépni (sem jelszóval, sem Google-lel), amíg fel nem oldod, és az aktív munkamenete megszűnik.",
"undoConfirm": "Feloldod a felfüggesztést: {{email}}? Újra be tud majd lépni.",
"done": "{{email}} felfüggesztve",
"undone": "{{email}} felfüggesztése feloldva",
"demoLocked": "A demo fiók nem függeszthető fel.",
"selfLocked": "A saját fiókodat nem függesztheted fel."
},
"delete": {
"action": "Törlés",
"locked": "Ez a fiók itt nem törölhető.",
"title": "Törlöd a fiókot?",
"confirm": "Véglegesen törlöd: {{email}} és minden adatát — feliratkozások, címkék, megtekintési előzmény, lejátszási listák és beállítások? Ez nem visszavonható.",
"done": "{{email}} törölve"
}
}