using Fengling.Console.Models.Dtos; using Fengling.Console.Repositories; using Microsoft.AspNetCore.Identity; using System.Security.Claims; using Fengling.Console.Datas; using Fengling.Console.Models.Entities; using Fengling.Platform.Domain.AggregatesModel.TenantAggregate; namespace Fengling.Console.Services; public interface ITenantService { Task<(IEnumerable Items, int TotalCount)> GetTenantsAsync(int page, int pageSize, string? name = null, string? tenantCode = null, TenantStatus? status = null); Task GetTenantAsync(long id); Task> GetTenantUsersAsync(long tenantId); Task> GetTenantRolesAsync(long tenantId); Task GetTenantSettingsAsync(long id); Task UpdateTenantSettingsAsync(long id, TenantSettingsDto settings); Task CreateTenantAsync(CreateTenantDto dto); Task UpdateTenantAsync(long id, UpdateTenantDto dto); Task DeleteTenantAsync(long id); } public class TenantService( ITenantRepository repository, IUserRepository userRepository, IRoleRepository roleRepository, UserManager userManager, ApplicationDbContext context, IHttpContextAccessor httpContextAccessor) : ITenantService { public async Task<(IEnumerable Items, int TotalCount)> GetTenantsAsync (int page, int pageSize, string? name = null, string? tenantCode = null, TenantStatus? status = null) { var tenants = await repository.GetPagedAsync(page, pageSize, name, tenantCode, status); var totalCount = await repository.CountAsync(name, tenantCode, status); var tenantDtos = new List(); foreach (var tenant in tenants) { var userCount = await repository.GetUserCountAsync(tenant.Id); tenantDtos.Add(new TenantDto { Id = tenant.Id, TenantCode = tenant.TenantCode, Name = tenant.Name, ContactName = tenant.ContactName, ContactEmail = tenant.ContactEmail, ContactPhone = tenant.ContactPhone, MaxUsers = tenant.MaxUsers, UserCount = userCount, Status = tenant.Status, ExpiresAt = tenant.ExpiresAt, Description = tenant.Description, CreatedAt = tenant.CreatedAt }); } return (tenantDtos, totalCount); } public async Task GetTenantAsync(long id) { var tenant = await repository.GetByIdAsync(id); if (tenant == null) return null; return new TenantDto { Id = tenant.Id, TenantCode = tenant.TenantCode, Name = tenant.Name, ContactName = tenant.ContactName, ContactEmail = tenant.ContactEmail, ContactPhone = tenant.ContactPhone, MaxUsers = tenant.MaxUsers, UserCount = await repository.GetUserCountAsync(tenant.Id), Status = tenant.Status, ExpiresAt = tenant.ExpiresAt, Description = tenant.Description, CreatedAt = tenant.CreatedAt }; } public async Task> GetTenantUsersAsync(long tenantId) { var tenant = await repository.GetByIdAsync(tenantId); if (tenant == null) { throw new KeyNotFoundException($"Tenant with ID {tenantId} not found"); } var users = await userRepository.GetPagedAsync(1, int.MaxValue, null, null, tenantId.ToString()); var userDtos = new List(); foreach (var user in users) { var roles = await userManager.GetRolesAsync(user); userDtos.Add(new UserDto { Id = user.Id, UserName = user.UserName, Email = user.Email, RealName = user.RealName, TenantCode = user.TenantInfo.TenantCode, TenantName = user.TenantInfo.TenantName, Roles = roles.ToList(), EmailConfirmed = user.EmailConfirmed, IsActive = !user.LockoutEnabled || user.LockoutEnd == null || user.LockoutEnd < DateTimeOffset.UtcNow, CreatedAt = user.CreatedTime }); } return userDtos; } public async Task> GetTenantRolesAsync(long tenantId) { var tenant = await repository.GetByIdAsync(tenantId); if (tenant == null) { throw new KeyNotFoundException($"Tenant with ID {tenantId} not found"); } var roles = await roleRepository.GetPagedAsync(1, int.MaxValue, null, tenantId.ToString()); return roles.Select(r => new { id = r.Id, name = r.Name, displayName = r.DisplayName }); } public async Task GetTenantSettingsAsync(long id) { var tenant = await repository.GetByIdAsync(id); if (tenant == null) { throw new KeyNotFoundException($"Tenant with ID {id} not found"); } return new TenantSettingsDto { AllowRegistration = false, AllowedEmailDomains = "", DefaultRoleId = null, PasswordPolicy = new List { "requireNumber", "requireLowercase" }, MinPasswordLength = 8, SessionTimeout = 120 }; } public async Task UpdateTenantSettingsAsync(long id, TenantSettingsDto settings) { var tenant = await repository.GetByIdAsync(id); if (tenant == null) { throw new KeyNotFoundException($"Tenant with ID {id} not found"); } await CreateAuditLog("tenant", "update", "TenantSettings", tenant.Id, tenant.Name, null, System.Text.Json.JsonSerializer.Serialize(settings)); } public async Task CreateTenantAsync(CreateTenantDto dto) { var tenant = new Tenant(dto.TenantCode, dto.Name, dto.ContactName, dto.ContactEmail, dto.ContactPhone,dto.MaxUsers,dto.Description,dto.ExpiresAt); await repository.AddAsync(tenant); await CreateAuditLog("tenant", "create", "Tenant", tenant.Id, tenant.Name, null, System.Text.Json.JsonSerializer.Serialize(dto)); return new TenantDto { Id = tenant.Id, TenantCode = tenant.TenantCode, Name = tenant.Name, ContactName = tenant.ContactName, ContactEmail = tenant.ContactEmail, ContactPhone = tenant.ContactPhone, MaxUsers = tenant.MaxUsers, UserCount = 0, Status = tenant.Status, ExpiresAt = tenant.ExpiresAt, Description = tenant.Description, CreatedAt = tenant.CreatedAt }; } public async Task UpdateTenantAsync(long id, UpdateTenantDto dto) { var tenant = await repository.GetByIdAsync(id); if (tenant == null) { throw new KeyNotFoundException($"Tenant with ID {id} not found"); } var oldValue = System.Text.Json.JsonSerializer.Serialize(tenant); tenant.UpdateInfo(dto.Name,dto.ContactName,dto.ContactEmail,dto.ContactPhone); await repository.UpdateAsync(tenant); await CreateAuditLog("tenant", "update", "Tenant", tenant.Id, tenant.Name, oldValue, System.Text.Json.JsonSerializer.Serialize(tenant)); return new TenantDto { Id = tenant.Id, TenantCode = tenant.TenantCode, Name = tenant.Name, ContactName = tenant.ContactName, ContactEmail = tenant.ContactEmail, ContactPhone = tenant.ContactPhone, MaxUsers = tenant.MaxUsers, UserCount = await repository.GetUserCountAsync(tenant.Id), Status = tenant.Status, ExpiresAt = tenant.ExpiresAt, Description = tenant.Description, CreatedAt = tenant.CreatedAt }; } public async Task DeleteTenantAsync(long id) { var tenant = await repository.GetByIdAsync(id); if (tenant == null) { throw new KeyNotFoundException($"Tenant with ID {id} not found"); } var oldValue = System.Text.Json.JsonSerializer.Serialize(tenant); var users = await userRepository.GetPagedAsync(1, int.MaxValue, null, null, id.ToString()); foreach (var user in users) { user.IsDeleted = true; user.UpdatedTime = DateTime.UtcNow; await context.SaveChangesAsync(); } tenant.Delete();; await repository.UpdateAsync(tenant); await CreateAuditLog("tenant", "delete", "Tenant", tenant.Id, tenant.Name, oldValue); } private async Task CreateAuditLog(string operation, string action, string targetType, long? targetId, string? targetName, string? oldValue = null, string? newValue = null) { var httpContext = httpContextAccessor.HttpContext; var userName = httpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier) ?? httpContext?.User?.Identity?.Name ?? "system"; var tenantId = httpContext?.User?.FindFirstValue("TenantId"); var log = new AuditLog { Operator = userName, TenantId = tenantId, Operation = operation, Action = action, TargetType = targetType, TargetId = targetId, TargetName = targetName, IpAddress = httpContext?.Connection?.RemoteIpAddress?.ToString() ?? "unknown", Status = "success", OldValue = oldValue, NewValue = newValue, CreatedAt = DateTime.UtcNow }; context.AuditLogs.Add(log); await context.SaveChangesAsync(); } }