using System; using System.Security.Claims; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; using FinlyticBackend.Services; using FinlyticCore.Models.Auth; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Mvc; namespace FinlyticBackend.Controllers; /// /// DTO for admin password reset requests (AOT-compliant). /// public record ResetPasswordAdminDto( [property: JsonPropertyName("newPassword")] string NewPassword ); [ApiController] [Route("api/v1/admin")] [Authorize(Roles = "Admin")] [EnableCors("AllowAll")] public class AdminUserController : ControllerBase { private readonly IUserService _userService; public AdminUserController(IUserService userService) { _userService = userService; } /// /// Creates a new user account by an administrator. /// [HttpPost("users")] public async Task CreateUser([FromBody] CreateUserRequestDto request, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(request.Email) || string.IsNullOrWhiteSpace(request.Password)) { return BadRequest(new { error = "Email and Password are required." }); } var createdUser = await _userService.CreateUserByAdminAsync(request, cancellationToken); if (createdUser == null) { return Conflict(new { error = $"User with email '{request.Email}' already exists." }); } return StatusCode(201, createdUser); } /// /// Retrieves a list of all registered users. /// [HttpGet("users")] public async Task GetAllUsers(CancellationToken cancellationToken) { var users = await _userService.GetAllUsersAsync(cancellationToken); return Ok(users); } /// /// Updates an existing user account. /// [HttpPut("users/{id:guid}")] public async Task UpdateUser(Guid id, [FromBody] UpdateUserRequestDto request, CancellationToken cancellationToken) { var currentAdminId = GetCurrentUserId(); // Schutz: Ein Admin sollte sich nicht selbst abwerten oder deaktivieren können if (currentAdminId.HasValue && currentAdminId.Value == id) { if (request.IsActive == false) { return BadRequest(new { error = "You cannot deactivate your own admin account." }); } if (!string.IsNullOrWhiteSpace(request.Role) && !request.Role.Equals("Admin", StringComparison.OrdinalIgnoreCase)) { return BadRequest(new { error = "You cannot revoke your own Admin role." }); } } var updated = await _userService.UpdateUserAsync(id, request, cancellationToken); if (updated == null) { return NotFound(new { error = $"User with ID '{id}' not found." }); } return Ok(updated); } /// /// Deactivates a user account. /// [HttpDelete("users/{id:guid}")] public async Task DeactivateUser(Guid id, CancellationToken cancellationToken) { var currentAdminId = GetCurrentUserId(); if (currentAdminId.HasValue && currentAdminId.Value == id) { return BadRequest(new { error = "You cannot deactivate your own admin account." }); } bool deactivated = await _userService.DeactivateUserAsync(id, cancellationToken); if (!deactivated) { return NotFound(new { error = $"User with ID '{id}' not found." }); } return Ok(new { message = $"User '{id}' deactivated successfully." }); } /// /// Resets a user's password and forces password change on next login. /// [HttpPost("users/{id:guid}/reset-password")] public async Task ResetPassword(Guid id, [FromBody] ResetPasswordAdminDto request, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(request?.NewPassword)) { return BadRequest(new { error = "NewPassword is required." }); } bool reset = await _userService.ResetPasswordAsync(id, request.NewPassword, cancellationToken); if (!reset) { return NotFound(new { error = $"User with ID '{id}' not found." }); } return Ok(new { message = $"Password for user '{id}' has been reset successfully. They must change it upon next login." }); } private Guid? GetCurrentUserId() { var claimVal = User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.FindFirstValue("sub"); return Guid.TryParse(claimVal, out var parsed) ? parsed : null; } }