Let admins create and delete users in Benutzerverwaltung, modernize list
Playwright Tests / test (push) Canceled after 0s

Wire up two previously-unwired stored procedures for the usr module:
- fis_admin_createUserAccount gained the missing @authaccount +
  intranet_admin auth gate, a duplicate-email check, and now returns
  the (possibly auto-generated) password so it can be emailed to the
  new user, mirroring fis_admin_resetUserPassword's pattern.
- fis_admin_delUserAccount gained the same missing auth gate plus a
  guard against an admin deleting their own account.

New /do/usr/create and /do/usr/delete endpoints in
IntranetController.AdminUsers.cs, a "Neuer Benutzer" button and a
"Benutzer löschen" ribbon action in fis.usr.js, and unit tests for the
new welcome-email content (BuildWelcomeEmail).

Also restyle the user list (fis.usr.scss) from a plain bordered table
to a card-style row grid with avatar-initial badges and status pills,
matching the Admin dashboard's visual language.

Documented as ADR 0020 and in the admin-user-management concept doc.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Stefan
2026-09-14 14:51:59 +02:00
co-authored by Claude Sonnet 5
parent 38145a917e
commit 4386a6336a
14 changed files with 716 additions and 138 deletions
+42 -3
View File
@@ -5,9 +5,9 @@ namespace Fuchs.Tests;
/// <summary>
/// Covers the pure (non-DB) logic behind the Admin module's user-management endpoints —
/// specifically the admin-initiated password-reset notification content, since the SQL-bound
/// parts of IntranetController.Admin.cs (fis_admin_* proc calls) can't be unit-tested per
/// repo convention and require a running database.
/// the admin-initiated password-reset and new-account welcome notification content, since the
/// SQL-bound parts of IntranetController.AdminUsers.cs (fis_admin_* proc calls) can't be
/// unit-tested per repo convention and require a running database.
/// </summary>
public class AdminUserManagementTests
{
@@ -40,4 +40,43 @@ public class AdminUserManagementTests
Assert.False(string.IsNullOrWhiteSpace(subject));
Assert.Contains("somepassword", html);
}
[Fact]
public void BuildWelcomeEmail_ValidInput_ContainsNameEmailAndPassword()
{
var (subject, html) = IntranetController.BuildWelcomeEmail("Max Mustermann", "max@example.com", "Ab12Cd34");
Assert.Contains("Zugang", subject);
Assert.Contains("Max Mustermann", html);
Assert.Contains("max@example.com", html);
Assert.Contains("Ab12Cd34", html);
}
[Theory]
[InlineData("<script>alert(1)</script>", "&lt;script&gt;alert(1)&lt;/script&gt;")]
[InlineData("O'Brien&Co", "O&#39;Brien&amp;Co")]
public void BuildWelcomeEmail_PasswordWithHtmlSpecialChars_IsHtmlEncoded(string rawPassword, string encoded)
{
var (_, html) = IntranetController.BuildWelcomeEmail("Test User", "test@example.com", rawPassword);
Assert.Contains(encoded, html);
Assert.DoesNotContain(rawPassword, html);
}
[Fact]
public void BuildWelcomeEmail_EmailWithHtmlSpecialChars_IsHtmlEncoded()
{
var (_, html) = IntranetController.BuildWelcomeEmail("Test User", "a&b@example.com", "somepassword");
Assert.Contains("a&amp;b@example.com", html);
}
[Fact]
public void BuildWelcomeEmail_EmptyName_StillProducesValidContent()
{
var (subject, html) = IntranetController.BuildWelcomeEmail("", "test@example.com", "somepassword");
Assert.False(string.IsNullOrWhiteSpace(subject));
Assert.Contains("somepassword", html);
}
}