fengling-console/Services/TenantService.cs
movingsam f5d6e0652c refactor: align TenantRepository with CleanDDD/NetCorePal规范
- remove duplicate ITenantRepository/TenantRepository from Console
- extend Platform ITenantRepository with GetByIdAsync, GetPagedAsync, CountAsync
- update Console services to use Platform.Infrastructure.Repositories
- fix nullable warnings (UserDto, OAuthClientService)
- fix YarpGateway Directory.Build.props duplicate import
- fix DynamicProxyConfigProvider CS8618 warning
2026-02-19 19:20:06 +08:00

277 lines
9.8 KiB
C#

using Fengling.Console.Models.Dtos;
using Fengling.Console.Repositories;
using Fengling.Platform.Infrastructure.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<TenantDto> Items, int TotalCount)> GetTenantsAsync(int page, int pageSize, string? name = null,
string? tenantCode = null, TenantStatus? status = null);
Task<TenantDto?> GetTenantAsync(long id);
Task<IEnumerable<UserDto>> GetTenantUsersAsync(long tenantId);
Task<IEnumerable<object>> GetTenantRolesAsync(long tenantId);
Task<TenantSettingsDto> GetTenantSettingsAsync(long id);
Task UpdateTenantSettingsAsync(long id, TenantSettingsDto settings);
Task<TenantDto> CreateTenantAsync(CreateTenantDto dto);
Task<TenantDto> UpdateTenantAsync(long id, UpdateTenantDto dto);
Task DeleteTenantAsync(long id);
}
public class TenantService(
ITenantRepository repository,
IUserRepository userRepository,
IRoleRepository roleRepository,
UserManager<ApplicationUser> userManager,
ApplicationDbContext context,
IHttpContextAccessor httpContextAccessor)
: ITenantService
{
public async Task<(IEnumerable<TenantDto> 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<TenantDto>();
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<TenantDto?> 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<IEnumerable<UserDto>> 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<UserDto>();
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<IEnumerable<object>> 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<TenantSettingsDto> 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<string> { "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<TenantDto> 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<TenantDto> 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();
}
}