From f19f759752720da9a72ff50aea810bc057fdcf9f Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Tue, 12 Aug 2025 14:49:23 +0530 Subject: [PATCH] Added suspend tenant API --- .../Controllers/TenantController.cs | 93 ++++++++++++++++++- 1 file changed, 91 insertions(+), 2 deletions(-) diff --git a/Marco.Pms.Services/Controllers/TenantController.cs b/Marco.Pms.Services/Controllers/TenantController.cs index 983c4ca..620591b 100644 --- a/Marco.Pms.Services/Controllers/TenantController.cs +++ b/Marco.Pms.Services/Controllers/TenantController.cs @@ -713,9 +713,98 @@ namespace Marco.Pms.Services.Controllers // DELETE api//5 - [HttpDelete("{id}")] - public void Delete(int id) + [HttpDelete("delete/{id}")] + public async Task DeleteTenant(Guid id, [FromQuery] bool isActive = false) { + var action = isActive ? "activation" : "deactivation"; + _logger.LogInfo("Attempting tenant {Action} for ID: {TenantId}", action, id); + + // --- 1. Authentication & Authorization --- + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + if (loggedInEmployee == null) + { + _logger.LogWarning("Unauthorized tenant status update attempt. User is not logged in."); + return StatusCode(403, ApiResponse.ErrorResponse("Unauthorized", "User must be logged in to perform this action.", 403)); + } + + using var scope = _serviceScopeFactory.CreateScope(); + var _permissionService = scope.ServiceProvider.GetRequiredService(); + var _updateLogHelper = scope.ServiceProvider.GetRequiredService(); + + var hasPermission = await _permissionService.HasPermission(PermissionsMaster.ManageTenants, loggedInEmployee.Id); + if (!hasPermission && !(loggedInEmployee.ApplicationUser?.IsRootUser ?? false)) + { + _logger.LogWarning( + "Permission Denied: User {EmployeeId} attempted tenant status update for Tenant {TenantId} without 'ManageTenants' permission.", + loggedInEmployee.Id, id); + return StatusCode(403, ApiResponse.ErrorResponse("Access Denied", "User does not have the required permissions for this action.", 403)); + } + + // --- 2. Data Retrieval --- + await using var context = await _dbContextFactory.CreateDbContextAsync(); + var tenant = await context.Tenants + // Include related data only if it's required by the TenantVM mapping. + // If not, removing these improves performance. + .Include(t => t.Industry) + .Include(t => t.TenantStatus) + .FirstOrDefaultAsync(t => t.Id == id); + + if (tenant == null) + { + _logger.LogWarning("Tenant status update failed: Tenant with ID {TenantId} not found.", id); + return NotFound(ApiResponse.ErrorResponse("Not Found", $"Tenant with ID '{id}' was not found.", 404)); + } + + // --- 3. Logic & State Change --- + // Efficiency: If the state is already what is being requested, do nothing. + if (tenant.IsActive == isActive) + { + var currentStatus = isActive ? "already active" : "already inactive"; + _logger.LogInfo("No action needed. Tenant {TenantId} is {Status}.", tenant.Id, currentStatus); + var noChangeMessage = $"Tenant was {currentStatus}. No changes were made."; + return Ok(ApiResponse.SuccessResponse(_mapper.Map(tenant), noChangeMessage, 200)); + } + + // Capture the state *before* modification for the audit log. + var tenantOldStateBson = _updateLogHelper.EntityToBsonDocument(tenant); + tenant.IsActive = isActive; + + // --- 4. Database Persistence --- + try + { + await context.SaveChangesAsync(); + _logger.LogInfo("Successfully updated Tenant {TenantId} IsActive status to {IsActive}.", tenant.Id, isActive); + } + catch (DbUpdateException ex) // Be more specific with exceptions if possible. + { + _logger.LogError(ex, "Database error occurred while updating status for Tenant {TenantId}.", tenant.Id); + return StatusCode(500, ApiResponse.ErrorResponse("Database Error", "An error occurred while saving changes to the database.", 500)); + } + catch (Exception ex) + { + _logger.LogError(ex, "An unexpected error occurred while updating status for Tenant {TenantId}.", tenant.Id); + return StatusCode(500, ApiResponse.ErrorResponse("Server Error", "An unexpected error occurred.", 500)); + } + + // --- 5. Audit Logging --- + // This runs after the DB save is confirmed. + // Note: If this call fails, the audit log will be missing for a successful DB change. + // For critical systems, consider a more robust outbox pattern. + await _updateLogHelper.PushToUpdateLogsAsync(new UpdateLogsObject + { + EntityId = tenant.Id.ToString(), + UpdatedById = loggedInEmployee.Id.ToString(), + OldObject = tenantOldStateBson, + UpdatedAt = DateTime.UtcNow + }, "TenantModificationLog"); + _logger.LogInfo("Audit log created for status change of Tenant {TenantId} by User {EmployeeId}.", tenant.Id, loggedInEmployee.Id); + + + // --- 6. Prepare and Return Response --- + var responseData = _mapper.Map(tenant); + var successMessage = $"Tenant successfully {(isActive ? "activated" : "deactivated")}."; + + return Ok(ApiResponse.SuccessResponse(responseData, successMessage, 200)); }