using DotBased.AspNet.Authority.Crypto; using DotBased.AspNet.Authority.Models; using DotBased.AspNet.Authority.Models.Authority; using DotBased.AspNet.Authority.Models.Validation; using DotBased.AspNet.Authority.Repositories; using DotBased.AspNet.Authority.Validators; using DotBased.Logging; namespace DotBased.AspNet.Authority.Managers; public class AuthorityUserManager where TUser : class { public AuthorityUserManager( AuthorityManager manager, IUserRepository userRepository, IPasswordHasher passwordHasher, IEnumerable>? passwordValidators, IEnumerable>? userValidators) { _logger = LogService.RegisterLogger>(); AuthorityManager = manager; UserRepository = userRepository; PasswordHasher = passwordHasher; if (passwordValidators != null) PasswordValidators = passwordValidators; if (userValidators != null) UserValidators = userValidators; } private readonly ILogger _logger; public AuthorityManager AuthorityManager { get; } public IUserRepository UserRepository { get; } public IPasswordHasher PasswordHasher { get; } public IEnumerable> PasswordValidators { get; } = []; public IEnumerable> UserValidators { get; } = []; public async Task ValidatePasswordAsync(TUser user, string password) { List errors = []; foreach (var validator in PasswordValidators) { var validatorResult = await validator.ValidatePasswordAsync(this, user, password); if (!validatorResult.Success) { errors.AddRange(validatorResult.Errors); } } return errors.Count > 0 ? ValidationResult.Failed(errors) : ValidationResult.Ok(); } public async Task ValidateUserAsync(TUser user) { List errors = []; foreach (var userValidator in UserValidators) { var validationResult = await userValidator.ValidateUserAsync(this, user); if (!validationResult.Success) { errors.AddRange(validationResult.Errors); } } return errors.Count > 0 ? ValidationResult.Failed(errors) : ValidationResult.Ok(); } public async Task> SearchUsersAsync(string query, int maxResults = 20, int offset = 0) { var searchResult = await UserRepository.GetUsersAsync(query, maxResults, offset); return searchResult.Item1 == null ? ListResult.Failed("No results!") : ListResult.Ok(searchResult.Item1, searchResult.Item2); } public async Task> UpdatePasswordAsync(TUser user, string password) { if (user is not AuthorityUserBase userBase) { return AuthorityResult.Error($"Given user is not of base type {nameof(AuthorityUserBase)}!"); } var passwordValidation = await ValidatePasswordAsync(user, password); if (!passwordValidation.Success) { List errors = []; errors.AddRange(passwordValidation.Errors); return AuthorityResult.Failed(errors, ResultFailReason.Validation); } userBase.PasswordHash = await PasswordHasher.HashPasswordAsync(password); userBase.SecurityVersion = AuthorityManager.GenerateVersion(); var updateResult = await UserRepository.UpdateUserAsync(user); return updateResult == null ? AuthorityResult.Error("Failed to save updates!") : AuthorityResult.Ok(updateResult); } public async Task> CreateUserAsync(TUser userModel, string password) { if (userModel is not AuthorityUserBase userBase) { return AuthorityResult.Error($"Given user is not of base type {nameof(AuthorityUserBase)}!"); } var userValidation = await ValidateUserAsync(userModel); var passwordValidation = await ValidatePasswordAsync(userModel, password); if (!userValidation.Success || !passwordValidation.Success) { List errors = []; errors.AddRange(userValidation.Errors); errors.AddRange(passwordValidation.Errors); return AuthorityResult.Failed(errors, ResultFailReason.Validation); } userBase.Version = AuthorityManager.GenerateVersion(); userBase.SecurityVersion = AuthorityManager.GenerateVersion(); var hashedPassword = await PasswordHasher.HashPasswordAsync(password); userBase.PasswordHash = hashedPassword; var userCreationResult = await UserRepository.CreateUserAsync(userModel); return userCreationResult != null ? AuthorityResult.Ok(userCreationResult) : AuthorityResult.Error("Failed to create user in repository!"); } public async Task> UpdateUserAsync(TUser model) { var updateResult = await UserRepository.UpdateUserAsync(model); return updateResult != null ? Result.Ok(updateResult) : Result.Failed("Failed to update user in repository!"); } public async Task DeleteUserAsync(TUser model) { var deleteResult = await UserRepository.DeleteUserAsync(model); return deleteResult; } }