459 lines
21 KiB
C#
459 lines
21 KiB
C#
using System.Data;
|
|
using Marco.Pms.DataAccess.Data;
|
|
using Marco.Pms.Model.Dtos.Employees;
|
|
using Marco.Pms.Model.Dtos.Roles;
|
|
using Marco.Pms.Model.Employees;
|
|
using Marco.Pms.Model.Entitlements;
|
|
using Marco.Pms.Model.Mapper;
|
|
using Marco.Pms.Model.Roles;
|
|
using Marco.Pms.Model.Utilities;
|
|
using Marco.Pms.Model.ViewModels;
|
|
using Marco.Pms.Model.ViewModels.Master;
|
|
using Marco.Pms.Model.ViewModels.Roles;
|
|
using Marco.Pms.Services.Helpers;
|
|
using MarcoBMS.Services.Helpers;
|
|
using MarcoBMS.Services.Service;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Identity;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.EntityFrameworkCore;
|
|
#nullable disable
|
|
namespace MarcoBMS.Services.Controllers
|
|
{
|
|
[Route("api/[controller]")]
|
|
[ApiController]
|
|
[Authorize]
|
|
public class RolesController : ControllerBase
|
|
{
|
|
private readonly ApplicationDbContext _context;
|
|
private readonly RolesHelper _rolesHelper;
|
|
private readonly UserHelper _userHelper;
|
|
private readonly UserManager<ApplicationUser> _userManager;
|
|
private readonly ILoggingService _logger;
|
|
private readonly CacheUpdateHelper _cache;
|
|
|
|
public RolesController(UserManager<ApplicationUser> userManager, ApplicationDbContext context, RolesHelper rolesHelper, UserHelper userHelper, ILoggingService logger,
|
|
CacheUpdateHelper cache)
|
|
{
|
|
_context = context;
|
|
_userManager = userManager;
|
|
_rolesHelper = rolesHelper;
|
|
_userHelper = userHelper;
|
|
_logger = logger;
|
|
_cache = cache;
|
|
}
|
|
|
|
private Guid GetTenantId()
|
|
{
|
|
return _userHelper.GetTenantId();
|
|
}
|
|
|
|
[HttpGet("jobrole")]
|
|
public async Task<IActionResult> GetAllJobRoles()
|
|
{
|
|
Guid TenantId = GetTenantId();
|
|
var roles = await _context.JobRoles.Where(c => c.TenantId == TenantId).Select(x => new JobRoleVM()
|
|
{
|
|
Id = x.Id,
|
|
Name = x.Name,
|
|
Description = x.Description
|
|
}).ToListAsync();
|
|
return Ok(ApiResponse<object>.SuccessResponse(roles, "Success.", 200));
|
|
}
|
|
|
|
[HttpPost("jobrole")]
|
|
public async Task<IActionResult> AddJobRole([FromBody] CreateJobRoleDto createJobRoleDto)
|
|
|
|
{
|
|
|
|
Guid TenantId = GetTenantId();
|
|
if (await _context.JobRoles.AnyAsync(c => c.Name.ToLower() == createJobRoleDto.Name.ToLower() && c.TenantId == TenantId))
|
|
{
|
|
return BadRequest(ApiResponse<object>.ErrorResponse("Role with same name already Exists.", "Role with same name already Exists.", 400));
|
|
}
|
|
else
|
|
{
|
|
JobRole jr = createJobRoleDto.ToJobRoleFromCreateJobRoleDot(TenantId);
|
|
_context.JobRoles.Add(jr);
|
|
await _context.SaveChangesAsync();
|
|
return Ok(ApiResponse<object>.SuccessResponse(jr, "Success.", 200));
|
|
}
|
|
}
|
|
|
|
[HttpPut("jobrole/{id}")]
|
|
public async Task<IActionResult> UpdateJobRole(string id, [FromBody] UpdateJobRoleDto updateRoleDto)
|
|
{
|
|
if (!ModelState.IsValid)
|
|
{
|
|
var errors = ModelState.Values
|
|
.SelectMany(v => v.Errors)
|
|
.Select(e => e.ErrorMessage)
|
|
.ToList();
|
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", errors, 400));
|
|
}
|
|
if (id != updateRoleDto.Id.ToString())
|
|
return BadRequest(ApiResponse<object>.ErrorResponse("Role ID mismatch", "Role ID mismatch", 400));
|
|
|
|
try
|
|
{
|
|
Guid TenantId = GetTenantId();
|
|
|
|
JobRole jr = updateRoleDto.ToJobRoleFromUpdateJobRoleDot(TenantId);
|
|
_context.JobRoles.Update(jr);
|
|
await _context.SaveChangesAsync();
|
|
return Ok(ApiResponse<object>.SuccessResponse(jr, "Success.", 200));
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return BadRequest(ApiResponse<object>.ErrorResponse(ex.Message, ex, 400));
|
|
}
|
|
}
|
|
[HttpDelete("jobrole/{id}")]
|
|
public async Task<IActionResult> DeleteJobRole(Guid id)
|
|
{
|
|
Guid tenantId = GetTenantId();
|
|
var LoggedEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
|
var jobRole = await _context.JobRoles.FirstOrDefaultAsync(r => r.Id == id && r.TenantId == tenantId);
|
|
if (jobRole != null)
|
|
{
|
|
var employee = await _context.Employees.Where(e => e.JobRoleId == jobRole.Id).ToListAsync();
|
|
if (employee.Any())
|
|
{
|
|
_logger.LogWarning("Employee with ID {LoggedEmployeeId} tries to delete the job role with ID {JobRoleId} which is assigned to one or more employees", LoggedEmployee.Id, jobRole.Id);
|
|
return BadRequest(ApiResponse<object>.ErrorResponse("Cannot delete the job role because it is assigned to one or more employees.", "Cannot delete the job role because it is assigned to one or more employees.", 400));
|
|
}
|
|
_context.JobRoles.Remove(jobRole);
|
|
await _context.SaveChangesAsync();
|
|
_logger.LogInfo("Employee with ID {LoggedEmployeeId} deleted the job role with ID {JobRoleId}", LoggedEmployee.Id, jobRole.Id);
|
|
}
|
|
else
|
|
{
|
|
_logger.LogWarning("Job role with ID {JobRoleId} not found in database", id);
|
|
}
|
|
return Ok(ApiResponse<object>.SuccessResponse(new { }, "Job role deleted successfully", 200));
|
|
}
|
|
|
|
[HttpGet]
|
|
public async Task<IActionResult> GetAllRoles()
|
|
{
|
|
Guid TenantId = GetTenantId();
|
|
|
|
var roles = await _context.ApplicationRoles.Where(c => c.TenantId == TenantId).ToListAsync();
|
|
|
|
|
|
var roleFeaturePermissions = await _context.RolePermissionMappings
|
|
.Join(
|
|
_context.FeaturePermissions,
|
|
rfp => rfp.FeaturePermissionId,
|
|
fp => fp.Id,
|
|
(rfp, fp) => new { rfp.ApplicationRoleId, FeaturePermission = fp })
|
|
.Join(
|
|
_context.ApplicationRoles,
|
|
result => result.ApplicationRoleId,
|
|
role => role.Id,
|
|
(result, role) => new { Role = role, result.FeaturePermission })
|
|
.Where(x => x.Role.TenantId == TenantId) // Filter by TenantId
|
|
.Select(x => new
|
|
{
|
|
RoleId = x.Role.Id,
|
|
RoleName = x.Role.Role,
|
|
FeaturePermission = x.FeaturePermission
|
|
})
|
|
.OrderByDescending(r => r.RoleName)
|
|
.ToListAsync();
|
|
|
|
List<ApplicationRolesVM> applicationRoles = new List<ApplicationRolesVM>();
|
|
|
|
foreach (var item in roles)
|
|
{
|
|
var rolesVM = new ApplicationRolesVM()
|
|
{
|
|
Id = item.Id,
|
|
Role = item.Role,
|
|
IsSystem = item.IsSystem,
|
|
Description = item.Description,
|
|
FeaturePermission = []
|
|
};
|
|
|
|
ICollection<FeaturePermission> permissions = roleFeaturePermissions.Where(c => c.RoleId == item.Id)
|
|
.Select(c => c.FeaturePermission).ToList();
|
|
|
|
foreach (var permission in permissions)
|
|
{
|
|
rolesVM.FeaturePermission.Add(
|
|
new FeaturePermissionVM()
|
|
{
|
|
Id = permission.Id,
|
|
Description = permission.Description,
|
|
FeatureId = permission.FeatureId,
|
|
IsEnabled = permission.IsEnabled,
|
|
Name = permission.Name
|
|
});
|
|
}
|
|
|
|
applicationRoles.Add(rolesVM);
|
|
|
|
}
|
|
|
|
return Ok(ApiResponse<object>.SuccessResponse(applicationRoles, "Roles list fetched successfully.", 200));
|
|
}
|
|
|
|
|
|
[HttpPost]
|
|
public async Task<IActionResult> AddRole([FromBody] CreateApplicationRoleDto createRoleDto)
|
|
{
|
|
if (!ModelState.IsValid)
|
|
{
|
|
var errors = ModelState.Values
|
|
.SelectMany(v => v.Errors)
|
|
.Select(e => e.ErrorMessage)
|
|
.ToList();
|
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", errors, 400));
|
|
}
|
|
|
|
Guid TenantId = GetTenantId();
|
|
|
|
if (createRoleDto.FeaturesPermission == null || (createRoleDto.FeaturesPermission != null && createRoleDto.FeaturesPermission.Count == 0))
|
|
{
|
|
return BadRequest(ApiResponse<object>.ErrorResponse("Feature Permission is required.", "Feature Permission is required.", 400));
|
|
}
|
|
|
|
bool roleExists = _context.ApplicationRoles
|
|
.Any(r => r.TenantId == TenantId && r.Role.ToLower() == createRoleDto.Role.ToLower());// assuming role name is unique per tenant
|
|
if (roleExists)
|
|
{
|
|
return BadRequest(ApiResponse<object>.ErrorResponse("Role already exists.", "Role already exists.", 400));
|
|
}
|
|
ApplicationRole role = createRoleDto.ToApplicationRoleFromCreateDto(TenantId);
|
|
_context.ApplicationRoles.Add(role);
|
|
|
|
foreach (var permission in createRoleDto.FeaturesPermission)
|
|
{
|
|
var item = new RolePermissionMappings() { ApplicationRoleId = role.Id, FeaturePermissionId = permission.Id };
|
|
bool assigned = _context.RolePermissionMappings.Any(c => c.ApplicationRoleId == role.Id && c.FeaturePermissionId == permission.Id);
|
|
if (permission.IsEnabled && !assigned)
|
|
_context.RolePermissionMappings.Add(item);
|
|
else
|
|
_context.RolePermissionMappings.Remove(item);
|
|
}
|
|
|
|
await _context.SaveChangesAsync();
|
|
return Ok(ApiResponse<object>.SuccessResponse(role.ToRoleVMFromApplicationRole(), "Roles created successfully.", 200));
|
|
}
|
|
|
|
[HttpPut("{id}")]
|
|
public async Task<IActionResult> UpdateRole(Guid id, [FromBody] UpdateApplicationRoleDto updateRoleDto)
|
|
{
|
|
if (!ModelState.IsValid)
|
|
{
|
|
var errors = ModelState.Values
|
|
.SelectMany(v => v.Errors)
|
|
.Select(e => e.ErrorMessage)
|
|
.ToList();
|
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", errors, 400));
|
|
}
|
|
if (id != updateRoleDto.Id)
|
|
return BadRequest("Role ID mismatch");
|
|
|
|
|
|
try
|
|
{
|
|
Guid TenantId = GetTenantId();
|
|
var LoggedEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
|
var existingRole = await _context.ApplicationRoles.AsNoTracking().FirstOrDefaultAsync(r => r.Id == id);
|
|
if (existingRole != null && existingRole.IsSystem)
|
|
{
|
|
_logger.LogWarning("Employee with ID {LoggedEmployeeId} tries to update System-defined application roles {AppcationRoleId}", LoggedEmployee.Id, existingRole.Id);
|
|
return BadRequest(ApiResponse<object>.ErrorResponse("System-defined roles cannot be updated", "System-defined roles cannot be updated", 400));
|
|
}
|
|
ApplicationRole role = updateRoleDto.ToApplicationRoleFromUpdateDto(TenantId);
|
|
|
|
if (role.TenantId != TenantId)
|
|
return Unauthorized(ApiResponse<object>.ErrorResponse("You don't have any authority to update role", "You don't have any authority to update role", 401));
|
|
if (existingRole != null)
|
|
{
|
|
_context.ApplicationRoles.Update(role);
|
|
await _context.SaveChangesAsync();
|
|
}
|
|
|
|
bool modified = false;
|
|
foreach (var permission in updateRoleDto.FeaturesPermission)
|
|
{
|
|
var item = new RolePermissionMappings() { ApplicationRoleId = role.Id, FeaturePermissionId = permission.Id };
|
|
bool assigned = _context.RolePermissionMappings.Any(c => c.ApplicationRoleId == role.Id && c.FeaturePermissionId == permission.Id);
|
|
if (permission.IsEnabled == false && assigned == true)
|
|
{
|
|
_context.RolePermissionMappings.Remove(item);
|
|
modified = true;
|
|
}
|
|
else if (permission.IsEnabled && !assigned)
|
|
{
|
|
_context.RolePermissionMappings.Add(item);
|
|
modified = true;
|
|
}
|
|
if (item.FeaturePermissionId == Guid.Parse("172fc9b6-755b-4f62-ab26-55c34a330614"))
|
|
{
|
|
await _cache.ClearAllProjectIdsByRoleId(id);
|
|
}
|
|
}
|
|
if (modified)
|
|
await _context.SaveChangesAsync();
|
|
|
|
await _cache.ClearAllPermissionIdsByRoleId(id);
|
|
|
|
ApplicationRolesVM response = role.ToRoleVMFromApplicationRole();
|
|
List<FeaturePermission> permissions = await _rolesHelper.GetFeaturePermissionByRoleID(response.Id);
|
|
response.FeaturePermission = permissions.Select(c => c.ToFeaturePermissionVMFromFeaturePermission()).ToList();
|
|
|
|
return Ok(ApiResponse<object>.SuccessResponse(response, "Roles perimssions updated.", 200));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
var response = new
|
|
{
|
|
message = ex.Message,
|
|
detail = ex.StackTrace,
|
|
statusCode = StatusCodes.Status500InternalServerError
|
|
};
|
|
return BadRequest(ApiResponse<object>.ErrorResponse(ex.Message, response, 400));
|
|
}
|
|
}
|
|
|
|
|
|
[HttpGet("{id}")]
|
|
public async Task<IActionResult> GetRoleById(Guid id)
|
|
{
|
|
Guid TenantId = GetTenantId();
|
|
|
|
var role = await _context.ApplicationRoles.FindAsync(id);
|
|
|
|
if (role == null)
|
|
return NotFound(ApiResponse<object>.ErrorResponse("Role not found", "Role not found", 404));
|
|
|
|
if (role.TenantId != TenantId)
|
|
return Unauthorized(ApiResponse<object>.ErrorResponse("You don't have any authority", "You don't have any authority", 401));
|
|
|
|
var featurePermissions = await _context.RolePermissionMappings
|
|
.Where(rfp => rfp.ApplicationRoleId == id)
|
|
.Join(
|
|
_context.FeaturePermissions,
|
|
rfp => rfp.FeaturePermissionId,
|
|
fp => fp.Id,
|
|
(rfp, fp) => new FeaturePermissionVM()
|
|
{
|
|
Id = fp.Id,
|
|
Name = fp.Name,
|
|
Description = fp.Description,
|
|
IsEnabled = fp.IsEnabled,
|
|
FeatureId = fp.FeatureId
|
|
})
|
|
.ToListAsync();
|
|
|
|
ApplicationRolesVM vm = new ApplicationRolesVM()
|
|
{
|
|
Id = role.Id,
|
|
Role = role.Role,
|
|
IsSystem = role.IsSystem,
|
|
FeaturePermission = featurePermissions
|
|
};
|
|
|
|
return Ok(ApiResponse<object>.SuccessResponse(vm, "Roles Perimssions fetched successfully.", 200));
|
|
|
|
}
|
|
[HttpDelete("{id}")]
|
|
public async Task<IActionResult> DeleteApplicationRole(Guid id)
|
|
{
|
|
Guid tenantId = GetTenantId();
|
|
var LoggedEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
|
var role = await _context.ApplicationRoles.AsNoTracking().FirstOrDefaultAsync(r => r.Id == id && r.TenantId == tenantId);
|
|
if (role != null)
|
|
{
|
|
if (role.IsSystem)
|
|
{
|
|
_logger.LogInfo("Employee with ID {LoggedEmployeeId} tries to delete system-defined application role with ID {ApplicationRoleId}", LoggedEmployee.Id, role.Id);
|
|
return BadRequest(ApiResponse<object>.ErrorResponse("This role cannot be deleted because it is system-defined.", "This role cannot be deleted because it is system-defined.", 400));
|
|
}
|
|
var employeeRoleMapping = await _context.EmployeeRoleMappings.Where(erm => erm.RoleId == role.Id).ToListAsync();
|
|
if (employeeRoleMapping.Count != 0)
|
|
{
|
|
_logger.LogInfo("Employee with ID {LoggedEmployeeId} tries to delete application role with ID {ApplicationRoleId} with is assigned to an employee", LoggedEmployee.Id, role.Id);
|
|
return BadRequest(ApiResponse<object>.ErrorResponse("This role cannot be deleted because it is currently assigned to employees.", "This role cannot be deleted because it is currently assigned to employees.", 400));
|
|
}
|
|
_context.ApplicationRoles.Remove(role);
|
|
var rolePermissionMapping = await _context.RolePermissionMappings.Where(r => r.ApplicationRoleId == role.Id).ToListAsync();
|
|
if (rolePermissionMapping.Count != 0)
|
|
{
|
|
_context.RolePermissionMappings.RemoveRange(rolePermissionMapping);
|
|
_logger.LogInfo("All permissions assigned to the application role with ID {ApplicationRoleId} have been removed.", role.Id);
|
|
}
|
|
await _context.SaveChangesAsync();
|
|
_logger.LogInfo("Employee with ID {LoggedEmployeeId} deleted application role with ID {ApplicationRoleId}", LoggedEmployee.Id, role.Id);
|
|
}
|
|
else
|
|
{
|
|
_logger.LogWarning("Application role with ID {ApplicationRoleId} not found in database", id);
|
|
}
|
|
return Ok(ApiResponse<object>.SuccessResponse(new { }, "Application role is deleted successfully", 200));
|
|
}
|
|
|
|
|
|
[HttpPost]
|
|
[Route("assign-roles")]
|
|
public async Task<IActionResult> ManageRoles([FromBody] List<EmployeeRoleDot> employeeRoleDots)
|
|
{
|
|
if (!ModelState.IsValid)
|
|
{
|
|
var errors = ModelState.Values
|
|
.SelectMany(v => v.Errors)
|
|
.Select(e => e.ErrorMessage)
|
|
.ToList();
|
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", errors, 400));
|
|
}
|
|
var employeesIds = employeeRoleDots.Select(e => e.EmployeeId).Distinct().ToList();
|
|
var LoggedEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
|
var employees = await _context.Employees.Where(e => employeesIds.Contains(e.Id)).ToListAsync();
|
|
|
|
Guid TenantId = GetTenantId();
|
|
try
|
|
{
|
|
foreach (EmployeeRoleDot role in employeeRoleDots)
|
|
{
|
|
var employee = employees.Find(e => e.Id == role.EmployeeId && e.IsSystem);
|
|
if (employee != null)
|
|
{
|
|
_logger.LogWarning("Employee with ID {LoggedEmployeeId} tries to assign or remove the application role to System-defined employee with ID {EmployeeId}", LoggedEmployee.Id, employee.Id);
|
|
return BadRequest(ApiResponse<object>.ErrorResponse("System-defined employee cannot have application roles assigned or removed.", "System-defined employee cannot have application roles assigned or removed.", 400));
|
|
}
|
|
EmployeeRoleMapping mapping = role.ToEmployeeRoleMappingFromEmployeeRoleDot(TenantId);
|
|
|
|
var existingItem = await _context.EmployeeRoleMappings.AsNoTracking().SingleOrDefaultAsync(c => c.Id == mapping.Id);
|
|
|
|
if (existingItem == null)
|
|
{
|
|
if (role.IsEnabled == true)
|
|
{
|
|
_context.EmployeeRoleMappings.Add(mapping);
|
|
await _cache.AddApplicationRole(role.EmployeeId, [mapping.RoleId]);
|
|
}
|
|
}
|
|
else if (role.IsEnabled == false)
|
|
{
|
|
_context.EmployeeRoleMappings.Remove(existingItem);
|
|
await _cache.RemoveRoleId(existingItem.EmployeeId, existingItem.RoleId);
|
|
await _cache.ClearAllPermissionIdsByEmployeeID(existingItem.EmployeeId);
|
|
}
|
|
await _cache.ClearAllProjectIds(role.EmployeeId);
|
|
|
|
}
|
|
await _context.SaveChangesAsync();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return BadRequest(ApiResponse<object>.ErrorResponse(ex.Message, ex, 400));
|
|
}
|
|
return Ok(ApiResponse<object>.SuccessResponse("success", "Roles modified.", 200));
|
|
}
|
|
}
|
|
}
|