From b29d174141a3336d5f1f2b7685a8dc048e9e5652 Mon Sep 17 00:00:00 2001 From: Jonas <77726472+kobolol@users.noreply.github.com> Date: Fri, 1 May 2026 15:22:42 +0200 Subject: [PATCH] Add user update endpoint and DTO Introduce ChangeUserRequest DTO (UserName, IsActive) and add UpdateAppUser action to AppUserController. The new endpoint allows updating a user's username and active state, trims and validates the username, checks for duplicates, updates the Identity security stamp when deactivating to invalidate sessions, and returns appropriate success or error responses. --- API/Contracts/Auth/ChangeUserRequest.cs | 8 ++++ API/Controllers/Auth/AppUserController.cs | 58 +++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 API/Contracts/Auth/ChangeUserRequest.cs diff --git a/API/Contracts/Auth/ChangeUserRequest.cs b/API/Contracts/Auth/ChangeUserRequest.cs new file mode 100644 index 0000000..9deba6c --- /dev/null +++ b/API/Contracts/Auth/ChangeUserRequest.cs @@ -0,0 +1,8 @@ +namespace API.Contracts.Auth +{ + public class ChangeUserRequest + { + public string? UserName { get; set; } + public bool? IsActive { get; set; } + } +} diff --git a/API/Controllers/Auth/AppUserController.cs b/API/Controllers/Auth/AppUserController.cs index 5793c17..6d24055 100644 --- a/API/Controllers/Auth/AppUserController.cs +++ b/API/Controllers/Auth/AppUserController.cs @@ -35,5 +35,63 @@ namespace API.Controllers.Auth return Ok(await user.ToCurrentUserResponseAsync(userManager)); } + + [HttpPost("{id:guid")] + public async Task UpdateAppUser([FromRoute] Guid id, [FromBody] ChangeUserRequest changeDto) + { + var user = await userManager.Users.FirstOrDefaultAsync(x => x.Id == id); + + if (user is null) + { + return NotFound(new { message = "Benutzer wurde nicht gefunden." }); + } + + if (changeDto.IsActive != null) + { + user.IsActive = changeDto.IsActive.Value; + + if (!changeDto.IsActive.Value) + { + var stampResult = await userManager.UpdateSecurityStampAsync(user); + if (!stampResult.Succeeded) + { + return StatusCode(500, new { message = "Benutzer wurde auf geändert, aber Sessions konnten nicht invalidiert werden. " + + "Er könnte also immer noch Angemeldet sein!" }); + } + } + } + + if (changeDto.UserName != null) + { + var newUserName = changeDto.UserName.Trim(); + + if (string.IsNullOrEmpty(newUserName)) + { + return BadRequest(new { message = "Benutzername darf nicht leer sein." }); + } + + if (!string.Equals(newUserName, user.UserName, StringComparison.OrdinalIgnoreCase)) + { + var existing = await userManager.FindByNameAsync(newUserName); + if (existing is not null && existing.Id != user.Id) + { + return Conflict(new { message = "Benutzername ist bereits vergeben." }); + } + + var setNameResult = await userManager.SetUserNameAsync(user, newUserName); + if (!setNameResult.Succeeded) + { + if (setNameResult.Errors.Any(e => e.Code == nameof(IdentityErrorDescriber.DuplicateUserName))) + { + return Conflict(new { message = "Benutzername ist bereits vergeben." }); + } + + return BadRequest(new { message = "Benutzername konnte nicht geändert werden.", errors = setNameResult.Errors.Select(e => e.Description) }); + } + } + } + + return Ok(await user.ToCurrentUserResponseAsync(userManager)); + } } }