From ba0de460686b40f4f119792ceea7dbfd0000f1da Mon Sep 17 00:00:00 2001 From: max Date: Fri, 11 Apr 2025 21:07:08 +0200 Subject: [PATCH] [REFACTOR] Refactored UserRepository to use new monads --- .../Repositories/RoleRepository.cs | 15 +- .../Repositories/UserRepository.cs | 257 +++++++----------- .../Managers/AuthorityRoleManager.cs | 21 +- .../Managers/AuthorityUserManager.cs | 45 ++- .../Monads/AuthorityResult.cs | 40 +++ .../Monads/ValidationResult.cs | 4 +- .../Repositories/IUserRepository.cs | 21 +- 7 files changed, 189 insertions(+), 214 deletions(-) create mode 100644 DotBased.AspNet.Authority/Monads/AuthorityResult.cs diff --git a/DotBased.AspNet.Authority.EFCore/Repositories/RoleRepository.cs b/DotBased.AspNet.Authority.EFCore/Repositories/RoleRepository.cs index 9da3084..c8ba830 100644 --- a/DotBased.AspNet.Authority.EFCore/Repositories/RoleRepository.cs +++ b/DotBased.AspNet.Authority.EFCore/Repositories/RoleRepository.cs @@ -77,11 +77,8 @@ public class RoleRepository(IDbContextFactory contextFactory, context.RoleLinks.RemoveRange(context.RoleLinks.Where(rl => roleIds.Contains(rl.RoleId))); var removedRoles = await context.SaveChangesAsync(cancellationToken); - if (removedRoles == roles.Count) - { - return true; - } - logger.LogError("Failed to remove all roles, {removedRoles}/{totalRoles} roles removed!", removedRoles, roles.Count); + if (removedRoles != 0) return true; + logger.LogError("Failed to remove roles"); return false; } @@ -116,12 +113,8 @@ public class RoleRepository(IDbContextFactory contextFactory, var roleIds = roles.Select(r => r.Id).ToList(); context.RoleLinks.RemoveRange(context.RoleLinks.Where(rg => rg.LinkId == linkId && roleIds.Contains(rg.RoleId))); var unlinkedRoles = await context.SaveChangesAsync(cancellationToken); - if (unlinkedRoles == roles.Count) - { - return true; - } - - logger.LogError("Failed to remove all linked roles, {unlinkedRoles}/{totalRoles} roles unlinked!", unlinkedRoles, roles.Count); + if (unlinkedRoles != 0) return true; + logger.LogError("Failed to remove linked roles"); return false; } diff --git a/DotBased.AspNet.Authority.EFCore/Repositories/UserRepository.cs b/DotBased.AspNet.Authority.EFCore/Repositories/UserRepository.cs index aefcd2b..c70fadc 100644 --- a/DotBased.AspNet.Authority.EFCore/Repositories/UserRepository.cs +++ b/DotBased.AspNet.Authority.EFCore/Repositories/UserRepository.cs @@ -1,216 +1,147 @@ +using DotBased.AspNet.Authority.Models; using DotBased.AspNet.Authority.Models.Authority; using DotBased.AspNet.Authority.Repositories; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; namespace DotBased.AspNet.Authority.EFCore.Repositories; -public class UserRepository(IDbContextFactory contextFactory) : RepositoryBase, IUserRepository +public class UserRepository(IDbContextFactory contextFactory, ILogger logger) : RepositoryBase, IUserRepository { - public async Task> GetAuthorityUsersAsync(int limit = 20, int offset = 0, string search = "", CancellationToken cancellationToken = default) + public async Task> GetAuthorityUsersAsync(int limit = 20, int offset = 0, string search = "", CancellationToken cancellationToken = default) { - try + await using var context = await contextFactory.CreateDbContextAsync(cancellationToken); + var query = context.Users.AsQueryable(); + if (!string.IsNullOrWhiteSpace(search)) { - await using var context = await contextFactory.CreateDbContextAsync(cancellationToken); - var query = context.Users.AsQueryable(); - if (!string.IsNullOrWhiteSpace(search)) - { - query = query.Where(u => - $"{u.Id} {u.Name} {u.UserName} {u.EmailAddress} {u.PhoneNumber}".Contains(search, - StringComparison.CurrentCultureIgnoreCase)); - } - var totalCount = query.Count(); - var selected = await query.OrderBy(u => u.UserName).Skip(offset).Take(limit).Select(u => new AuthorityUserItem() - { - Id = u.Id, - UserName = u.UserName, - EmailAddress = u.EmailAddress, - PhoneNumber = u.PhoneNumber - }).ToListAsync(cancellationToken: cancellationToken); - return ListResultOld.Ok(selected, totalCount, limit, offset); + query = query.Where(u => + $"{u.Id} {u.Name} {u.UserName} {u.EmailAddress} {u.PhoneNumber}".Contains(search, + StringComparison.CurrentCultureIgnoreCase)); } - catch (Exception e) + var totalCount = query.Count(); + var selected = await query.OrderBy(u => u.UserName).Skip(offset).Take(limit).Select(u => new AuthorityUserItem() { - return HandleExceptionListResult("Failed to get users.", e); - } + Id = u.Id, + UserName = u.UserName, + EmailAddress = u.EmailAddress, + PhoneNumber = u.PhoneNumber + }).ToListAsync(cancellationToken: cancellationToken); + return QueryItems.Create(selected, totalCount, limit, offset); } - public async Task> GetAuthorityUserByIdAsync(string id, CancellationToken cancellationToken = default) + public async Task GetAuthorityUserByIdAsync(Guid id, CancellationToken cancellationToken = default) { - try + await using var context = await contextFactory.CreateDbContextAsync(cancellationToken); + if (id == Guid.Empty) { - await using var context = await contextFactory.CreateDbContextAsync(cancellationToken); - if (!Guid.TryParse(id, out var guid)) - { - return ResultOld.Failed("Invalid id!"); - } + throw new Exception("Id is required!"); + } - var user = await context.Users.Where(u => u.Id == guid).Include(u => u.Attributes).FirstOrDefaultAsync(cancellationToken: cancellationToken); - return ResultOld.HandleResult(user, "User not found."); - } - catch (Exception e) - { - return HandleExceptionResult("Failed to get user.", e); - } + return await context.Users.Where(u => u.Id == id).Include(u => u.Attributes).FirstOrDefaultAsync(cancellationToken: cancellationToken); } - public async Task> CreateUserAsync(AuthorityUser user, CancellationToken cancellationToken = default) + public async Task CreateUserAsync(AuthorityUser user, CancellationToken cancellationToken = default) { - try + await using var context = await contextFactory.CreateDbContextAsync(cancellationToken); + if (user.Id == Guid.Empty) { - await using var context = await contextFactory.CreateDbContextAsync(cancellationToken); - if (user.Id == Guid.Empty) - { - return ResultOld.Failed("Id cannot be empty!"); - } - var entity = context.Users.Add(user); - var saveResult = await context.SaveChangesAsync(cancellationToken); - return saveResult <= 0 ? ResultOld.Failed("Failed to create user!") : ResultOld.Ok(entity.Entity); - } - catch (Exception e) - { - return HandleExceptionResult("Failed to create user.", e); + throw new Exception("User id is required!"); } + var entity = context.Users.Add(user); + var saveResult = await context.SaveChangesAsync(cancellationToken); + return saveResult != 0 ? entity.Entity : null; } - public async Task> UpdateUserAsync(AuthorityUser user, CancellationToken cancellationToken = default) + public async Task UpdateUserAsync(AuthorityUser user, CancellationToken cancellationToken = default) { - try + await using var context = await contextFactory.CreateDbContextAsync(cancellationToken); + var usr = await context.Users.FirstOrDefaultAsync(u => u.Id == user.Id, cancellationToken: cancellationToken); + if (usr == null) { - await using var context = await contextFactory.CreateDbContextAsync(cancellationToken); - var usr = await context.Users.FirstOrDefaultAsync(u => u.Id == user.Id, cancellationToken: cancellationToken); - if (usr == null) - { - return ResultOld.Failed("User not found!"); - } + throw new Exception("User not found!"); + } - if (usr.Version != user.Version || usr.SecurityVersion != user.SecurityVersion) - { - return ResultOld.Failed("Version validation failed!"); - } + if (usr.Version != user.Version || usr.SecurityVersion != user.SecurityVersion) + { + throw new Exception("User does not have the correct security version!"); + } - var entity = context.Users.Update(user); - var saveResult = await context.SaveChangesAsync(cancellationToken); - return saveResult <= 0 ? ResultOld.Failed("Failed to save updated user!") : ResultOld.Ok(entity.Entity); - } - catch (Exception e) - { - return HandleExceptionResult("Failed to update user!", e); - } + var entity = context.Users.Update(user); + var saveResult = await context.SaveChangesAsync(cancellationToken); + return saveResult != 0 ? entity.Entity : null; } - public async Task DeleteUserAsync(AuthorityUser user, CancellationToken cancellationToken = default) + public async Task DeleteUsersAsync(List users, CancellationToken cancellationToken = default) { - try - { - await using var context = await contextFactory.CreateDbContextAsync(cancellationToken); - var usr = await context.Users.FirstOrDefaultAsync(u => u.Id == user.Id, cancellationToken: cancellationToken); - if (usr == null) - { - return ResultOld.Failed("User not found!"); - } - context.Users.Remove(usr); - var saveResult = await context.SaveChangesAsync(cancellationToken); - return saveResult <= 0 ? ResultOld.Failed("Failed to delete user!") : ResultOld.Ok(); - } - catch (Exception e) - { - return HandleException("Failed to delete user!", e); - } + await using var context = await contextFactory.CreateDbContextAsync(cancellationToken); + var usrIds = users.Select(u => u.Id); + + context.Users.RemoveRange(users); + context.RoleLinks.RemoveRange(context.RoleLinks.Where(rl => usrIds.Contains(rl.LinkId))); + + var removedResult = await context.SaveChangesAsync(cancellationToken); + if (removedResult != 0) return true; + logger.LogError("Failed to delete users"); + return false; } - public async Task> GetUserByEmailAsync(string email, CancellationToken cancellationToken = default) + public async Task GetUserByEmailAsync(string email, CancellationToken cancellationToken = default) { - try - { - await using var context = await contextFactory.CreateDbContextAsync(cancellationToken); - var usr = await context.Users.Where(u => u.EmailAddress == email).Include(u => u.Attributes).FirstOrDefaultAsync(cancellationToken: cancellationToken); - return ResultOld.HandleResult(usr, "User not found by given email address."); - } - catch (Exception e) - { - return HandleExceptionResult("An error occured while getting the user.", e); - } + await using var context = await contextFactory.CreateDbContextAsync(cancellationToken); + return await context.Users.Where(u => u.EmailAddress == email).Include(u => u.Attributes).FirstOrDefaultAsync(cancellationToken: cancellationToken); } - public async Task SetVersionAsync(AuthorityUser user, long version, CancellationToken cancellationToken = default) + public async Task SetVersionAsync(AuthorityUser user, long version, CancellationToken cancellationToken = default) { - try + await using var context = await contextFactory.CreateDbContextAsync(cancellationToken); + var usr = await context.Users.FirstOrDefaultAsync(u => u.Id == user.Id, cancellationToken); + if (usr == null) { - await using var context = await contextFactory.CreateDbContextAsync(cancellationToken); - var usr = await context.Users.FirstOrDefaultAsync(u => u.Id == user.Id, cancellationToken); - if (usr == null) - { - return ResultOld.Failed("Failed to find user with given id!"); - } + throw new Exception("User not found!"); + } - if (usr.Version != user.Version) - { - return ResultOld.Failed("Stored user version doesn't match current user version!"); - } + if (usr.Version != user.Version) + { + throw new Exception("User does not have the correct security version!"); + } - usr.Version = version; - context.Users.Update(usr); - var saveResult = await context.SaveChangesAsync(cancellationToken); - return saveResult <= 0 ? ResultOld.Failed("Failed to update user!") : ResultOld.Ok(); - } - catch (Exception e) - { - return HandleException("An error occured while updating the version.", e); - } + usr.Version = version; + context.Users.Update(usr); + var saveResult = await context.SaveChangesAsync(cancellationToken); + return saveResult != 0; } - public async Task> GetVersionAsync(AuthorityUser user, CancellationToken cancellationToken = default) + public async Task GetVersionAsync(AuthorityUser user, CancellationToken cancellationToken = default) { - try - { - await using var context = await contextFactory.CreateDbContextAsync(cancellationToken); - var usrVersion = await context.Users.Where(u => u.Id == user.Id).Select(u => u.Version).FirstOrDefaultAsync(cancellationToken); - return ResultOld.HandleResult(usrVersion, "Failed to get user version!"); - } - catch (Exception e) - { - return HandleExceptionResult("An error occured while getting the user version.", e); - } + await using var context = await contextFactory.CreateDbContextAsync(cancellationToken); + var usrVersion = await context.Users.Where(u => u.Id == user.Id).Select(u => u.Version).FirstOrDefaultAsync(cancellationToken); + return usrVersion; } - public async Task SetSecurityVersionAsync(AuthorityUser user, long securityVersion, CancellationToken cancellationToken = default) + public async Task SetSecurityVersionAsync(AuthorityUser user, long securityVersion, CancellationToken cancellationToken = default) { - try + await using var context = await contextFactory.CreateDbContextAsync(cancellationToken); + var usr = await context.Users.FirstOrDefaultAsync(u => u.Id == user.Id, cancellationToken); + if (usr == null) { - await using var context = await contextFactory.CreateDbContextAsync(cancellationToken); - var usr = await context.Users.FirstOrDefaultAsync(u => u.Id == user.Id, cancellationToken); - if (usr == null) - { - return ResultOld.Failed("Failed to find user with given id!"); - } + throw new Exception("User not found!"); + } - if (usr.SecurityVersion != user.SecurityVersion) - { - return ResultOld.Failed("Stored user version doesn't match current user version!"); - } + if (usr.SecurityVersion != user.SecurityVersion) + { + throw new Exception("User does not have the correct security version!"); + } - usr.SecurityVersion = securityVersion; - context.Users.Update(usr); - var saveResult = await context.SaveChangesAsync(cancellationToken); - return saveResult <= 0 ? ResultOld.Failed("Failed to update user!") : ResultOld.Ok(); - } - catch (Exception e) - { - return HandleException("An error occured while updating the security version.", e); - } + usr.SecurityVersion = securityVersion; + context.Users.Update(usr); + var saveResult = await context.SaveChangesAsync(cancellationToken); + return saveResult != 0; } - public async Task> GetSecurityVersionAsync(AuthorityUser user, CancellationToken cancellationToken = default) + public async Task GetSecurityVersionAsync(AuthorityUser user, CancellationToken cancellationToken = default) { - try - { - await using var context = await contextFactory.CreateDbContextAsync(cancellationToken); - var usrVersion = await context.Users.Where(u => u.Id == user.Id).Select(u => u.SecurityVersion).FirstOrDefaultAsync(cancellationToken); - return ResultOld.HandleResult(usrVersion, "Failed to get user security version!"); - } - catch (Exception e) - { - return HandleExceptionResult("An error occured while getting the user security version.", e); - } + await using var context = await contextFactory.CreateDbContextAsync(cancellationToken); + var usrVersion = await context.Users.Where(u => u.Id == user.Id).Select(u => u.SecurityVersion).FirstOrDefaultAsync(cancellationToken); + return usrVersion; } } \ No newline at end of file diff --git a/DotBased.AspNet.Authority/Managers/AuthorityRoleManager.cs b/DotBased.AspNet.Authority/Managers/AuthorityRoleManager.cs index adb54b1..64e5f65 100755 --- a/DotBased.AspNet.Authority/Managers/AuthorityRoleManager.cs +++ b/DotBased.AspNet.Authority/Managers/AuthorityRoleManager.cs @@ -44,9 +44,9 @@ public partial class AuthorityManager public async Task AddRolesToUserAsync(List roles, AuthorityUser user, CancellationToken cancellationToken = default) { var usrValidation = await IsValidUserAsync(user, cancellationToken); - if (!usrValidation.Success) + if (!usrValidation.IsSuccess) { - return ResultError.Fail("Validation for user failed!"); + return usrValidation; } var linkedRoles = await RoleRepository.GetRolesFromLinkAsync(user.Id, roles, cancellationToken); @@ -65,9 +65,9 @@ public partial class AuthorityManager public async Task RemoveRolesFromUserAsync(List roles, AuthorityUser user, CancellationToken cancellationToken = default) { var usrValidation = await IsValidUserAsync(user, cancellationToken); - if (!usrValidation.Success) + if (!usrValidation.IsSuccess) { - return ResultError.Fail("Validation for user failed!"); + return usrValidation; } var linkedRoles = await RoleRepository.GetRolesFromLinkAsync(user.Id, roles, cancellationToken); @@ -95,20 +95,15 @@ public partial class AuthorityManager var linkResult = await RoleRepository.AddRolesLinkAsync(rolesToAdd, group.Id, cancellationToken); return linkResult ? Result.Success() : ResultError.Fail("Failed to add roles."); } - - /// - /// Get all roles (including group roles) that the user has. - /// - /// The user to get the roles from - /// - public async Task>> GetUserRolesAsync(AuthorityUser user, CancellationToken cancellationToken = default) + + public async Task>> GetAllUserRolesAsync(AuthorityUser user, CancellationToken cancellationToken = default) { try { var usrValidation = await IsValidUserAsync(user, cancellationToken); - if (!usrValidation.Success) + if (!usrValidation.IsSuccess) { - return ResultError.Fail("Invalid user"); + return usrValidation.Error ?? ResultError.Fail("User validation failed."); } var searchIds = new List { user.Id }; diff --git a/DotBased.AspNet.Authority/Managers/AuthorityUserManager.cs b/DotBased.AspNet.Authority/Managers/AuthorityUserManager.cs index 81a99e4..3a15a4c 100755 --- a/DotBased.AspNet.Authority/Managers/AuthorityUserManager.cs +++ b/DotBased.AspNet.Authority/Managers/AuthorityUserManager.cs @@ -1,7 +1,8 @@ using DotBased.AspNet.Authority.Models; using DotBased.AspNet.Authority.Models.Authority; using DotBased.AspNet.Authority.Models.Validation; -using ValidationResult = DotBased.AspNet.Authority.Monads.ValidationResult; +using DotBased.AspNet.Authority.Monads; +using DotBased.Monads; namespace DotBased.AspNet.Authority.Managers; @@ -35,28 +36,33 @@ public partial class AuthorityManager return errors.Count > 0 ? ValidationResult.Fail(errors) : ValidationResult.Success(); } - public async Task> SearchUsersAsync(string query, int maxResults = 20, int offset = 0, CancellationToken cancellationToken = default) + public async Task>> SearchUsersAsync(string query, int maxResults = 20, int offset = 0, CancellationToken cancellationToken = default) { var result = await UserRepository.GetAuthorityUsersAsync(maxResults, offset, query, cancellationToken); return result; } - public async Task> UpdatePasswordAsync(AuthorityUser user, string password, CancellationToken cancellationToken = default) + public async Task> UpdatePasswordAsync(AuthorityUser user, string password, CancellationToken cancellationToken = default) { var passwordValidation = await ValidatePasswordAsync(user, password); if (!passwordValidation.IsSuccess) { - return AuthorityResultOldOld.Failed(passwordValidation.ValidationErrors, ResultFailReason.Validation); + return passwordValidation.ValidationErrors.ToList(); } user.PasswordHash = await PasswordHasher.HashPasswordAsync(password); user.SecurityVersion = GenerateVersion(); var updateResult = await UserRepository.UpdateUserAsync(user, cancellationToken); - return AuthorityResultOldOld.FromResult(updateResult); + if (updateResult == null) + { + return ResultError.Fail("Failed to update user password."); + } + + return updateResult; } - public async Task> CreateUserAsync(AuthorityUser userModel, string password, CancellationToken cancellationToken = default) + public async Task> CreateUserAsync(AuthorityUser userModel, string password, CancellationToken cancellationToken = default) { var userValidation = await ValidateUserAsync(userModel); var passwordValidation = await ValidatePasswordAsync(userModel, password); @@ -65,7 +71,7 @@ public partial class AuthorityManager List errors = []; errors.AddRange(userValidation.ValidationErrors); errors.AddRange(passwordValidation.ValidationErrors); - return AuthorityResultOldOld.Failed(errors, ResultFailReason.Validation); + return errors; } userModel.Version = GenerateVersion(); @@ -74,25 +80,34 @@ public partial class AuthorityManager userModel.PasswordHash = hashedPassword; var userCreationResult = await UserRepository.CreateUserAsync(userModel, cancellationToken); - - return AuthorityResultOldOld.FromResult(userCreationResult); + if (userCreationResult == null) + { + return ResultError.Fail("Failed to create user."); + } + + return userCreationResult; } - public async Task> UpdateUserAsync(AuthorityUser model, CancellationToken cancellationToken = default) + public async Task> UpdateUserAsync(AuthorityUser model, CancellationToken cancellationToken = default) { var updateResult = await UserRepository.UpdateUserAsync(model, cancellationToken); + if (updateResult == null) + { + return ResultError.Fail("Failed to update user."); + } + return updateResult; } - public async Task DeleteUserAsync(AuthorityUser model, CancellationToken cancellationToken = default) + public async Task DeleteUserAsync(AuthorityUser model, CancellationToken cancellationToken = default) { - var deleteResult = await UserRepository.DeleteUserAsync(model, cancellationToken); - return deleteResult; + var deleteResult = await UserRepository.DeleteUsersAsync([model], cancellationToken); + return deleteResult ? Result.Success() : ResultError.Fail("Failed to delete user."); } - public async Task IsValidUserAsync(AuthorityUser user, CancellationToken cancellationToken = default) + public async Task IsValidUserAsync(AuthorityUser user, CancellationToken cancellationToken = default) { var usrResult = await UserRepository.GetVersionAsync(user, cancellationToken); - return usrResult; + return usrResult == 0 ? ResultError.Fail("Invalid user version detected.") : Result.Success(); } } \ No newline at end of file diff --git a/DotBased.AspNet.Authority/Monads/AuthorityResult.cs b/DotBased.AspNet.Authority/Monads/AuthorityResult.cs new file mode 100644 index 0000000..ee57341 --- /dev/null +++ b/DotBased.AspNet.Authority/Monads/AuthorityResult.cs @@ -0,0 +1,40 @@ +using DotBased.AspNet.Authority.Models.Validation; +using DotBased.Monads; + +namespace DotBased.AspNet.Authority.Monads; + +public class AuthorityResult : Result +{ + protected AuthorityResult(TResult result) : base(result) + { + } + + protected AuthorityResult(Exception exception) : base(exception) + { + } + + protected AuthorityResult(ResultError error) : base(error) + { + } + + protected AuthorityResult(List validationErrors) : base(ResultError.Fail("Validation failed!")) + { + _validationErrors = validationErrors; + } + + private readonly List _validationErrors = []; + public IReadOnlyList ValidationErrors => _validationErrors; + + public static implicit operator AuthorityResult(TResult result) => new(result); + public static implicit operator AuthorityResult(Exception exception) => new(exception); + public static implicit operator AuthorityResult(ResultError error) => new(error); + public static implicit operator AuthorityResult(List validationErrors) => new(validationErrors); + + public static AuthorityResult FromResult(Result result) + { + var authorityResult = result.Match>( + r => new AuthorityResult(r), + error => new AuthorityResult(error)); + return authorityResult; + } +} \ No newline at end of file diff --git a/DotBased.AspNet.Authority/Monads/ValidationResult.cs b/DotBased.AspNet.Authority/Monads/ValidationResult.cs index a07ff0c..3a9e679 100644 --- a/DotBased.AspNet.Authority/Monads/ValidationResult.cs +++ b/DotBased.AspNet.Authority/Monads/ValidationResult.cs @@ -32,10 +32,10 @@ public class ValidationResult : Result public static ValidationResult FromResult(Result result) { - var authorityResult = result.Match( + var validationResult = result.Match( () => new ValidationResult(), error => new ValidationResult(error)); - return authorityResult; + return validationResult; } public new static ValidationResult Success() => new(); diff --git a/DotBased.AspNet.Authority/Repositories/IUserRepository.cs b/DotBased.AspNet.Authority/Repositories/IUserRepository.cs index 97cc30c..809c02a 100755 --- a/DotBased.AspNet.Authority/Repositories/IUserRepository.cs +++ b/DotBased.AspNet.Authority/Repositories/IUserRepository.cs @@ -1,17 +1,18 @@ +using DotBased.AspNet.Authority.Models; using DotBased.AspNet.Authority.Models.Authority; namespace DotBased.AspNet.Authority.Repositories; public interface IUserRepository { - public Task> GetAuthorityUsersAsync(int limit = 20, int offset = 0, string search = "", CancellationToken cancellationToken = default); - public Task> GetAuthorityUserByIdAsync(string id, CancellationToken cancellationToken = default); - public Task> CreateUserAsync(AuthorityUser user, CancellationToken cancellationToken = default); - public Task> UpdateUserAsync(AuthorityUser user, CancellationToken cancellationToken = default); - public Task DeleteUserAsync(AuthorityUser user, CancellationToken cancellationToken = default); - public Task> GetUserByEmailAsync(string email, CancellationToken cancellationToken = default); - public Task SetVersionAsync(AuthorityUser user, long version, CancellationToken cancellationToken = default); - public Task> GetVersionAsync(AuthorityUser user, CancellationToken cancellationToken = default); - public Task SetSecurityVersionAsync(AuthorityUser user, long securityVersion, CancellationToken cancellationToken = default); - public Task> GetSecurityVersionAsync(AuthorityUser user, CancellationToken cancellationToken = default); + public Task> GetAuthorityUsersAsync(int limit = 20, int offset = 0, string search = "", CancellationToken cancellationToken = default); + public Task GetAuthorityUserByIdAsync(Guid id, CancellationToken cancellationToken = default); + public Task CreateUserAsync(AuthorityUser user, CancellationToken cancellationToken = default); + public Task UpdateUserAsync(AuthorityUser user, CancellationToken cancellationToken = default); + public Task DeleteUsersAsync(List users, CancellationToken cancellationToken = default); + public Task GetUserByEmailAsync(string email, CancellationToken cancellationToken = default); + public Task SetVersionAsync(AuthorityUser user, long version, CancellationToken cancellationToken = default); + public Task GetVersionAsync(AuthorityUser user, CancellationToken cancellationToken = default); + public Task SetSecurityVersionAsync(AuthorityUser user, long securityVersion, CancellationToken cancellationToken = default); + public Task GetSecurityVersionAsync(AuthorityUser user, CancellationToken cancellationToken = default); } \ No newline at end of file