fengling-console/Services/UserService.cs
movingsam fc8fcc7de2 refactor(console): remove Repository layer, use Manager pattern
- Remove Repositories folder (IUserRepository, UserRepository, IRoleRepository, RoleRepository)
- Remove Managers folder (old TenantManager)
- Remove Datas folder (old ApplicationDbContext)
- Remove Models/Entities folder (old domain entities)
- Remove EntityConfigurations folder
- Update Services to use UserManager/RoleManager/PlatformDbContext directly
- Update DTOs to use Platform's TenantStatus
2026-02-21 13:52:37 +08:00

285 lines
10 KiB
C#

using Fengling.Console.Models.Dtos;
using Fengling.Platform.Domain.AggregatesModel.UserAggregate;
using Fengling.Platform.Domain.AggregatesModel.RoleAggregate;
using Fengling.Platform.Domain.AggregatesModel.TenantAggregate;
using Fengling.Platform.Infrastructure;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using System.Security.Claims;
namespace Fengling.Console.Services;
public interface IUserService
{
Task<(IEnumerable<UserDto> Items, int TotalCount)> GetUsersAsync(int page, int pageSize, string? userName = null, string? email = null, string? tenantId = null);
Task<UserDto?> GetUserAsync(long id);
Task<UserDto> CreateUserAsync(CreateUserDto dto);
Task<UserDto> UpdateUserAsync(long id, UpdateUserDto dto);
Task ResetPasswordAsync(long id, ResetPasswordDto dto);
Task DeleteUserAsync(long id);
}
public class UserService(
ITenantManager tenantManager,
UserManager<ApplicationUser> userManager,
RoleManager<ApplicationRole> roleManager,
PlatformDbContext context,
IHttpContextAccessor httpContextAccessor)
: IUserService
{
public async Task<(IEnumerable<UserDto> Items, int TotalCount)> GetUsersAsync(int page, int pageSize, string? userName = null, string? email = null, string? tenantId = null)
{
var query = context.Users.AsQueryable();
if (!string.IsNullOrEmpty(userName))
{
query = query.Where(u => u.UserName != null && u.UserName.Contains(userName));
}
if (!string.IsNullOrEmpty(email))
{
query = query.Where(u => u.Email != null && u.Email.Contains(email));
}
if (!string.IsNullOrEmpty(tenantId))
{
query = query.Where(u => u.TenantInfo.TenantId.ToString().Contains(tenantId));
}
var totalCount = await query.CountAsync();
var users = await query
.OrderByDescending(u => u.CreatedTime)
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
var userDtos = new List<UserDto>();
foreach (var user in users)
{
var roles = await userManager.GetRolesAsync(user);
var tenant = user.TenantInfo.TenantId > 0 ? await tenantManager.FindByIdAsync(user.TenantInfo.TenantId) : null;
userDtos.Add(new UserDto
{
Id = user.Id,
UserName = user.UserName,
Email = user.Email,
RealName = user.RealName,
Phone = user.Phone,
TenantCode = user.TenantInfo.TenantId.ToString(),
TenantName = tenant?.Name ?? "",
Roles = roles.ToList(),
EmailConfirmed = user.EmailConfirmed,
IsActive = !user.LockoutEnabled || user.LockoutEnd == null || user.LockoutEnd < DateTimeOffset.UtcNow,
CreatedAt = user.CreatedTime
});
}
return (userDtos, totalCount);
}
public async Task<UserDto?> GetUserAsync(long id)
{
var user = await context.Users.FindAsync(id);
if (user == null) return null;
var roles = await userManager.GetRolesAsync(user);
var tenant = user.TenantInfo.TenantId > 0 ? await tenantManager.FindByIdAsync(user.TenantInfo.TenantId) : null;
return new UserDto
{
Id = user.Id,
UserName = user.UserName,
Email = user.Email,
RealName = user.RealName,
Phone = user.Phone,
TenantCode = user.TenantInfo.TenantId.ToString(),
TenantName = tenant?.Name ?? "",
Roles = roles.ToList(),
EmailConfirmed = user.EmailConfirmed,
IsActive = !user.LockoutEnabled || user.LockoutEnd == null || user.LockoutEnd < DateTimeOffset.UtcNow,
CreatedAt = user.CreatedTime
};
}
public async Task<UserDto> CreateUserAsync(CreateUserDto dto)
{
Tenant? tenant = null;
if (dto.TenantId.HasValue && dto.TenantId.Value > 0)
{
tenant = await tenantManager.FindByIdAsync(dto.TenantId.Value);
if (tenant == null)
{
throw new InvalidOperationException("Invalid tenant ID");
}
}
var tenantInfo = tenant != null
? new TenantInfo(tenant.Id, tenant.TenantCode, tenant.Name)
: new TenantInfo(0, "", "");
var user = new ApplicationUser
{
UserName = dto.UserName,
Email = dto.Email,
RealName = dto.RealName,
Phone = dto.Phone,
TenantInfo = tenantInfo,
EmailConfirmed = dto.EmailConfirmed,
CreatedTime = DateTime.UtcNow
};
var result = await userManager.CreateAsync(user, dto.Password);
if (!result.Succeeded)
{
throw new InvalidOperationException(string.Join(", ", result.Errors.Select(e => e.Description)));
}
if (dto.RoleIds != null && dto.RoleIds.Any())
{
foreach (var roleId in dto.RoleIds)
{
var role = await roleManager.FindByIdAsync(roleId.ToString());
if (role != null)
{
await userManager.AddToRoleAsync(user, role.Name!);
}
}
}
if (!dto.IsActive)
{
await userManager.SetLockoutEnabledAsync(user, true);
await userManager.SetLockoutEndDateAsync(user, DateTimeOffset.MaxValue);
}
await CreateAuditLog("user", "create", "User", user.Id, user.UserName, null, System.Text.Json.JsonSerializer.Serialize(dto));
var roles = await userManager.GetRolesAsync(user);
return new UserDto
{
Id = user.Id,
UserName = user.UserName,
Email = user.Email,
RealName = user.RealName,
Phone = user.Phone,
TenantCode = user.TenantInfo.TenantId.ToString(),
TenantName = tenant?.Name ?? "",
Roles = roles.ToList(),
EmailConfirmed = user.EmailConfirmed,
IsActive = !user.LockoutEnabled || user.LockoutEnd == null || user.LockoutEnd < DateTimeOffset.UtcNow,
CreatedAt = user.CreatedTime
};
}
public async Task<UserDto> UpdateUserAsync(long id, UpdateUserDto dto)
{
var user = await context.Users.FindAsync(id);
if (user == null)
{
throw new KeyNotFoundException($"User with ID {id} not found");
}
var oldValue = System.Text.Json.JsonSerializer.Serialize(user);
user.Email = dto.Email;
user.RealName = dto.RealName;
user.Phone = dto.Phone;
user.EmailConfirmed = dto.EmailConfirmed;
user.UpdatedTime = DateTime.UtcNow;
await userManager.UpdateAsync(user);
if (dto.IsActive)
{
await userManager.SetLockoutEnabledAsync(user, false);
await userManager.SetLockoutEndDateAsync(user, null);
}
else
{
await userManager.SetLockoutEnabledAsync(user, true);
await userManager.SetLockoutEndDateAsync(user, DateTimeOffset.MaxValue);
}
var tenant = user.TenantInfo.TenantId > 0 ? await tenantManager.FindByIdAsync(user.TenantInfo.TenantId) : null;
await CreateAuditLog("user", "update", "User", user.Id, user.UserName, oldValue, System.Text.Json.JsonSerializer.Serialize(user));
var roles = await userManager.GetRolesAsync(user);
return new UserDto
{
Id = user.Id,
UserName = user.UserName,
Email = user.Email,
RealName = user.RealName,
Phone = user.Phone,
TenantCode = user.TenantInfo.TenantId.ToString(),
TenantName = tenant?.Name ?? "",
Roles = roles.ToList(),
EmailConfirmed = user.EmailConfirmed,
IsActive = !user.LockoutEnabled || user.LockoutEnd == null || user.LockoutEnd < DateTimeOffset.UtcNow,
CreatedAt = user.CreatedTime
};
}
public async Task ResetPasswordAsync(long id, ResetPasswordDto dto)
{
var user = await userManager.FindByIdAsync(id.ToString());
if (user == null)
{
throw new KeyNotFoundException($"User with ID {id} not found");
}
var token = await userManager.GeneratePasswordResetTokenAsync(user);
var result = await userManager.ResetPasswordAsync(user, token, dto.NewPassword);
if (!result.Succeeded)
{
throw new InvalidOperationException(string.Join(", ", result.Errors.Select(e => e.Description)));
}
await CreateAuditLog("user", "reset_password", "User", user.Id, user.UserName);
}
public async Task DeleteUserAsync(long id)
{
var user = await context.Users.FindAsync(id);
if (user == null)
{
throw new KeyNotFoundException($"User with ID {id} not found");
}
var oldValue = System.Text.Json.JsonSerializer.Serialize(user);
user.IsDeleted = true;
user.UpdatedTime = DateTime.UtcNow;
await context.SaveChangesAsync();
await CreateAuditLog("user", "delete", "User", user.Id, user.UserName, 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 tenantIdClaim = httpContext?.User?.FindFirstValue("TenantId");
var log = new AuditLog
{
Operator = userName,
TenantId = tenantIdClaim,
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();
}
}