using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Nuuru.Server.Auth; using Nuuru.Server.Data; using Nuuru.Server.DTOs.Role; using Nuuru.Server.Extensions; using Nuuru.Server.Models; using Nuuru.Server.Services; namespace Nuuru.Server.Controllers { [ApiController] [Route("api/[controller]")] [Authorize(Policy = Permissions.Admin.ManagePermissions)] public class RoleController : ControllerBase { private readonly IRoleService _roleService; private readonly IPermissionMetadataService _metadataService; private readonly ApplicationDbContext _context; private readonly UserManager _userManager; private readonly ILogger _logger; public RoleController( IRoleService roleService, IPermissionMetadataService metadataService, ApplicationDbContext context, UserManager userManager, ILogger logger) { _roleService = roleService; _metadataService = metadataService; _context = context; _userManager = userManager; _logger = logger; } /// /// Get all roles /// [HttpGet] public async Task GetAllRoles() { var roles = await _roleService.GetAllRolesAsync(); return Ok(roles); } /// /// Get role by ID /// [HttpGet("{roleId}")] public async Task GetRole(Guid roleId) { var role = await _roleService.GetRoleAsync(roleId); if (role == null) { return NotFound(new { error = "Role not found" }); } return Ok(role); } /// /// Create a new role /// [HttpPost] public async Task CreateRole([FromBody] CreateRoleRequest request) { if (string.IsNullOrWhiteSpace(request.Name)) { return BadRequest(new { error = "Role name is required" }); } // Validate all permissions var invalidPermissions = request.Permissions .Where(p => !_metadataService.IsValidPermission(p)) .ToList(); if (invalidPermissions.Any()) { return BadRequest(new { error = "Invalid permissions", invalidPermissions }); } var role = await _roleService.CreateRoleAsync(request.Name, request.Color, request.Permissions); if (role == null) { return BadRequest(new { error = "Failed to create role. Role name may already exist." }); } var moderator = await _userManager.GetUserAsync(User); if (moderator != null) { _context.ModerationActions.Add(new ModerationAction { Action = "CreateRole", TargetType = "Role", TargetId = role.Id.ToString(), Details = $"Created role \"{request.Name}\" with {request.Permissions.Count()} permissions", Moderator = moderator }); await _context.SaveChangesAsync(); } _logger.LogInformation("Role {RoleName} created by {AdminId}", request.Name, User.GetUserId()); // Set target for audit log HttpContext.Items[AuditLog.TargetIdKey] = role.Id.ToString(); HttpContext.Items[AuditLog.TargetTypeKey] = "Role"; return CreatedAtAction(nameof(GetRole), new { roleId = role.Id }, role); } /// /// Update an existing role /// [HttpPut("{roleId}")] public async Task UpdateRole(Guid roleId, [FromBody] UpdateRoleRequest request) { if (string.IsNullOrWhiteSpace(request.Name)) { return BadRequest(new { error = "Role name is required" }); } // Validate all permissions var invalidPermissions = request.Permissions .Where(p => !_metadataService.IsValidPermission(p)) .ToList(); if (invalidPermissions.Any()) { return BadRequest(new { error = "Invalid permissions", invalidPermissions }); } var role = await _roleService.UpdateRoleAsync(roleId, request.Name, request.Color, request.Permissions); if (role == null) { return BadRequest(new { error = "Failed to update role. Role may not exist or name may already be in use." }); } var moderator = await _userManager.GetUserAsync(User); if (moderator != null) { _context.ModerationActions.Add(new ModerationAction { Action = "UpdateRole", TargetType = "Role", TargetId = roleId.ToString(), Details = $"Updated role \"{request.Name}\"", Moderator = moderator }); await _context.SaveChangesAsync(); } _logger.LogInformation("Role {RoleId} updated by {AdminId}", roleId, User.GetUserId()); // Set target for audit log HttpContext.Items[AuditLog.TargetIdKey] = roleId.ToString(); HttpContext.Items[AuditLog.TargetTypeKey] = "Role"; return Ok(role); } /// /// Delete a role /// [HttpDelete("{roleId}")] public async Task DeleteRole(Guid roleId) { var result = await _roleService.DeleteRoleAsync(roleId); if (!result) { return BadRequest(new { error = "Failed to delete role. Role may not exist or may have users assigned to it." }); } var moderator = await _userManager.GetUserAsync(User); if (moderator != null) { _context.ModerationActions.Add(new ModerationAction { Action = "DeleteRole", TargetType = "Role", TargetId = roleId.ToString(), Moderator = moderator }); await _context.SaveChangesAsync(); } _logger.LogInformation("Role {RoleId} deleted by {AdminId}", roleId, User.GetUserId()); // Set target for audit log HttpContext.Items[AuditLog.TargetIdKey] = roleId.ToString(); HttpContext.Items[AuditLog.TargetTypeKey] = "Role"; return Ok(new { message = "Role deleted successfully" }); } [Authorize(Policy = Permissions.Admin.ManageUsers)] [HttpPost("{roleId}/users/{userId}")] public async Task AssignRoleToUser(Guid roleId, Guid userId) { if (await IsSystemAccountAsync(userId)) return BadRequest(new { error = "Cannot modify system accounts" }); var result = await _roleService.AssignRoleToUserAsync(userId, roleId); if (!result) { return BadRequest(new { error = "Failed to assign role to user. User or role may not exist, or user may already have this role." }); } var targetUser = await _userManager.FindByIdAsync(userId.ToString()); var moderator = await _userManager.GetUserAsync(User); if (moderator != null) { _context.ModerationActions.Add(new ModerationAction { Action = "AssignRole", TargetType = "User", TargetId = targetUser?.UserName ?? userId.ToString(), Details = $"Assigned role {roleId}", Moderator = moderator }); await _context.SaveChangesAsync(); } _logger.LogInformation("Role {RoleId} assigned to user {UserId} by {AdminId}", roleId, userId, User.GetUserId()); // Set target for audit log HttpContext.Items[AuditLog.TargetIdKey] = targetUser?.UserName ?? userId.ToString(); HttpContext.Items[AuditLog.TargetTypeKey] = "User"; return Ok(new { message = "Role assigned successfully" }); } /// /// Remove a role from a user /// [Authorize(Policy = Permissions.Admin.ManageUsers)] [HttpDelete("{roleId}/users/{userId}")] public async Task RemoveRoleFromUser(Guid roleId, Guid userId) { if (await IsSystemAccountAsync(userId)) return BadRequest(new { error = "Cannot modify system accounts" }); var result = await _roleService.RemoveRoleFromUserAsync(userId, roleId); if (!result) { return BadRequest(new { error = "Failed to remove role from user. User or role may not exist, or user may not have this role." }); } var targetUser = await _userManager.FindByIdAsync(userId.ToString()); var moderator = await _userManager.GetUserAsync(User); if (moderator != null) { _context.ModerationActions.Add(new ModerationAction { Action = "RemoveRole", TargetType = "User", TargetId = targetUser?.UserName ?? userId.ToString(), Details = $"Removed role {roleId}", Moderator = moderator }); await _context.SaveChangesAsync(); } _logger.LogInformation("Role {RoleId} removed from user {UserId} by {AdminId}", roleId, userId, User.GetUserId()); // Set target for audit log HttpContext.Items[AuditLog.TargetIdKey] = targetUser?.UserName ?? userId.ToString(); HttpContext.Items[AuditLog.TargetTypeKey] = "User"; return Ok(new { message = "Role removed successfully" }); } /// /// Get all roles for a user /// [HttpGet("user/{userId}")] public async Task GetUserRoles(Guid userId) { var roles = await _roleService.GetUserRolesAsync(userId); return Ok(new { userId, roles }); } private async Task IsSystemAccountAsync(Guid userId) { var user = await _userManager.FindByIdAsync(userId.ToString()); return user?.IsSystemAccount == true; } } }