using MS.Microservice.Core.Extension; using MS.Microservice.Core.Domain.Repository.Extensions; using MS.Microservice.Core.Dto; using MS.Microservice.Core.Functional; using MS.Microservice.Domain.Aggregates.IdentityModel; using MS.Microservice.Domain.Aggregates.IdentityModel.Repository; using MS.Microservice.Domain.Consts; using MS.Microservice.Domain.Exception; using MS.Microservice.Domain.Services.Interfaces; namespace MS.Microservice.Domain.Services { public class UserDomainService : IUserDomainService { private readonly IUserRepository _userRepository; public UserDomainService(IUserRepository userRepository) { _userRepository = userRepository; } public async Task> CreateUserEitherAsync(User user, CancellationToken cancellationToken = default) { var existUser = await _userRepository.FindOptionAsync(p => p.Account == user.Account, cancellationToken); return await existUser .Where(existingUser => !existingUser.IsTransient()) .MatchAsync( none: async () => { if (!user.HasModernPasswordHash()) { return F.Left(Error.Validation( "用户密码尚未使用版本化哈希", ["创建用户前必须通过 IPasswordHasher 生成密码哈希。"])); } var insertResult = await _userRepository.InsertEitherAsync(user, cancellationToken); return await insertResult.BindAsync(async _ => { var saveResult = await _userRepository.UnitOfWork.SaveChangesEitherAsync(cancellationToken); return saveResult .Where( predicate: changed => changed > 0, leftFactory: _ => Error.Unexpected("用户创建失败", ["SaveChangesAsync returned 0."])) .Map(_ => true); }); }, some: _ => Task.FromResult((Either)F.Left(Error.Conflict(ExceptionConsts.UserExisted, [$"Account={user.Account}"])))); } public async Task> CreateUserResultAsync(User user, CancellationToken cancellationToken = default) { var either = await CreateUserEitherAsync(user, cancellationToken); return either.Match( left: error => Result.Fail(new DomainException(error.ToDisplayMessage())), right: Result.Success); } public async Task CreateUserAsync(User user, CancellationToken cancellationToken = default) { var result = await CreateUserResultAsync(user, cancellationToken); return result.Match( onSuccess: success => success, onFailure: exception => throw exception); } public async Task DeleteUserAsync(int userId, CancellationToken cancellationToken = default) { var userInfo = await _userRepository.GetAsync(userId, cancellationToken); if (userInfo == null || userInfo.IsTransient()) { return true; } userInfo.Delete(); await _userRepository.UpdateAsync(userInfo, cancellationToken); return await _userRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken); } public async Task> GetAllRolesAsync(CancellationToken cancellationToken = default) { var roles = await _userRepository.GetAllRoleAsync(cancellationToken); return roles; } public async Task GetUserAsync(int userId, CancellationToken cancellationToken = default) { var existUser = await _userRepository.GetAsync(userId, cancellationToken); return existUser; } public async Task FindAsync(string account, CancellationToken cancellationToken = default) { return await _userRepository.FindAsync(u => u.Account == account, cancellationToken); } public async Task FindFzAccountAsync(string fzAccount, CancellationToken cancellationToken = default) { return await _userRepository.FindAsync(u => u.FzAccount == fzAccount, cancellationToken); } public async Task UpdatePasswordHashAsync( User user, string passwordHash, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(user); user.SetPasswordHash(passwordHash); await _userRepository.UpdateAsync(user, cancellationToken); return await _userRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken); } public async Task UpdateUserAsync(User user, CancellationToken cancellationToken = default) { var existUser = await _userRepository.FindAsync(p => p.Account == user.Account, cancellationToken); if (existUser == null || existUser.IsTransient()) { throw new DomainException(ExceptionConsts.UserNotExisted); } if (existUser.Telephone != user.Telephone) { var existPhoneUser = await _userRepository.FindAsync(p => p.Telephone == user.Telephone && p.Id != user.Id, cancellationToken); if (existPhoneUser != null && !existPhoneUser.IsTransient()) { throw new DomainException(ExceptionConsts.UserExisted); } } existUser.Update(user.Name, user.Telephone, user.Email, user.Password, user.Salt); existUser.Roles.RemoveAll(r => !user.Roles.Contains(r)); existUser.AddRoles(user.Roles); await _userRepository.UpdateAsync(existUser, cancellationToken); return await _userRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken); } } }