Skip to content

Commit

Permalink
Add User subscriptions without event senders
Browse files Browse the repository at this point in the history
  • Loading branch information
Cyberboss committed Sep 24, 2024
1 parent 5faf6ee commit 1cb77e1
Showing 1 changed file with 93 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

using HotChocolate;
using HotChocolate.Execution;
using HotChocolate.Subscriptions;
using HotChocolate.Types;

using Tgstation.Server.Api.Rights;
using Tgstation.Server.Host.GraphQL.Types;
using Tgstation.Server.Host.Models.Transformers;
using Tgstation.Server.Host.Security;

namespace Tgstation.Server.Host.GraphQL.Subscriptions
{
/// <summary>
/// Subscriptions for <see cref="User"/>.
/// </summary>
[ExtendObjectType(typeof(Subscription))]
public sealed class UserSubscriptions
{
/// <summary>
/// The name of the topic for when any user is updated.
/// </summary>
const string UserUpdatedTopic = "UserUpdated";

/// <summary>
/// Get the names of the topics to send to when a <see cref="Models.User"/> is updated.
/// </summary>
/// <param name="userId">The <see cref="Api.Models.EntityId.Id"/> of the updated <see cref="Models.User"/>.</param>
/// <returns>An <see cref="IEnumerable{T}"/> of topic <see cref="string"/>s.</returns>
public static IEnumerable<string> UserUpdatedTopics(long userId)
{
yield return UserUpdatedTopic;
yield return SpecificUserUpdatedTopic(userId);
}

/// <summary>
/// The name of the topic for when a specific <see cref="Models.User"/> is updated.
/// </summary>
/// <param name="userId">The <see cref="Api.Models.EntityId.Id"/> of the updated <see cref="Models.User"/>.</param>
/// <returns>The topic <see cref="string"/>.</returns>
static string SpecificUserUpdatedTopic(long userId)
=> $"{UserUpdatedTopic}.{userId}";

/// <summary>
/// Receive an update for all <see cref="User"/> changes.
/// </summary>
/// <param name="user">The <see cref="Models.User"/> received from the publisher.</param>
/// <returns>The updated <see cref="User"/>.</returns>
[Subscribe]
[TgsGraphQLAuthorize(AdministrationRights.ReadUsers)]
public User UserUpdated([EventMessage] Models.User user)
{
ArgumentNullException.ThrowIfNull(user);

return ((Models.IApiTransformable<Models.User, User, UserGraphQLTransformer>)user).ToApi();
}

/// <summary>
/// <see cref="ISourceStream"/> for <see cref="CurrentUserUpdated(Models.User)"/>.
/// </summary>
/// <param name="receiver">The <see cref="ITopicEventReceiver"/>.</param>
/// <param name="authenticationContext">The <see cref="IAuthenticationContext"/> for the request.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="ValueTask{TResult}"/> resulting in a <see cref="ISourceStream{TMessage}"/> of the <see cref="SessionInvalidationReason"/> for the <paramref name="authenticationContext"/>.</returns>
public ValueTask<ISourceStream<Models.User>> CurrentUserUpdatedStream(
[Service] ITopicEventReceiver receiver,
[Service] IAuthenticationContext authenticationContext,
CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(receiver);
ArgumentNullException.ThrowIfNull(authenticationContext);
return receiver.SubscribeAsync<Models.User>(SpecificUserUpdatedTopic(Models.ModelExtensions.Require(authenticationContext.User, user => user.Id)), cancellationToken);
}

/// <summary>
/// Receive an update to the logged in <see cref="User"/> when it is changed.
/// </summary>
/// <param name="user">The <see cref="Models.User"/> received from the publisher.</param>
/// <returns>The updated <see cref="User"/>.</returns>
[Subscribe]
[TgsGraphQLAuthorize]
public User CurrentUserUpdated([EventMessage] Models.User user)
{
ArgumentNullException.ThrowIfNull(user);

return ((Models.IApiTransformable<Models.User, User, UserGraphQLTransformer>)user).ToApi();
}
}
}

0 comments on commit 1cb77e1

Please sign in to comment.