From 74fa26fe023f65ad160c82b74de4d82100afa486 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 10 Sep 2024 23:34:10 -0400 Subject: [PATCH] Implement baby's first pagination on `User`s --- .../Authority/IUserAuthority.cs | 7 ++- .../Authority/UserAuthority.cs | 43 +++++++++++++------ .../GraphQL/Types/Users.cs | 21 ++++++++- 3 files changed, 52 insertions(+), 19 deletions(-) diff --git a/src/Tgstation.Server.Host/Authority/IUserAuthority.cs b/src/Tgstation.Server.Host/Authority/IUserAuthority.cs index 29eebfab5b..0279483f5c 100644 --- a/src/Tgstation.Server.Host/Authority/IUserAuthority.cs +++ b/src/Tgstation.Server.Host/Authority/IUserAuthority.cs @@ -27,7 +27,7 @@ namespace Tgstation.Server.Host.Authority /// Gets the with a given . /// /// The of the . - /// If relevant entities should be loaded. + /// If related entities should be loaded. /// The for the operation. /// A resulting in a . [TgsAuthorize(AdministrationRights.ReadUsers)] @@ -36,10 +36,9 @@ namespace Tgstation.Server.Host.Authority /// /// Gets all registered s. /// - /// If relevant entities should be loaded. - /// The for the operation. + /// If related entities should be loaded. /// A resulting in a . [TgsAuthorize(AdministrationRights.ReadUsers)] - public ValueTask>> List(bool includeJoins, CancellationToken cancellationToken); + public ValueTask>> List(bool includeJoins); } } diff --git a/src/Tgstation.Server.Host/Authority/UserAuthority.cs b/src/Tgstation.Server.Host/Authority/UserAuthority.cs index a1d09a2afd..2d113a7abb 100644 --- a/src/Tgstation.Server.Host/Authority/UserAuthority.cs +++ b/src/Tgstation.Server.Host/Authority/UserAuthority.cs @@ -49,18 +49,7 @@ namespace Tgstation.Server.Host.Authority /// public async ValueTask> GetId(long id, bool includeJoins, CancellationToken cancellationToken) { - var queryable = databaseContext - .Users - .AsQueryable(); - - if (includeJoins) - queryable = queryable - .Where(x => x.Id == id) - .Include(x => x.CreatedBy) - .Include(x => x.OAuthConnections) - .Include(x => x.Group!) - .ThenInclude(x => x.PermissionSet) - .Include(x => x.PermissionSet); + var queryable = ListCore(includeJoins); var user = await queryable.FirstOrDefaultAsync( dbModel => dbModel.Id == id, @@ -75,9 +64,35 @@ namespace Tgstation.Server.Host.Authority } /// - public ValueTask>> List(bool includeJoins, CancellationToken cancellationToken) + public ValueTask>> List(bool includeJoins) { - throw new NotImplementedException(); + var systemUserCanonicalName = User.CanonicalizeName(User.TgsSystemUserName); + return ValueTask.FromResult( + new AuthorityResponse>( + ListCore(includeJoins) + .Where(x => x.CanonicalName != systemUserCanonicalName))); + } + + /// + /// Generates an for listing s. + /// + /// If related entities should be loaded. + /// A new of s. + private IQueryable ListCore(bool includeJoins) + { + var queryable = databaseContext + .Users + .AsQueryable(); + + if (includeJoins) + queryable = queryable + .Include(x => x.CreatedBy) + .Include(x => x.OAuthConnections) + .Include(x => x.Group!) + .ThenInclude(x => x.PermissionSet) + .Include(x => x.PermissionSet); + + return queryable; } } } diff --git a/src/Tgstation.Server.Host/GraphQL/Types/Users.cs b/src/Tgstation.Server.Host/GraphQL/Types/Users.cs index 30d683201c..9ff2e2b256 100644 --- a/src/Tgstation.Server.Host/GraphQL/Types/Users.cs +++ b/src/Tgstation.Server.Host/GraphQL/Types/Users.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -8,6 +9,7 @@ using HotChocolate.Types.Relay; using Tgstation.Server.Host.Authority; using Tgstation.Server.Host.Authority.Core; +using Tgstation.Server.Host.Models; using Tgstation.Server.Host.Security; #pragma warning disable CA1724 // conflict with GitLabApiClient.Models.Users. They can fuck off @@ -40,7 +42,7 @@ namespace Tgstation.Server.Host.GraphQL.Types /// The of the . /// The . /// The for the operation. - /// A resulting in a . + /// The represented by , if any. [Error(typeof(ErrorMessageException))] [TgsGraphQLAuthorize(nameof(IUserAuthority.GetId))] public async ValueTask ById( @@ -51,5 +53,22 @@ namespace Tgstation.Server.Host.GraphQL.Types ArgumentNullException.ThrowIfNull(userAuthority); return await userAuthority.InvokeTransformable(authority => authority.GetId(id, false, cancellationToken)); } + + /// + /// Lists all registered s. + /// + /// The . + /// A list of all registered s. + [UsePaging(IncludeTotalCount = true)] + [TgsGraphQLAuthorize(nameof(IUserAuthority.List))] + public async ValueTask> List( + [Service] IGraphQLAuthorityInvoker userAuthority) + { + ArgumentNullException.ThrowIfNull(userAuthority); + var dtoQueryable = await userAuthority.Invoke, IQueryable>(authority => authority.List(false)); + return dtoQueryable + .Cast>() + .Select(dto => dto.ToApi()); + } } }