Optimized the assign bucket API and delete bucket API in Directory module
This commit is contained in:
parent
3980c14d72
commit
830accbe98
@ -238,7 +238,7 @@ namespace Marco.Pms.Services.Controllers
|
||||
public async Task<IActionResult> AssignBucket(Guid bucketId, [FromBody] List<AssignBucketDto> assignBuckets)
|
||||
{
|
||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
var response = await _directoryService.AssignBucket(bucketId, assignBuckets);
|
||||
var response = await _directoryService.AssignBucketAsync(bucketId, assignBuckets, tenantId, loggedInEmployee);
|
||||
if (response.Success)
|
||||
{
|
||||
var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Directory_Buckets", Response = response.Data };
|
||||
@ -251,7 +251,7 @@ namespace Marco.Pms.Services.Controllers
|
||||
public async Task<IActionResult> DeleteBucket(Guid id)
|
||||
{
|
||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
var response = await _directoryService.DeleteBucket(id);
|
||||
var response = await _directoryService.DeleteBucketAsync(id, tenantId, loggedInEmployee);
|
||||
if (response.Success)
|
||||
{
|
||||
var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Directory_Buckets", Response = id };
|
||||
|
@ -1780,163 +1780,269 @@ namespace Marco.Pms.Services.Service
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse<object>> AssignBucket(Guid bucketId, List<AssignBucketDto> assignBuckets)
|
||||
public async Task<ApiResponse<object>> AssignBucketAsync(Guid bucketId, List<AssignBucketDto> assignBuckets, Guid tenantId, Employee loggedInEmployee)
|
||||
{
|
||||
Guid tenantId = _userHelper.GetTenantId();
|
||||
var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
if (assignBuckets != null && bucketId != Guid.Empty)
|
||||
// Validate input payload
|
||||
if (assignBuckets == null || bucketId == Guid.Empty)
|
||||
{
|
||||
var assignedRoleIds = await _context.EmployeeRoleMappings.Where(r => r.EmployeeId == LoggedInEmployee.Id).Select(r => r.RoleId).ToListAsync();
|
||||
var permissionIds = await _context.RolePermissionMappings.Where(rp => assignedRoleIds.Contains(rp.ApplicationRoleId)).Select(rp => rp.FeaturePermissionId).Distinct().ToListAsync();
|
||||
_logger.LogWarning("Employee with ID {EmployeeId} sent empty or invalid payload.", loggedInEmployee.Id);
|
||||
return ApiResponse<object>.ErrorResponse("User sent empty or invalid payload", "User sent empty or invalid payload", 400);
|
||||
}
|
||||
|
||||
Bucket? bucket = await _context.Buckets.Include(b => b.CreatedBy).FirstOrDefaultAsync(b => b.Id == bucketId && b.TenantId == tenantId);
|
||||
// Check permissions of the logged-in employee
|
||||
var (hasAdminPermission, hasManagerPermission, hasUserPermission) = await CheckPermissionsAsync(loggedInEmployee.Id);
|
||||
|
||||
|
||||
// Load the bucket with related CreatedBy and validate tenant
|
||||
var bucket = await _context.Buckets.Include(b => b.CreatedBy)
|
||||
.FirstOrDefaultAsync(b => b.Id == bucketId && b.TenantId == tenantId);
|
||||
|
||||
if (bucket == null)
|
||||
{
|
||||
_logger.LogWarning("Employee ID {LoggedInEmployeeId} attempted to update a bucket but not found in database.", LoggedInEmployee.Id);
|
||||
_logger.LogWarning("Employee ID {EmployeeId} attempted to update bucket {BucketId} but it was not found.", loggedInEmployee.Id, bucketId);
|
||||
return ApiResponse<object>.ErrorResponse("Bucket not found", "Bucket not found", 404);
|
||||
}
|
||||
var employeeBuckets = await _context.EmployeeBucketMappings.Where(eb => eb.BucketId == bucketId).ToListAsync();
|
||||
var bucketIds = employeeBuckets.Where(eb => eb.EmployeeId == LoggedInEmployee.Id).Select(eb => eb.BucketId).ToList();
|
||||
var employeeBucketIds = employeeBuckets.Select(eb => eb.EmployeeId).ToList();
|
||||
Bucket? accessableBucket = null;
|
||||
if (permissionIds.Contains(PermissionsMaster.DirectoryAdmin))
|
||||
|
||||
// Load EmployeeBucketMappings related to the bucket
|
||||
var employeeBuckets = await _context.EmployeeBucketMappings
|
||||
.Where(eb => eb.BucketId == bucketId)
|
||||
.ToListAsync();
|
||||
|
||||
var employeeBucketIds = employeeBuckets.Select(eb => eb.EmployeeId).ToHashSet();
|
||||
|
||||
// Check access permissions to the bucket
|
||||
bool hasAccess = false;
|
||||
if (hasAdminPermission)
|
||||
{
|
||||
accessableBucket = bucket;
|
||||
hasAccess = true;
|
||||
}
|
||||
else if (permissionIds.Contains(PermissionsMaster.DirectoryAdmin) && bucketIds.Contains(bucketId))
|
||||
else if (hasManagerPermission && employeeBucketIds.Contains(loggedInEmployee.Id))
|
||||
{
|
||||
accessableBucket = bucket;
|
||||
hasAccess = true;
|
||||
}
|
||||
else if (permissionIds.Contains(PermissionsMaster.DirectoryUser))
|
||||
else if (hasUserPermission && bucket.CreatedByID == loggedInEmployee.Id)
|
||||
{
|
||||
if (bucket.CreatedByID == LoggedInEmployee.Id)
|
||||
{
|
||||
accessableBucket = bucket;
|
||||
hasAccess = true;
|
||||
}
|
||||
}
|
||||
if (accessableBucket == null)
|
||||
|
||||
if (!hasAccess)
|
||||
{
|
||||
_logger.LogWarning("Employee {EmployeeId} attempted to access bucket {BucketId} without the necessary permissions.", LoggedInEmployee.Id, bucket.Id);
|
||||
_logger.LogWarning("Employee {EmployeeId} attempted to access bucket {BucketId} without permission.", loggedInEmployee.Id, bucketId);
|
||||
return ApiResponse<object>.ErrorResponse("You don't have permission to access this bucket", "You don't have permission to access this bucket", 403);
|
||||
}
|
||||
var employeeIds = await _context.Employees.Where(e => e.TenantId == tenantId && e.IsActive).Select(e => e.Id).ToListAsync();
|
||||
int assignedEmployee = 0;
|
||||
int removededEmployee = 0;
|
||||
|
||||
// Load active employees tenant-wide
|
||||
var activeEmployeeIds = await _context.Employees
|
||||
.Where(e => e.TenantId == tenantId && e.IsActive)
|
||||
.Select(e => e.Id)
|
||||
.ToListAsync();
|
||||
|
||||
int assignedEmployeesCount = 0;
|
||||
int removedEmployeesCount = 0;
|
||||
|
||||
// Process each assignment request
|
||||
foreach (var assignBucket in assignBuckets)
|
||||
{
|
||||
if (employeeIds.Contains(assignBucket.EmployeeId))
|
||||
if (!activeEmployeeIds.Contains(assignBucket.EmployeeId))
|
||||
{
|
||||
if (assignBucket.IsActive && !employeeBucketIds.Contains(assignBucket.EmployeeId))
|
||||
// Skip employee IDs that are not active or not in tenant
|
||||
_logger.LogWarning("Skipping inactive or non-tenant employee ID {EmployeeId} in assignment.", assignBucket.EmployeeId);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (assignBucket.IsActive)
|
||||
{
|
||||
EmployeeBucketMapping employeeBucketMapping = new EmployeeBucketMapping
|
||||
// Add mapping if not already exists
|
||||
if (!employeeBucketIds.Contains(assignBucket.EmployeeId))
|
||||
{
|
||||
var newMapping = new EmployeeBucketMapping
|
||||
{
|
||||
EmployeeId = assignBucket.EmployeeId,
|
||||
BucketId = bucketId
|
||||
};
|
||||
_context.EmployeeBucketMappings.Add(employeeBucketMapping);
|
||||
assignedEmployee += 1;
|
||||
_context.EmployeeBucketMappings.Add(newMapping);
|
||||
assignedEmployeesCount++;
|
||||
}
|
||||
else if (!assignBucket.IsActive)
|
||||
{
|
||||
EmployeeBucketMapping? employeeBucketMapping = employeeBuckets.FirstOrDefault(eb => eb.BucketId == bucketId && eb.EmployeeId == assignBucket.EmployeeId);
|
||||
if (employeeBucketMapping != null)
|
||||
{
|
||||
_context.EmployeeBucketMappings.Remove(employeeBucketMapping);
|
||||
removededEmployee += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove mapping if it exists
|
||||
var existingMapping = employeeBuckets.FirstOrDefault(eb => eb.EmployeeId == assignBucket.EmployeeId);
|
||||
if (existingMapping != null && bucket.CreatedByID != assignBucket.EmployeeId)
|
||||
{
|
||||
_context.EmployeeBucketMappings.Remove(existingMapping);
|
||||
removedEmployeesCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add directory update log
|
||||
_context.DirectoryUpdateLogs.Add(new DirectoryUpdateLog
|
||||
{
|
||||
RefereanceId = bucketId,
|
||||
UpdatedById = LoggedInEmployee.Id,
|
||||
UpdatedById = loggedInEmployee.Id,
|
||||
UpdateAt = DateTime.UtcNow
|
||||
});
|
||||
|
||||
// Save changes with error handling
|
||||
try
|
||||
{
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
AssignBucketVM bucketVM = bucket.ToAssignBucketVMFromBucket();
|
||||
List<EmployeeBucketMapping> employeeBucketMappings = await _context.EmployeeBucketMappings.Where(eb => eb.BucketId == bucket.Id).ToListAsync();
|
||||
List<ContactBucketMapping> contactBuckets = await _context.ContactBucketMappings.Where(eb => eb.BucketId == bucket.Id).ToListAsync();
|
||||
employeeIds = employeeBucketMappings.Select(eb => eb.EmployeeId).ToList();
|
||||
bucketVM.EmployeeIds = employeeIds;
|
||||
bucketVM.NumberOfContacts = contactBuckets.Count;
|
||||
|
||||
if (assignedEmployee > 0)
|
||||
{
|
||||
_logger.LogInfo("Employee {EmployeeId} assigned bucket {BucketId} to {conut} number of employees", LoggedInEmployee.Id, bucketId, assignedEmployee);
|
||||
}
|
||||
if (removededEmployee > 0)
|
||||
catch (DbUpdateException ex)
|
||||
{
|
||||
_logger.LogWarning("Employee {EmployeeId} removed {conut} number of employees from bucket {BucketId}", LoggedInEmployee.Id, removededEmployee, bucketId);
|
||||
}
|
||||
return ApiResponse<object>.SuccessResponse(bucketVM, "Details updated successfully", 200);
|
||||
}
|
||||
_logger.LogWarning("Employee with ID {LoggedInEmployeeId} sended empty payload", LoggedInEmployee.Id);
|
||||
return ApiResponse<object>.ErrorResponse("User Send empty Payload", "User Send empty Payload", 400);
|
||||
}
|
||||
public async Task<ApiResponse<object>> DeleteBucket(Guid id)
|
||||
{
|
||||
Guid tenantId = _userHelper.GetTenantId();
|
||||
var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
|
||||
Bucket? bucket = await _context.Buckets.FirstOrDefaultAsync(n => n.Id == id && n.TenantId == tenantId);
|
||||
|
||||
if (bucket != null)
|
||||
{
|
||||
List<EmployeeBucketMapping>? employeeBuckets = await _context.EmployeeBucketMappings.Where(eb => eb.BucketId == id).ToListAsync();
|
||||
List<ContactBucketMapping>? contactBuckets = await _context.ContactBucketMappings.Where(eb => eb.BucketId == id).ToListAsync();
|
||||
|
||||
if (contactBuckets.Any())
|
||||
{
|
||||
_logger.LogInfo("Employee {EmployeeId} attempted to deleted bucket {BucketId},but bucket have contacts in it.", LoggedInEmployee.Id, id);
|
||||
return ApiResponse<object>.ErrorResponse("This bucket can not be deleted", "This bucket can not be deleted", 400);
|
||||
_logger.LogError(ex, "Failed to save changes while assigning bucket {BucketId} by employee {EmployeeId}.", bucketId, loggedInEmployee.Id);
|
||||
return ApiResponse<object>.ErrorResponse("Failed to update bucket assignments", "An error occurred while updating bucket assignments", 500);
|
||||
}
|
||||
|
||||
var assignedRoleIds = await _context.EmployeeRoleMappings.Where(r => r.EmployeeId == LoggedInEmployee.Id).Select(r => r.RoleId).ToListAsync();
|
||||
var permissionIds = await _context.RolePermissionMappings.Where(rp => assignedRoleIds.Contains(rp.ApplicationRoleId)).Select(rp => rp.FeaturePermissionId).Distinct().ToListAsync();
|
||||
var bucketIds = employeeBuckets.Where(eb => eb.EmployeeId == LoggedInEmployee.Id).Select(eb => eb.BucketId).ToList();
|
||||
// Reload mappings and contacts for the updated bucket
|
||||
var employeeBucketMappingTask = Task.Run(async () =>
|
||||
{
|
||||
using (var context = _dbContextFactory.CreateDbContext())
|
||||
{
|
||||
return await context.EmployeeBucketMappings.Where(eb => eb.BucketId == bucket.Id).ToListAsync();
|
||||
}
|
||||
});
|
||||
var contactBucketMappingTask = Task.Run(async () =>
|
||||
{
|
||||
using (var context = _dbContextFactory.CreateDbContext())
|
||||
{
|
||||
return await context.ContactBucketMappings.Where(eb => eb.BucketId == bucket.Id).ToListAsync();
|
||||
}
|
||||
});
|
||||
await Task.WhenAll(employeeBucketMappingTask, contactBucketMappingTask);
|
||||
var employeeBucketMappings = employeeBucketMappingTask.Result;
|
||||
var contactBucketMappings = contactBucketMappingTask.Result;
|
||||
|
||||
Bucket? accessableBucket = null;
|
||||
if (permissionIds.Contains(PermissionsMaster.DirectoryAdmin))
|
||||
// Prepare view model response
|
||||
var bucketVm = _mapper.Map<AssignBucketVM>(bucket);
|
||||
bucketVm.EmployeeIds = employeeBucketMappings.Select(eb => eb.EmployeeId).ToList();
|
||||
bucketVm.NumberOfContacts = contactBucketMappings.Count;
|
||||
|
||||
// Log assignment and removal actions
|
||||
if (assignedEmployeesCount > 0)
|
||||
{
|
||||
accessableBucket = bucket;
|
||||
_logger.LogInfo("Employee {EmployeeId} assigned bucket {BucketId} to {Count} employees.", loggedInEmployee.Id, bucketId, assignedEmployeesCount);
|
||||
}
|
||||
else if (permissionIds.Contains(PermissionsMaster.DirectoryAdmin) && bucketIds.Contains(id))
|
||||
if (removedEmployeesCount > 0)
|
||||
{
|
||||
accessableBucket = bucket;
|
||||
}
|
||||
else if (permissionIds.Contains(PermissionsMaster.DirectoryUser))
|
||||
{
|
||||
if (bucket.CreatedByID == LoggedInEmployee.Id)
|
||||
{
|
||||
accessableBucket = bucket;
|
||||
}
|
||||
}
|
||||
if (accessableBucket == null)
|
||||
{
|
||||
_logger.LogWarning("Employee {EmployeeId} attempted to access bucket {BucketId} without the necessary permissions.", LoggedInEmployee.Id, bucket.Id);
|
||||
return ApiResponse<object>.ErrorResponse("You don't have permission to access this bucket", "You don't have permission to access this bucket", 403);
|
||||
_logger.LogInfo("Employee {EmployeeId} removed {Count} employees from bucket {BucketId}.", loggedInEmployee.Id, removedEmployeesCount, bucketId);
|
||||
}
|
||||
|
||||
_context.EmployeeBucketMappings.RemoveRange(employeeBuckets);
|
||||
return ApiResponse<object>.SuccessResponse(bucketVm, "Bucket details updated successfully", 200);
|
||||
}
|
||||
|
||||
public async Task<ApiResponse<object>> DeleteBucketAsync(Guid id, Guid tenantId, Employee loggedInEmployee)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Fetch the bucket in the main context to verify existence and tenant scope
|
||||
var bucket = await _context.Buckets.FirstOrDefaultAsync(b => b.Id == id && b.TenantId == tenantId);
|
||||
|
||||
if (bucket == null)
|
||||
{
|
||||
_logger.LogWarning("Employee {EmployeeId} attempted to delete bucket {BucketId}, bucket not found for tenant {TenantId}.",
|
||||
loggedInEmployee.Id, id, tenantId);
|
||||
|
||||
// Returning success response to maintain idempotency
|
||||
return ApiResponse<object>.SuccessResponse(new { }, "Bucket deleted successfully", 200);
|
||||
}
|
||||
|
||||
// Run parallel tasks to fetch related mappings using separate DbContext instances
|
||||
var employeeBucketMappingsTask = Task.Run(async () =>
|
||||
{
|
||||
using var context = _dbContextFactory.CreateDbContext();
|
||||
return await context.EmployeeBucketMappings
|
||||
.Where(eb => eb.BucketId == bucket.Id)
|
||||
.ToListAsync();
|
||||
});
|
||||
|
||||
var contactBucketMappingsTask = Task.Run(async () =>
|
||||
{
|
||||
using var context = _dbContextFactory.CreateDbContext();
|
||||
return await context.ContactBucketMappings
|
||||
.Where(cb => cb.BucketId == bucket.Id)
|
||||
.ToListAsync();
|
||||
});
|
||||
|
||||
// Await both tasks concurrently
|
||||
await Task.WhenAll(employeeBucketMappingsTask, contactBucketMappingsTask);
|
||||
|
||||
var employeeBucketMappings = employeeBucketMappingsTask.Result;
|
||||
var contactBucketMappings = contactBucketMappingsTask.Result;
|
||||
|
||||
// Check if bucket has any contacts mapped - cannot delete in this state
|
||||
if (contactBucketMappings.Any())
|
||||
{
|
||||
_logger.LogInfo("Employee {EmployeeId} attempted to delete bucket {BucketId} but bucket contains contacts, deletion blocked.",
|
||||
loggedInEmployee.Id, bucket.Id);
|
||||
|
||||
return ApiResponse<object>.ErrorResponse("This bucket cannot be deleted because it contains contacts.",
|
||||
"This bucket cannot be deleted", 400);
|
||||
}
|
||||
|
||||
// Check permissions of the logged-in employee
|
||||
var (hasAdminPermission, hasManagerPermission, hasUserPermission) = await CheckPermissionsAsync(loggedInEmployee.Id);
|
||||
|
||||
var accessibleBucket = (Bucket?)null;
|
||||
|
||||
// Get bucket IDs for which the employee has mapping association
|
||||
var employeeBucketIds = employeeBucketMappings
|
||||
.Where(eb => eb.EmployeeId == loggedInEmployee.Id)
|
||||
.Select(eb => eb.BucketId)
|
||||
.ToList();
|
||||
|
||||
// Determine if employee has permission to delete this bucket
|
||||
if (hasAdminPermission)
|
||||
{
|
||||
accessibleBucket = bucket;
|
||||
}
|
||||
else if (hasManagerPermission && employeeBucketIds.Contains(bucket.Id))
|
||||
{
|
||||
accessibleBucket = bucket;
|
||||
}
|
||||
else if (hasUserPermission && bucket.CreatedByID == loggedInEmployee.Id)
|
||||
{
|
||||
accessibleBucket = bucket;
|
||||
}
|
||||
|
||||
if (accessibleBucket == null)
|
||||
{
|
||||
_logger.LogWarning("Employee {EmployeeId} attempted to delete bucket {BucketId} without sufficient permissions.",
|
||||
loggedInEmployee.Id, bucket.Id);
|
||||
|
||||
return ApiResponse<object>.ErrorResponse("You don't have permission to access this bucket.",
|
||||
"Permission denied", 403);
|
||||
}
|
||||
|
||||
// Remove related employee bucket mappings
|
||||
_context.EmployeeBucketMappings.RemoveRange(employeeBucketMappings);
|
||||
// Remove the bucket itself
|
||||
_context.Buckets.Remove(bucket);
|
||||
// Log deletion action
|
||||
_context.DirectoryUpdateLogs.Add(new DirectoryUpdateLog
|
||||
{
|
||||
RefereanceId = id,
|
||||
UpdatedById = LoggedInEmployee.Id,
|
||||
RefereanceId = bucket.Id,
|
||||
UpdatedById = loggedInEmployee.Id,
|
||||
UpdateAt = DateTime.UtcNow
|
||||
});
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
_logger.LogInfo("Employee {EmployeeId} deleted bucket {BucketId} and related entries", LoggedInEmployee.Id, id);
|
||||
|
||||
_logger.LogInfo("Employee {EmployeeId} deleted bucket {BucketId} along with related employee bucket mappings.",
|
||||
loggedInEmployee.Id, bucket.Id);
|
||||
|
||||
return ApiResponse<object>.SuccessResponse(new { }, "Bucket deleted successfully", 200);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log the exception with error level
|
||||
_logger.LogError(ex, "An error occurred while employee {EmployeeId} attempted to delete bucket {BucketId}.",
|
||||
loggedInEmployee.Id, id);
|
||||
|
||||
_logger.LogWarning("Employee {EmployeeId} tries to delete bucket {BucketId} but not found in database", LoggedInEmployee.Id, id);
|
||||
return ApiResponse<object>.SuccessResponse(new { }, "Bucket deleted successfully", 200);
|
||||
return ApiResponse<object>.ErrorResponse("An unexpected error occurred while deleting the bucket.",
|
||||
"Internal Server Error", 500);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -26,7 +26,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
|
||||
Task<ApiResponse<object>> GetBucketListAsync(Guid tenantId, Employee loggedInEmployee);
|
||||
Task<ApiResponse<object>> CreateBucketAsync(CreateBucketDto bucketDto, Guid tenantId, Employee loggedInEmployee);
|
||||
Task<ApiResponse<object>> UpdateBucketAsync(Guid id, UpdateBucketDto bucketDto, Guid tenantId, Employee loggedInEmployee);
|
||||
Task<ApiResponse<object>> AssignBucket(Guid bucketId, List<AssignBucketDto> assignBuckets);
|
||||
Task<ApiResponse<object>> DeleteBucket(Guid id);
|
||||
Task<ApiResponse<object>> AssignBucketAsync(Guid bucketId, List<AssignBucketDto> assignBuckets, Guid tenantId, Employee loggedInEmployee);
|
||||
Task<ApiResponse<object>> DeleteBucketAsync(Guid id, Guid tenantId, Employee loggedInEmployee);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user