From cefa47a176178a55f93035ae563609ebf798b14e Mon Sep 17 00:00:00 2001 From: "a.beging@eas-solutions.de" Date: Thu, 30 Apr 2026 09:53:05 +0200 Subject: [PATCH] Enhance user management: prevent deletion of the last admin user and restrict admin type changes for the last admin account Co-authored-by: Copilot --- .../Data/Service/UserService.cs | 14 ++++++++++++++ FoodsharingSiegen.Server/Pages/Users.razor | 14 +++++++++----- FoodsharingSiegen.Server/Pages/Users.razor.cs | 11 +++++------ 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/FoodsharingSiegen.Server/Data/Service/UserService.cs b/FoodsharingSiegen.Server/Data/Service/UserService.cs index 5b4b7f6..4937a16 100644 --- a/FoodsharingSiegen.Server/Data/Service/UserService.cs +++ b/FoodsharingSiegen.Server/Data/Service/UserService.cs @@ -105,6 +105,13 @@ namespace FoodsharingSiegen.Server.Data.Service var user = await Context.Users!.Include(x => x.Interactions).FirstOrDefaultAsync(x => x.Id == userId); if (user == null) return new(new Exception("User not found")); + if (user.Type == UserType.Admin) + { + var adminCount = await Context.Users!.CountAsync(x => x.Type == UserType.Admin && x.Id != userId); + if (adminCount == 0) + return new(new Exception("Der letzte Administrator kann nicht gelöscht werden.")); + } + // Interaktionen vom aktuellen Nutzer übernehmen if(CurrentUser?.Id != null) foreach (var userInteraction in user.Interactions) @@ -184,6 +191,13 @@ namespace FoodsharingSiegen.Server.Data.Service var entityUser = await Context.Users!.FirstOrDefaultAsync(x => x.Id == user.Id); if (entityUser == null) return new(new Exception("User not found")); + if (entityUser.Type == UserType.Admin && user.Type != UserType.Admin) + { + var adminCount = await Context.Users!.CountAsync(x => x.Type == UserType.Admin && x.Id != user.Id); + if (adminCount == 0) + return new(new Exception("Der Typ des letzten Administrators kann nicht geändert werden.")); + } + if (entityUser.Mail != user.Mail || entityUser.Type != user.Type || entityUser.Groups != user.Groups) diff --git a/FoodsharingSiegen.Server/Pages/Users.razor b/FoodsharingSiegen.Server/Pages/Users.razor index 1fabec4..dfeddb8 100644 --- a/FoodsharingSiegen.Server/Pages/Users.razor +++ b/FoodsharingSiegen.Server/Pages/Users.razor @@ -55,13 +55,13 @@ -
- -
- + @if (!(user.Type == UserType.Admin && SortedUsers.Count(x => x.Type == UserType.Admin) <= 1)) + { + + }
} @@ -105,12 +105,16 @@ Typ - @foreach (var enumValue in Enum.GetValues()) { @enumValue } + @if (IsLastAdmin) + { + Das ist der letzte Administrator-Account. Der Typ kann nicht geändert werden. + } Gruppen diff --git a/FoodsharingSiegen.Server/Pages/Users.razor.cs b/FoodsharingSiegen.Server/Pages/Users.razor.cs index f487841..f9b1e2b 100644 --- a/FoodsharingSiegen.Server/Pages/Users.razor.cs +++ b/FoodsharingSiegen.Server/Pages/Users.razor.cs @@ -57,6 +57,11 @@ namespace FoodsharingSiegen.Server.Pages /// private bool IsEditing { get; set; } + /// + /// Gets a value indicating whether the current editing user is the last admin + /// + private bool IsLastAdmin => IsEditing && EditModel?.Type == UserType.Admin && UserList?.Count(x => x.Type == UserType.Admin) <= 1; + /// /// Gets the value of the user groups (ab) /// @@ -184,12 +189,6 @@ namespace FoodsharingSiegen.Server.Pages /// A task that represents the asynchronous remove operation. private async Task RemoveUserAsync(User user) { - if (user.IsAdmin()) - { - await Notification.Error("Admins können nicht gelöscht werden!"); - return; - } - await ConfirmDialog.ShowAsync(ModalService, "Bestätigen", $"User {user.Mail} löschen?", async () => { var removeR = await UserService.RemoveAsync(user.Id);