Organization_Management #142
@ -125,38 +125,43 @@ namespace Marco.Pms.Services.Controllers
|
||||
public async Task<IActionResult> CreateOrganizationAsync([FromBody] CreateOrganizationDto model)
|
||||
{
|
||||
await using var _context = await _dbContextFactory.CreateDbContextAsync();
|
||||
using var scope = _serviceScope.CreateScope();
|
||||
using var scope = _serviceScope.CreateScope(); // Create scope for scoped services
|
||||
await using var transaction = await _context.Database.BeginTransactionAsync();
|
||||
|
||||
try
|
||||
{
|
||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
|
||||
// Concurrent permission check and organization existence check
|
||||
var hasPermissionTask = Task.Run(async () =>
|
||||
{
|
||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||
return await permissionService.HasPermission(PermissionsMaster.AddOrganization, loggedInEmployee.Id);
|
||||
});
|
||||
|
||||
var IsPrimaryOrganizationTask = Task.Run(async () =>
|
||||
var isPrimaryOrganizationTask = Task.Run(async () =>
|
||||
{
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.Tenants.AnyAsync(t => t.OrganizationId == loggedInEmployee.OrganizationId);
|
||||
});
|
||||
|
||||
await Task.WhenAll(hasPermissionTask, IsPrimaryOrganizationTask);
|
||||
await Task.WhenAll(hasPermissionTask, isPrimaryOrganizationTask);
|
||||
|
||||
var hasPermission = hasPermissionTask.Result;
|
||||
var IsPrimaryOrganization = IsPrimaryOrganizationTask.Result;
|
||||
bool hasPermission = hasPermissionTask.Result;
|
||||
bool isPrimaryOrganization = isPrimaryOrganizationTask.Result;
|
||||
|
||||
if (!hasPermission && !IsPrimaryOrganization)
|
||||
// Check user access permission
|
||||
if (!hasPermission && !isPrimaryOrganization)
|
||||
{
|
||||
return StatusCode(403, ApiResponse<object>.ErrorResponse("Access Denied", "You do not have permission to create new service provider.", 403));
|
||||
_logger.LogWarning("User {EmployeeId} attempted to create a new organization without permission", loggedInEmployee.Id);
|
||||
return StatusCode(403, ApiResponse<object>.ErrorResponse("Access Denied", "You do not have permission to create new organization.", 403));
|
||||
}
|
||||
|
||||
// Get last SPRID and increment for new organization
|
||||
var lastOrganization = await _context.Organizations.OrderByDescending(sp => sp.SPRID).FirstOrDefaultAsync();
|
||||
double lastSPRID = lastOrganization?.SPRID ?? 5400;
|
||||
|
||||
var lastSPRID = lastOrganization != null ? lastOrganization.SPRID : 5400;
|
||||
|
||||
// Map DTO to entity and set defaults
|
||||
Organization organization = _mapper.Map<Organization>(model);
|
||||
organization.SPRID = lastSPRID + 1;
|
||||
organization.CreatedAt = DateTime.UtcNow;
|
||||
@ -165,8 +170,19 @@ namespace Marco.Pms.Services.Controllers
|
||||
|
||||
_context.Organizations.Add(organization);
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
// Create mapping for organization tenant
|
||||
var newOrganizationTenantMapping = new TenantOrgMapping
|
||||
{
|
||||
OrganizationId = organization.Id,
|
||||
SPRID = organization.SPRID,
|
||||
AssignedDate = DateTime.UtcNow,
|
||||
IsActive = true,
|
||||
AssignedById = loggedInEmployee.Id,
|
||||
TenantId = tenantId
|
||||
};
|
||||
_context.TenantOrgMappings.Add(newOrganizationTenantMapping);
|
||||
|
||||
// Prepare user creation for identity
|
||||
var user = new ApplicationUser
|
||||
{
|
||||
UserName = model.Email,
|
||||
@ -174,25 +190,29 @@ namespace Marco.Pms.Services.Controllers
|
||||
EmailConfirmed = true
|
||||
};
|
||||
|
||||
var _configuration = scope.ServiceProvider.GetRequiredService<IConfiguration>();
|
||||
var _emailSender = scope.ServiceProvider.GetRequiredService<IEmailSender>();
|
||||
var _userManager = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
|
||||
var configuration = scope.ServiceProvider.GetRequiredService<IConfiguration>();
|
||||
var emailSender = scope.ServiceProvider.GetRequiredService<IEmailSender>();
|
||||
var userManager = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
|
||||
|
||||
// Create Identity User
|
||||
var result = await _userManager.CreateAsync(user, "User@123");
|
||||
// Create Identity user with a default password (recommend to improve password handling)
|
||||
var result = await userManager.CreateAsync(user, "User@123");
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
_logger.LogWarning("Failed to create identity user for email {Email}: {Errors}", model.Email, result.Errors);
|
||||
return BadRequest(ApiResponse<object>.ErrorResponse("Failed to create user", result.Errors, 400));
|
||||
}
|
||||
|
||||
var jobRole = await _context.JobRoles.FirstOrDefaultAsync(jr => jr.Name == "Admin" && jr.TenantId == tenantId);
|
||||
if (jobRole == null)
|
||||
jobRole = await _context.JobRoles.FirstOrDefaultAsync(jr => jr.TenantId == tenantId);
|
||||
// Get admin job role or fallback role of the tenant
|
||||
var jobRole = await _context.JobRoles.FirstOrDefaultAsync(jr => jr.Name == "Admin" && jr.TenantId == tenantId)
|
||||
?? await _context.JobRoles.FirstOrDefaultAsync(jr => jr.TenantId == tenantId);
|
||||
|
||||
var fullName = model.ContactPerson.Split(" ");
|
||||
// Parse full name safely (consider improving split logic for multi-part names)
|
||||
var fullName = model.ContactPerson?.Split(' ', StringSplitOptions.RemoveEmptyEntries) ?? Array.Empty<string>();
|
||||
|
||||
Employee newEmployee = new Employee
|
||||
{
|
||||
FirstName = fullName[0],
|
||||
LastName = fullName[fullName.Length - 1],
|
||||
FirstName = fullName.Length > 0 ? fullName[0] : string.Empty,
|
||||
LastName = fullName.Length > 1 ? fullName[^1] : string.Empty,
|
||||
Email = model.Email,
|
||||
PermanentAddress = model.Address,
|
||||
CurrentAddress = model.Address,
|
||||
@ -202,54 +222,54 @@ namespace Marco.Pms.Services.Controllers
|
||||
IsActive = true,
|
||||
IsSystem = false,
|
||||
IsPrimary = true,
|
||||
OrganizationId = organization.Id
|
||||
OrganizationId = organization.Id,
|
||||
HasApplicationAccess = user.Id != null
|
||||
};
|
||||
|
||||
if (newEmployee.ApplicationUserId != null)
|
||||
{
|
||||
newEmployee.HasApplicationAccess = true;
|
||||
}
|
||||
_context.Employees.Add(newEmployee);
|
||||
|
||||
var serviceOrgMapping = model.ServiceIds.Select(s => new OrgServiceMapping
|
||||
// Map organization services
|
||||
var serviceOrgMappings = model.ServiceIds.Select(s => new OrgServiceMapping
|
||||
{
|
||||
ServiceId = s,
|
||||
OrganizationId = organization.Id
|
||||
}).ToList();
|
||||
|
||||
_context.OrgServiceMappings.AddRange(serviceOrgMapping);
|
||||
_context.OrgServiceMappings.AddRange(serviceOrgMappings);
|
||||
|
||||
// Persist all changes
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
await transaction.CommitAsync();
|
||||
|
||||
/* SEND USER REGISTRATION MAIL*/
|
||||
var token = await _userManager.GeneratePasswordResetTokenAsync(user);
|
||||
var resetLink = $"{_configuration["AppSettings:WebFrontendUrl"]}/reset-password?token={WebUtility.UrlEncode(token)}";
|
||||
if (newEmployee.FirstName != null)
|
||||
// Send user registration email with password reset link
|
||||
var token = await userManager.GeneratePasswordResetTokenAsync(user);
|
||||
var resetLink = $"{configuration["AppSettings:WebFrontendUrl"]}/reset-password?token={WebUtility.UrlEncode(token)}";
|
||||
if (!string.IsNullOrEmpty(newEmployee.FirstName))
|
||||
{
|
||||
await _emailSender.SendResetPasswordEmailOnRegister(user.Email, newEmployee.FirstName, resetLink);
|
||||
await emailSender.SendResetPasswordEmailOnRegister(user.Email, newEmployee.FirstName, resetLink);
|
||||
}
|
||||
|
||||
// Prepare response DTO
|
||||
var response = _mapper.Map<OrganizationVM>(organization);
|
||||
response.CreatedBy = _mapper.Map<BasicEmployeeVM>(loggedInEmployee);
|
||||
|
||||
return Ok(ApiResponse<object>.SuccessResponse(response, "Successfully created the service provider", 200));
|
||||
return Ok(ApiResponse<object>.SuccessResponse(response, "Successfully created the organization", 200));
|
||||
}
|
||||
catch (DbUpdateException dbEx)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
|
||||
_logger.LogError(dbEx, "Database Exception has been occured");
|
||||
return StatusCode(500, ApiResponse<object>.ErrorResponse("Internal error", "An database exception has been occured", 500));
|
||||
_logger.LogError(dbEx, "Database exception occurred while creating organization");
|
||||
return StatusCode(500, ApiResponse<object>.ErrorResponse("Internal error", "A database exception occurred", 500));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Exception has been occured");
|
||||
return StatusCode(500, ApiResponse<object>.ErrorResponse("Internal error", "An internal exception has been occured", 500));
|
||||
_logger.LogError(ex, "Unexpected exception occurred while creating organization");
|
||||
return StatusCode(500, ApiResponse<object>.ErrorResponse("Internal error", "An unexpected error occurred", 500));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[HttpPost("assign/project")]
|
||||
public async Task<IActionResult> AssignOrganizationToProjectAsync([FromBody] AssignOrganizationDto model)
|
||||
{
|
||||
@ -468,7 +488,7 @@ namespace Marco.Pms.Services.Controllers
|
||||
{
|
||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
|
||||
var serviceProviderTenantMappingTask = Task.Run(async () =>
|
||||
var organizationTenantMappingTask = Task.Run(async () =>
|
||||
{
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.TenantOrgMappings
|
||||
@ -482,9 +502,9 @@ namespace Marco.Pms.Services.Controllers
|
||||
.FirstOrDefaultAsync(o => o.Id == organizationId);
|
||||
});
|
||||
|
||||
await Task.WhenAll(serviceProviderTenantMappingTask, organizationTask);
|
||||
await Task.WhenAll(organizationTenantMappingTask, organizationTask);
|
||||
|
||||
var serviceProviderTenantMapping = serviceProviderTenantMappingTask.Result;
|
||||
var organizationTenantMapping = organizationTenantMappingTask.Result;
|
||||
var organization = organizationTask.Result;
|
||||
|
||||
if (organization == null)
|
||||
@ -492,9 +512,9 @@ namespace Marco.Pms.Services.Controllers
|
||||
return NotFound(ApiResponse<object>.ErrorResponse("Organization not found", "Organization not found in database", 404));
|
||||
}
|
||||
|
||||
if (serviceProviderTenantMapping == null)
|
||||
if (organizationTenantMapping == null)
|
||||
{
|
||||
var newServiceProviderTenantMapping = new TenantOrgMapping
|
||||
var newOrganizationTenantMapping = new TenantOrgMapping
|
||||
{
|
||||
OrganizationId = organization.Id,
|
||||
SPRID = organization.SPRID,
|
||||
@ -503,7 +523,7 @@ namespace Marco.Pms.Services.Controllers
|
||||
AssignedById = loggedInEmployee.Id,
|
||||
TenantId = tenantId
|
||||
};
|
||||
_context.TenantOrgMappings.Add(newServiceProviderTenantMapping);
|
||||
_context.TenantOrgMappings.Add(newOrganizationTenantMapping);
|
||||
await _context.SaveChangesAsync();
|
||||
await transaction.CommitAsync();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user