diff --git a/src/Tgstation.Server.Host/Authority/Core/AuthorityBase.cs b/src/Tgstation.Server.Host/Authority/Core/AuthorityBase.cs
index eff31f3c41..898c701eb8 100644
--- a/src/Tgstation.Server.Host/Authority/Core/AuthorityBase.cs
+++ b/src/Tgstation.Server.Host/Authority/Core/AuthorityBase.cs
@@ -7,6 +7,7 @@ using Octokit;
using Tgstation.Server.Api.Models;
using Tgstation.Server.Api.Models.Response;
+using Tgstation.Server.Host.Database;
using Tgstation.Server.Host.Security;
namespace Tgstation.Server.Host.Authority.Core
@@ -21,6 +22,11 @@ namespace Tgstation.Server.Host.Authority.Core
///
protected IAuthenticationContext AuthenticationContext { get; }
+ ///
+ /// Gets the for the .
+ ///
+ protected IDatabaseContext DatabaseContext { get; }
+
///
/// Gets the for the .
///
@@ -71,12 +77,15 @@ namespace Tgstation.Server.Host.Authority.Core
/// Initializes a new instance of the class.
///
/// The value of .
+ /// The value of .
/// The value of .
protected AuthorityBase(
IAuthenticationContext authenticationContext,
+ IDatabaseContext databaseContext,
ILogger logger)
{
AuthenticationContext = authenticationContext ?? throw new ArgumentNullException(nameof(authenticationContext));
+ DatabaseContext = databaseContext ?? throw new ArgumentNullException(nameof(databaseContext));
Logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
diff --git a/src/Tgstation.Server.Host/Authority/IUserGroupAuthority.cs b/src/Tgstation.Server.Host/Authority/IUserGroupAuthority.cs
index 3afd0c5777..cd4845a5e5 100644
--- a/src/Tgstation.Server.Host/Authority/IUserGroupAuthority.cs
+++ b/src/Tgstation.Server.Host/Authority/IUserGroupAuthority.cs
@@ -1,4 +1,5 @@
-using System.Threading;
+using System.Linq;
+using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Api.Rights;
@@ -13,6 +14,12 @@ namespace Tgstation.Server.Host.Authority
///
public interface IUserGroupAuthority : IAuthority
{
+ ///
+ /// Gets the current .
+ ///
+ /// A resulting in a .
+ ValueTask> Read();
+
///
/// Gets the with a given .
///
@@ -21,5 +28,12 @@ namespace Tgstation.Server.Host.Authority
/// A resulting in a .
[TgsAuthorize(AdministrationRights.ReadUsers)]
public ValueTask> GetId(long id, CancellationToken cancellationToken);
+
+ ///
+ /// Gets all registered s.
+ ///
+ /// A of s.
+ [TgsAuthorize(AdministrationRights.ReadUsers)]
+ IQueryable Queryable();
}
}
diff --git a/src/Tgstation.Server.Host/Authority/LoginAuthority.cs b/src/Tgstation.Server.Host/Authority/LoginAuthority.cs
index d32e066478..3ed1e1315d 100644
--- a/src/Tgstation.Server.Host/Authority/LoginAuthority.cs
+++ b/src/Tgstation.Server.Host/Authority/LoginAuthority.cs
@@ -31,11 +31,6 @@ namespace Tgstation.Server.Host.Authority
///
readonly ISystemIdentityFactory systemIdentityFactory;
- ///
- /// The for the .
- ///
- readonly IDatabaseContext databaseContext;
-
///
/// The for the .
///
@@ -102,29 +97,31 @@ namespace Tgstation.Server.Host.Authority
/// Initializes a new instance of the class.
///
/// The to use.
+ /// The to use.
/// The to use.
/// The value of .
/// The value of .
- /// The value of .
/// The value of .
/// The value of .
/// The value of .
/// The value of .
public LoginAuthority(
IAuthenticationContext authenticationContext,
+ IDatabaseContext databaseContext,
ILogger logger,
IApiHeadersProvider apiHeadersProvider,
ISystemIdentityFactory systemIdentityFactory,
- IDatabaseContext databaseContext,
IOAuthProviders oAuthProviders,
ITokenFactory tokenFactory,
ICryptographySuite cryptographySuite,
IIdentityCache identityCache)
- : base(authenticationContext, logger)
+ : base(
+ authenticationContext,
+ databaseContext,
+ logger)
{
this.apiHeadersProvider = apiHeadersProvider ?? throw new ArgumentNullException(nameof(apiHeadersProvider));
this.systemIdentityFactory = systemIdentityFactory ?? throw new ArgumentNullException(nameof(systemIdentityFactory));
- this.databaseContext = databaseContext ?? throw new ArgumentNullException(nameof(databaseContext));
this.oAuthProviders = oAuthProviders ?? throw new ArgumentNullException(nameof(oAuthProviders));
this.tokenFactory = tokenFactory ?? throw new ArgumentNullException(nameof(tokenFactory));
this.cryptographySuite = cryptographySuite ?? throw new ArgumentNullException(nameof(cryptographySuite));
@@ -158,7 +155,7 @@ namespace Tgstation.Server.Host.Authority
using (systemIdentity)
{
// Get the user from the database
- IQueryable query = databaseContext.Users.AsQueryable();
+ IQueryable query = DatabaseContext.Users.AsQueryable();
if (oAuthLogin)
{
var oAuthProvider = headers.OAuthProvider!.Value;
@@ -228,9 +225,9 @@ namespace Tgstation.Server.Host.Authority
{
Id = user.Id,
};
- databaseContext.Users.Attach(updatedUser);
+ DatabaseContext.Users.Attach(updatedUser);
updatedUser.PasswordHash = user.PasswordHash;
- await databaseContext.Save(cancellationToken);
+ await DatabaseContext.Save(cancellationToken);
}
}
else
@@ -238,7 +235,7 @@ namespace Tgstation.Server.Host.Authority
var usernameMismatch = systemIdentity!.Username != user.Name;
if (isLikelyDbUser || usernameMismatch)
{
- databaseContext.Users.Attach(user);
+ DatabaseContext.Users.Attach(user);
if (isLikelyDbUser)
{
// cleanup from https://github.com/tgstation/tgstation-server/issues/1528
@@ -255,7 +252,7 @@ namespace Tgstation.Server.Host.Authority
user.CanonicalName = User.CanonicalizeName(user.Name);
}
- await databaseContext.Save(cancellationToken);
+ await DatabaseContext.Save(cancellationToken);
}
}
diff --git a/src/Tgstation.Server.Host/Authority/UserAuthority.cs b/src/Tgstation.Server.Host/Authority/UserAuthority.cs
index a46e244ce2..6cb8ba430d 100644
--- a/src/Tgstation.Server.Host/Authority/UserAuthority.cs
+++ b/src/Tgstation.Server.Host/Authority/UserAuthority.cs
@@ -20,11 +20,6 @@ namespace Tgstation.Server.Host.Authority
///
sealed class UserAuthority : AuthorityBase, IUserAuthority
{
- ///
- /// The for the .
- ///
- readonly IDatabaseContext databaseContext;
-
///
/// The for the .
///
@@ -88,20 +83,22 @@ namespace Tgstation.Server.Host.Authority
///
/// Initializes a new instance of the class.
///
+ /// The to use.
+ /// The to use.
/// The to use.
- /// The value of .
/// The value of .
/// The value of .
- /// The value of .
public UserAuthority(
IAuthenticationContext authenticationContext,
- ILogger logger,
IDatabaseContext databaseContext,
+ ILogger logger,
IUsersDataLoader usersDataLoader,
IOAuthConnectionsDataLoader oAuthConnectionsDataLoader)
- : base(authenticationContext, logger)
+ : base(
+ authenticationContext,
+ databaseContext,
+ logger)
{
- this.databaseContext = databaseContext ?? throw new ArgumentNullException(nameof(databaseContext));
this.usersDataLoader = usersDataLoader ?? throw new ArgumentNullException(nameof(usersDataLoader));
this.oAuthConnectionsDataLoader = oAuthConnectionsDataLoader ?? throw new ArgumentNullException(nameof(oAuthConnectionsDataLoader));
}
@@ -155,7 +152,7 @@ namespace Tgstation.Server.Host.Authority
IQueryable Queryable(bool includeJoins, bool allowSystemUser)
{
var tgsUserCanonicalName = User.CanonicalizeName(User.TgsSystemUserName);
- var queryable = databaseContext
+ var queryable = DatabaseContext
.Users
.AsQueryable();
diff --git a/src/Tgstation.Server.Host/Authority/UserGroupAuthority.cs b/src/Tgstation.Server.Host/Authority/UserGroupAuthority.cs
index c15b7c4c2e..b6268906fc 100644
--- a/src/Tgstation.Server.Host/Authority/UserGroupAuthority.cs
+++ b/src/Tgstation.Server.Host/Authority/UserGroupAuthority.cs
@@ -51,13 +51,18 @@ namespace Tgstation.Server.Host.Authority
/// Initializes a new instance of the class.
///
/// The to use.
+ /// The to use.
/// The to use.
/// The value of .
public UserGroupAuthority(
IAuthenticationContext authenticationContext,
+ IDatabaseContext databaseContext,
ILogger logger,
IUserGroupsDataLoader userGroupsDataLoader)
- : base(authenticationContext, logger)
+ : base(
+ authenticationContext,
+ databaseContext,
+ logger)
{
this.userGroupsDataLoader = userGroupsDataLoader ?? throw new ArgumentNullException(nameof(userGroupsDataLoader));
}
@@ -74,5 +79,21 @@ namespace Tgstation.Server.Host.Authority
return new AuthorityResponse(userGroup);
}
+
+ ///
+ public ValueTask> Read()
+ {
+ var group = AuthenticationContext.User!.Group;
+ if (group == null)
+ return ValueTask.FromResult(NotFound());
+
+ return ValueTask.FromResult(new AuthorityResponse(group));
+ }
+
+ ///
+ public IQueryable Queryable()
+ => DatabaseContext
+ .Groups
+ .AsQueryable();
}
}
diff --git a/src/Tgstation.Server.Host/GraphQL/Types/UserGroups.cs b/src/Tgstation.Server.Host/GraphQL/Types/UserGroups.cs
new file mode 100644
index 0000000000..9cf6a9a58b
--- /dev/null
+++ b/src/Tgstation.Server.Host/GraphQL/Types/UserGroups.cs
@@ -0,0 +1,65 @@
+using System;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+using HotChocolate;
+using HotChocolate.Data;
+using HotChocolate.Types;
+using HotChocolate.Types.Relay;
+
+using Tgstation.Server.Host.Authority;
+using Tgstation.Server.Host.Models.Transformers;
+using Tgstation.Server.Host.Security;
+
+namespace Tgstation.Server.Host.GraphQL.Types
+{
+ ///
+ /// Wrapper for accessing s.
+ ///
+ public sealed class UserGroups
+ {
+ ///
+ /// Gets the current .
+ ///
+ /// The .
+ /// A resulting in the current 's .
+ public ValueTask Current(
+ [Service] IGraphQLAuthorityInvoker userGroupAuthority)
+ {
+ ArgumentNullException.ThrowIfNull(userGroupAuthority);
+ return userGroupAuthority.InvokeTransformable(authority => authority.Read());
+ }
+
+ ///
+ /// Gets a by .
+ ///
+ /// The of the .
+ /// The .
+ /// The for the operation.
+ /// The represented by , if any.
+ [TgsGraphQLAuthorize(nameof(IUserGroupAuthority.GetId))]
+ public ValueTask ById(
+ [ID(nameof(UserGroup))] long id,
+ [Service] IGraphQLAuthorityInvoker userGroupAuthority,
+ CancellationToken cancellationToken)
+ => UserGroup.GetUserGroup(id, userGroupAuthority, cancellationToken);
+
+ ///
+ /// Queries all registered s.
+ ///
+ /// The .
+ /// A of all registered s.
+ [UsePaging]
+ [UseFiltering]
+ [UseSorting]
+ [TgsGraphQLAuthorize(nameof(IUserGroupAuthority.Queryable))]
+ public IQueryable? Queryable(
+ [Service] IGraphQLAuthorityInvoker userGroupAuthority)
+ {
+ ArgumentNullException.ThrowIfNull(userGroupAuthority);
+ var dtoQueryable = userGroupAuthority.InvokeTransformableQueryable(authority => authority.Queryable());
+ return dtoQueryable;
+ }
+ }
+}
diff --git a/src/Tgstation.Server.Host/GraphQL/Types/Users.cs b/src/Tgstation.Server.Host/GraphQL/Types/Users.cs
index db0a333f53..95d8173efd 100644
--- a/src/Tgstation.Server.Host/GraphQL/Types/Users.cs
+++ b/src/Tgstation.Server.Host/GraphQL/Types/Users.cs
@@ -21,6 +21,12 @@ namespace Tgstation.Server.Host.GraphQL.Types
///
public sealed class Users
{
+ ///
+ /// Gets the swarm's .
+ ///
+ /// A new .
+ public UserGroups Groups() => new();
+
///
/// Gets the current .
///
@@ -37,7 +43,7 @@ namespace Tgstation.Server.Host.GraphQL.Types
}
///
- /// Gets a user by .
+ /// Gets a by .
///
/// The of the .
/// The .
@@ -45,17 +51,17 @@ namespace Tgstation.Server.Host.GraphQL.Types
/// The represented by , if any.
[Error(typeof(ErrorMessageException))]
[TgsGraphQLAuthorize(nameof(IUserAuthority.GetId))]
- public async ValueTask ById(
+ public ValueTask ById(
[ID(nameof(User))] long id,
[Service] IGraphQLAuthorityInvoker userAuthority,
CancellationToken cancellationToken)
- => await User.GetUser(id, userAuthority, cancellationToken);
+ => User.GetUser(id, userAuthority, cancellationToken);
///
- /// Lists all registered s.
+ /// Queries all registered s.
///
/// The .
- /// A list of all registered s.
+ /// A of all registered s.
[UsePaging]
[UseFiltering]
[UseSorting]