b29d174141
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.
98 lines
3.7 KiB
C#
98 lines
3.7 KiB
C#
using API.Contracts.Auth;
|
|
using API.Models;
|
|
using API.Security;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Identity;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace API.Controllers.Auth
|
|
{
|
|
[ApiController]
|
|
[Authorize(Policy = PolicyNames.AdminOnly)]
|
|
[Route("auth/user")]
|
|
public class AppUserController(UserManager<AppUser> userManager) : ControllerBase
|
|
{
|
|
[HttpGet]
|
|
public async Task<ActionResult<IReadOnlyList<CurrentUserResponse>>> GetAppUsers()
|
|
{
|
|
var users = await userManager.Users
|
|
.OrderBy(x => x.UserName)
|
|
.ToListAsync();
|
|
|
|
var tasks = users.Select(user => user.ToCurrentUserResponseAsync(userManager));
|
|
return Ok(await Task.WhenAll(tasks));
|
|
}
|
|
|
|
[HttpGet("{id:guid}")]
|
|
public async Task<ActionResult<CurrentUserResponse>> GetAppUserById([FromRoute] Guid id)
|
|
{
|
|
var user = await userManager.Users.FirstOrDefaultAsync(x => x.Id == id);
|
|
if (user is null)
|
|
{
|
|
return NotFound(new { message = "Benutzer wurde nicht gefunden." });
|
|
}
|
|
|
|
return Ok(await user.ToCurrentUserResponseAsync(userManager));
|
|
}
|
|
|
|
[HttpPost("{id:guid")]
|
|
public async Task<IActionResult> 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));
|
|
}
|
|
}
|
|
}
|