using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Nuuru.Server.Auth; using Nuuru.Server.Data; 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 PermissionController : ControllerBase { private readonly IPermissionService _permissionService; private readonly IPermissionMetadataService _metadataService; private readonly ApplicationDbContext _context; private readonly UserManager _userManager; private readonly ILogger _logger; public PermissionController( IPermissionService permissionService, IPermissionMetadataService metadataService, ApplicationDbContext context, UserManager userManager, ILogger logger) { _permissionService = permissionService; _metadataService = metadataService; _context = context; _userManager = userManager; _logger = logger; } [HttpGet("user/{userId}")] public async Task GetUserPermissions(Guid userId) { var permissions = await _permissionService.GetUserPermissionsAsync(userId); var deniedPermissions = await _permissionService.GetDeniedPermissionsAsync(userId); var effectivePermissions = await _permissionService.GetEffectivePermissionsAsync(userId); return Ok(new { userId, permissions, deniedPermissions, effectivePermissions }); } [HttpPost("user/{userId}/grant")] public async Task GrantPermission(Guid userId, [FromBody] PermissionRequest request) { if (await IsSystemAccountAsync(userId)) return BadRequest(new { error = "Cannot modify system accounts" }); if (string.IsNullOrWhiteSpace(request.Permission)) { return BadRequest(new { error = "Permission is required" }); } // Validate permission exists in constants if (!_metadataService.IsValidPermission(request.Permission)) { return BadRequest(new { error = "Invalid permission" }); } var result = await _permissionService.GrantPermissionAsync(userId, request.Permission); if (!result) { return BadRequest(new { error = "Failed to grant permission" }); } var targetUser = await _userManager.FindByIdAsync(userId.ToString()); var moderator = await _userManager.GetUserAsync(User); if (moderator != null) { _context.ModerationActions.Add(new ModerationAction { Action = "GrantPermission", TargetType = "User", TargetId = targetUser?.UserName ?? userId.ToString(), Details = $"Granted permission: {request.Permission}", Moderator = moderator }); await _context.SaveChangesAsync(); } _logger.LogInformation("Permission {Permission} granted to user {UserId} by {AdminId}", request.Permission, 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 = "Permission granted successfully" }); } [HttpPost("user/{userId}/revoke")] public async Task RevokePermission(Guid userId, [FromBody] PermissionRequest request) { if (await IsSystemAccountAsync(userId)) return BadRequest(new { error = "Cannot modify system accounts" }); if (string.IsNullOrWhiteSpace(request.Permission)) { return BadRequest(new { error = "Permission is required" }); } var result = await _permissionService.RevokePermissionAsync(userId, request.Permission); if (!result) { return BadRequest(new { error = "Failed to revoke permission" }); } var targetUser = await _userManager.FindByIdAsync(userId.ToString()); var moderator = await _userManager.GetUserAsync(User); if (moderator != null) { _context.ModerationActions.Add(new ModerationAction { Action = "RevokePermission", TargetType = "User", TargetId = targetUser?.UserName ?? userId.ToString(), Details = $"Revoked permission: {request.Permission}", Moderator = moderator }); await _context.SaveChangesAsync(); } _logger.LogInformation("Permission {Permission} revoked from user {UserId} by {AdminId}", request.Permission, 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 = "Permission revoked successfully" }); } [HttpPut("user/{userId}")] public async Task SetUserPermissions(Guid userId, [FromBody] SetPermissionsRequest request) { if (await IsSystemAccountAsync(userId)) return BadRequest(new { error = "Cannot modify system accounts" }); // Prevent removing own admin permissions if (userId == User.GetUserId() && !request.Permissions.Contains(Permissions.Admin.ManagePermissions)) { return BadRequest(new { error = "Cannot remove your own permission management rights" }); } // Validate all permissions var invalidPermissions = request.Permissions.Where(p => !_metadataService.IsValidPermission(p)).ToList(); if (invalidPermissions.Any()) { return BadRequest(new { error = "Invalid permissions", invalidPermissions }); } var result = await _permissionService.SetUserPermissionsAsync(userId, request.Permissions); if (!result) { return BadRequest(new { error = "Failed to update permissions" }); } var targetUser = await _userManager.FindByIdAsync(userId.ToString()); var moderator = await _userManager.GetUserAsync(User); if (moderator != null) { _context.ModerationActions.Add(new ModerationAction { Action = "SetPermissions", TargetType = "User", TargetId = targetUser?.UserName ?? userId.ToString(), Details = $"Set permissions: {string.Join(", ", request.Permissions)}", Moderator = moderator }); await _context.SaveChangesAsync(); } _logger.LogInformation("Permissions updated for user {UserId} by {AdminId}. New permissions: {Permissions}", userId, User.GetUserId(), string.Join(", ", request.Permissions)); // Set target for audit log HttpContext.Items[AuditLog.TargetIdKey] = targetUser?.UserName ?? userId.ToString(); HttpContext.Items[AuditLog.TargetTypeKey] = "User"; return Ok(new { message = "Permissions updated successfully", permissions = request.Permissions }); } [HttpGet("available")] public IActionResult GetAvailablePermissions() { var permissionsByCategory = _metadataService.GetPermissionsByCategory(); var result = new Dictionary(); foreach (var category in permissionsByCategory) { var categoryName = category.Key.ToString().ToLowerInvariant(); result[categoryName] = category.Value.Select(p => new { value = p.Value, description = p.Description, displayOrder = p.DisplayOrder }); } return Ok(result); } [HttpGet("permission/{permission}")] public IActionResult GetPermissionInfo(string permission) { var info = _metadataService.GetPermissionInfo(permission); if (info == null) { return NotFound(new { error = "Permission not found" }); } return Ok(new { value = info.Value, description = info.Description, category = info.Category.ToString(), displayOrder = info.DisplayOrder }); } [HttpPost("user/{userId}/deny")] public async Task DenyPermission(Guid userId, [FromBody] PermissionRequest request) { if (await IsSystemAccountAsync(userId)) return BadRequest(new { error = "Cannot modify system accounts" }); if (string.IsNullOrWhiteSpace(request.Permission)) { return BadRequest(new { error = "Permission is required" }); } // Validate permission exists in constants if (!_metadataService.IsValidPermission(request.Permission)) { return BadRequest(new { error = "Invalid permission" }); } var result = await _permissionService.DenyPermissionAsync(userId, request.Permission); if (!result) { return BadRequest(new { error = "Failed to deny permission. Permission may already be denied." }); } var targetUser = await _userManager.FindByIdAsync(userId.ToString()); var moderator = await _userManager.GetUserAsync(User); if (moderator != null) { _context.ModerationActions.Add(new ModerationAction { Action = "DenyPermission", TargetType = "User", TargetId = targetUser?.UserName ?? userId.ToString(), Details = $"Denied permission: {request.Permission}", Moderator = moderator }); await _context.SaveChangesAsync(); } _logger.LogInformation("Permission {Permission} denied for user {UserId} by {AdminId}", request.Permission, 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 = "Permission denied successfully" }); } [HttpPost("user/{userId}/remove-deny")] public async Task RemoveDenyPermission(Guid userId, [FromBody] PermissionRequest request) { if (await IsSystemAccountAsync(userId)) return BadRequest(new { error = "Cannot modify system accounts" }); if (string.IsNullOrWhiteSpace(request.Permission)) { return BadRequest(new { error = "Permission is required" }); } var result = await _permissionService.RemoveDenyPermissionAsync(userId, request.Permission); if (!result) { return BadRequest(new { error = "Failed to remove permission denial. Permission may not be denied." }); } var targetUser = await _userManager.FindByIdAsync(userId.ToString()); var moderator = await _userManager.GetUserAsync(User); if (moderator != null) { _context.ModerationActions.Add(new ModerationAction { Action = "RemoveDenyPermission", TargetType = "User", TargetId = targetUser?.UserName ?? userId.ToString(), Details = $"Removed permission denial: {request.Permission}", Moderator = moderator }); await _context.SaveChangesAsync(); } _logger.LogInformation("Permission denial {Permission} removed from user {UserId} by {AdminId}", request.Permission, 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 = "Permission denial removed successfully" }); } private async Task IsSystemAccountAsync(Guid userId) { var user = await _userManager.FindByIdAsync(userId.ToString()); return user?.IsSystemAccount == true; } [HttpGet("user/{userId}/denied")] public async Task GetDeniedPermissions(Guid userId) { var deniedPermissions = await _permissionService.GetDeniedPermissionsAsync(userId); return Ok(new { userId, deniedPermissions }); } [HttpGet("user/{userId}/effective")] public async Task GetEffectivePermissions(Guid userId) { var effectivePermissions = await _permissionService.GetEffectivePermissionsAsync(userId); return Ok(new { userId, effectivePermissions }); } } public class PermissionRequest { public string Permission { get; set; } = string.Empty; } public class SetPermissionsRequest { public IEnumerable Permissions { get; set; } = new List(); } }