From 8fa0de60944551a890d305f5fc244141eaaf7763 Mon Sep 17 00:00:00 2001 From: Veljko Tosic Date: Mon, 9 Mar 2026 23:06:27 +0100 Subject: [PATCH] Canceling join request now actually changes the status to cancelled so trying to join same RequestToJoin whiteboard with code manually doesnt fail due to status being Pending --- .../UserCanceledRequestToJoinMessage.cs | 6 +++ ...UserCanceledRequestToJoinMessageHandler.cs | 19 +++++++++ .../UserCanceledRequestToJoinCommand.cs | 5 +++ ...UserCanceledRequestToJoinCommandHandler.cs | 40 +++++++++++++++++++ dotnet/AipsRT/Hubs/WhiteboardHub.cs | 10 +++-- .../{GetUserService.cs => UserService.cs} | 5 ++- dotnet/AipsRT/Program.cs | 2 +- .../Services/Interfaces/IMessagingService.cs | 2 + dotnet/AipsRT/Services/MessagingService.cs | 8 ++++ .../Messages/MessageTypesProvider.cs | 4 +- front/src/stores/whiteboard.ts | 1 + 11 files changed, 94 insertions(+), 8 deletions(-) create mode 100644 dotnet/AipsCore/Application/Common/Message/UserCanceledRequestToJoin/UserCanceledRequestToJoinMessage.cs create mode 100644 dotnet/AipsCore/Application/Common/Message/UserCanceledRequestToJoin/UserCanceledRequestToJoinMessageHandler.cs create mode 100644 dotnet/AipsCore/Application/Models/Whiteboard/Command/UserCanceledRequestToJoin/UserCanceledRequestToJoinCommand.cs create mode 100644 dotnet/AipsCore/Application/Models/Whiteboard/Command/UserCanceledRequestToJoin/UserCanceledRequestToJoinCommandHandler.cs rename dotnet/AipsRT/Model/Users/{GetUserService.cs => UserService.cs} (77%) diff --git a/dotnet/AipsCore/Application/Common/Message/UserCanceledRequestToJoin/UserCanceledRequestToJoinMessage.cs b/dotnet/AipsCore/Application/Common/Message/UserCanceledRequestToJoin/UserCanceledRequestToJoinMessage.cs new file mode 100644 index 0000000..7ca3eb0 --- /dev/null +++ b/dotnet/AipsCore/Application/Common/Message/UserCanceledRequestToJoin/UserCanceledRequestToJoinMessage.cs @@ -0,0 +1,6 @@ +using AipsCore.Application.Abstract.MessageBroking; +using AipsCore.Application.Models.Whiteboard.Command.UserCanceledRequestToJoin; + +namespace AipsCore.Application.Common.Message.UserCanceledRequestToJoin; + +public record UserCanceledRequestToJoinMessage(UserCanceledRequestToJoinCommand Command): IMessage; \ No newline at end of file diff --git a/dotnet/AipsCore/Application/Common/Message/UserCanceledRequestToJoin/UserCanceledRequestToJoinMessageHandler.cs b/dotnet/AipsCore/Application/Common/Message/UserCanceledRequestToJoin/UserCanceledRequestToJoinMessageHandler.cs new file mode 100644 index 0000000..9a35815 --- /dev/null +++ b/dotnet/AipsCore/Application/Common/Message/UserCanceledRequestToJoin/UserCanceledRequestToJoinMessageHandler.cs @@ -0,0 +1,19 @@ +using AipsCore.Application.Abstract; +using AipsCore.Application.Abstract.MessageBroking; + +namespace AipsCore.Application.Common.Message.UserCanceledRequestToJoin; + +public class UserCanceledRequestToJoinMessageHandler : IMessageHandler +{ + private readonly IDispatcher _dispatcher; + + public UserCanceledRequestToJoinMessageHandler(IDispatcher dispatcher) + { + _dispatcher = dispatcher; + } + + public async Task Handle(UserCanceledRequestToJoinMessage message, CancellationToken cancellationToken) + { + await _dispatcher.Execute(message.Command, cancellationToken); + } +} \ No newline at end of file diff --git a/dotnet/AipsCore/Application/Models/Whiteboard/Command/UserCanceledRequestToJoin/UserCanceledRequestToJoinCommand.cs b/dotnet/AipsCore/Application/Models/Whiteboard/Command/UserCanceledRequestToJoin/UserCanceledRequestToJoinCommand.cs new file mode 100644 index 0000000..b169f89 --- /dev/null +++ b/dotnet/AipsCore/Application/Models/Whiteboard/Command/UserCanceledRequestToJoin/UserCanceledRequestToJoinCommand.cs @@ -0,0 +1,5 @@ +using AipsCore.Application.Abstract.Command; + +namespace AipsCore.Application.Models.Whiteboard.Command.UserCanceledRequestToJoin; + +public record UserCanceledRequestToJoinCommand(string WhiteboardId, string UserId): ICommand; \ No newline at end of file diff --git a/dotnet/AipsCore/Application/Models/Whiteboard/Command/UserCanceledRequestToJoin/UserCanceledRequestToJoinCommandHandler.cs b/dotnet/AipsCore/Application/Models/Whiteboard/Command/UserCanceledRequestToJoin/UserCanceledRequestToJoinCommandHandler.cs new file mode 100644 index 0000000..b307915 --- /dev/null +++ b/dotnet/AipsCore/Application/Models/Whiteboard/Command/UserCanceledRequestToJoin/UserCanceledRequestToJoinCommandHandler.cs @@ -0,0 +1,40 @@ +using AipsCore.Application.Abstract.Command; +using AipsCore.Domain.Abstract; +using AipsCore.Domain.Common.Validation; +using AipsCore.Domain.Models.User.ValueObjects; +using AipsCore.Domain.Models.Whiteboard.ValueObjects; +using AipsCore.Domain.Models.WhiteboardMembership.Enums; +using AipsCore.Domain.Models.WhiteboardMembership.External; +using AipsCore.Domain.Models.WhiteboardMembership.Validation; + +namespace AipsCore.Application.Models.Whiteboard.Command.UserCanceledRequestToJoin; + +public class CancelJoinRequestCommandHandler : ICommandHandler +{ + private readonly IWhiteboardMembershipRepository _whiteboardMembershipRepository; + private readonly IUnitOfWork _unitOfWork; + + public CancelJoinRequestCommandHandler(IWhiteboardMembershipRepository whiteboardMembershipRepository, IUnitOfWork unitOfWork) + { + _whiteboardMembershipRepository = whiteboardMembershipRepository; + _unitOfWork = unitOfWork; + } + + public async Task Handle(UserCanceledRequestToJoinCommand command, CancellationToken cancellationToken = default) + { + var whiteboardId = new WhiteboardId(command.WhiteboardId); + var userId = new UserId(command.UserId); + + var membership = await _whiteboardMembershipRepository.GetByWhiteboardAndUserAsync(whiteboardId, userId, cancellationToken); + + if (membership is null) + { + throw new ValidationException(WhiteboardMembershipErrors.NotFound(whiteboardId, userId)); + } + + membership.UpdateStatus(WhiteboardMembershipStatus.Cancelled); + + await _whiteboardMembershipRepository.SaveAsync(membership, cancellationToken); + await _unitOfWork.SaveChangesAsync(cancellationToken); + } +} \ No newline at end of file diff --git a/dotnet/AipsRT/Hubs/WhiteboardHub.cs b/dotnet/AipsRT/Hubs/WhiteboardHub.cs index 519c915..af07b91 100644 --- a/dotnet/AipsRT/Hubs/WhiteboardHub.cs +++ b/dotnet/AipsRT/Hubs/WhiteboardHub.cs @@ -2,6 +2,7 @@ using AipsCore.Application.Abstract; using AipsCore.Application.Models.Shape.Command.MoveShape; using AipsCore.Application.Models.Whiteboard.Command.AcceptUserRequestToJoin; using AipsCore.Application.Models.Whiteboard.Command.RejectUserRequestToJoin; +using AipsCore.Application.Models.Whiteboard.Command.UserCanceledRequestToJoin; using AipsCore.Application.Models.Whiteboard.Query.GetMembershipStatus; using AipsCore.Domain.Models.WhiteboardMembership.Enums; using AipsRT.Model.Memberships; @@ -21,14 +22,14 @@ public class WhiteboardHub : Hub private readonly WhiteboardManager _whiteboardManager; private readonly IMessagingService _messagingService; private readonly MembershipService _membershipService; - private readonly GetUserService _getUserService; + private readonly UserService _userService; - public WhiteboardHub(WhiteboardManager whiteboardManager, IMessagingService messagingService, MembershipService membershipService, GetUserService getUserService) + public WhiteboardHub(WhiteboardManager whiteboardManager, IMessagingService messagingService, MembershipService membershipService, UserService userService) { _whiteboardManager = whiteboardManager; _messagingService = messagingService; _membershipService = membershipService; - _getUserService = getUserService; + _userService = userService; } public override async Task OnDisconnectedAsync(Exception? exception) @@ -107,7 +108,7 @@ public class WhiteboardHub : Hub if (user == null) { - user = await _getUserService.GetUser(userId); + user = await _userService.GetUser(userId); } await Clients.User(ownerId.ToString()).SendAsync("UserWaitingForApproval", user); @@ -147,6 +148,7 @@ public class WhiteboardHub : Hub if (whiteboard != null) { + await _messagingService.CancelJoinRequest(new UserCanceledRequestToJoinCommand(whiteboard.WhiteboardId.ToString(), userId.ToString())); await Clients.User(whiteboard.OwnerId.ToString()).SendAsync("UserCanceledJoinRequest", userId.ToString()); } } diff --git a/dotnet/AipsRT/Model/Users/GetUserService.cs b/dotnet/AipsRT/Model/Users/UserService.cs similarity index 77% rename from dotnet/AipsRT/Model/Users/GetUserService.cs rename to dotnet/AipsRT/Model/Users/UserService.cs index 988939e..bdd7d8d 100644 --- a/dotnet/AipsRT/Model/Users/GetUserService.cs +++ b/dotnet/AipsRT/Model/Users/UserService.cs @@ -1,13 +1,14 @@ using AipsCore.Application.Abstract; using AipsCore.Application.Models.User.Query.GetUser; +using AipsCore.Application.Models.Whiteboard.Command.UserCanceledRequestToJoin; namespace AipsRT.Model.Users; -public class GetUserService +public class UserService { private readonly IDispatcher _dispatcher; - public GetUserService(IDispatcher dispatcher) + public UserService(IDispatcher dispatcher) { _dispatcher = dispatcher; } diff --git a/dotnet/AipsRT/Program.cs b/dotnet/AipsRT/Program.cs index 2f7711f..8949cb6 100644 --- a/dotnet/AipsRT/Program.cs +++ b/dotnet/AipsRT/Program.cs @@ -27,7 +27,7 @@ builder.Services.AddSingleton(); builder.Services.AddTransient(); -builder.Services.AddTransient(); +builder.Services.AddTransient(); builder.Services.AddScoped(); builder.Services.AddSingleton(); diff --git a/dotnet/AipsRT/Services/Interfaces/IMessagingService.cs b/dotnet/AipsRT/Services/Interfaces/IMessagingService.cs index ca8b3cb..bbf42d7 100644 --- a/dotnet/AipsRT/Services/Interfaces/IMessagingService.cs +++ b/dotnet/AipsRT/Services/Interfaces/IMessagingService.cs @@ -2,6 +2,7 @@ using AipsCore.Application.Models.Shape.Command.CreateTextShape; using AipsCore.Application.Models.Shape.Command.MoveShape; using AipsCore.Application.Models.Whiteboard.Command.AcceptUserRequestToJoin; using AipsCore.Application.Models.Whiteboard.Command.RejectUserRequestToJoin; +using AipsCore.Application.Models.Whiteboard.Command.UserCanceledRequestToJoin; using AipsRT.Model.Whiteboard.Shapes; namespace AipsRT.Services.Interfaces; @@ -17,4 +18,5 @@ public interface IMessagingService Task AcceptedUser(AcceptUserRequestToJoinCommand command); Task RejectedUser(RejectUserRequestToJoinCommand command); + Task CancelJoinRequest(UserCanceledRequestToJoinCommand command); } \ No newline at end of file diff --git a/dotnet/AipsRT/Services/MessagingService.cs b/dotnet/AipsRT/Services/MessagingService.cs index 7789852..ecd08c0 100644 --- a/dotnet/AipsRT/Services/MessagingService.cs +++ b/dotnet/AipsRT/Services/MessagingService.cs @@ -6,6 +6,7 @@ using AipsCore.Application.Common.Message.AddRectangle; using AipsCore.Application.Common.Message.AddTextShape; using AipsCore.Application.Common.Message.MoveShape; using AipsCore.Application.Common.Message.RejectUserRequestToJoin; +using AipsCore.Application.Common.Message.UserCanceledRequestToJoin; using AipsCore.Application.Models.Shape.Command.CreateArrow; using AipsCore.Application.Models.Shape.Command.CreateLine; using AipsCore.Application.Models.Shape.Command.CreateRectangle; @@ -13,6 +14,7 @@ using AipsCore.Application.Models.Shape.Command.CreateTextShape; using AipsCore.Application.Models.Shape.Command.MoveShape; using AipsCore.Application.Models.Whiteboard.Command.AcceptUserRequestToJoin; using AipsCore.Application.Models.Whiteboard.Command.RejectUserRequestToJoin; +using AipsCore.Application.Models.Whiteboard.Command.UserCanceledRequestToJoin; using AipsRT.Model.Whiteboard.Shapes; using AipsRT.Services.Interfaces; @@ -116,4 +118,10 @@ public class MessagingService : IMessagingService var message = new RejectUserRequestToJoinMessage(command); await _messagePublisher.PublishAsync(message); } + + public async Task CancelJoinRequest(UserCanceledRequestToJoinCommand command) + { + var message = new UserCanceledRequestToJoinMessage(command); + await _messagePublisher.PublishAsync(message); + } } \ No newline at end of file diff --git a/dotnet/AipsWorker/Messages/MessageTypesProvider.cs b/dotnet/AipsWorker/Messages/MessageTypesProvider.cs index a2c62b4..d8089e4 100644 --- a/dotnet/AipsWorker/Messages/MessageTypesProvider.cs +++ b/dotnet/AipsWorker/Messages/MessageTypesProvider.cs @@ -6,6 +6,7 @@ using AipsCore.Application.Common.Message.AddRectangle; using AipsCore.Application.Common.Message.AddTextShape; using AipsCore.Application.Common.Message.MoveShape; using AipsCore.Application.Common.Message.RejectUserRequestToJoin; +using AipsCore.Application.Common.Message.UserCanceledRequestToJoin; namespace AipsWorker.Messages; @@ -21,7 +22,8 @@ public class MessageTypesProvider : IMessageTypesProvider typeof(AddTextShapeMessage), typeof(MoveShapeMessage), typeof(AcceptUserRequestToJoinMessage), - typeof(RejectUserRequestToJoinMessage) + typeof(RejectUserRequestToJoinMessage), + typeof(UserCanceledRequestToJoinMessage) ]; } } \ No newline at end of file diff --git a/front/src/stores/whiteboard.ts b/front/src/stores/whiteboard.ts index c3eb8a4..81687db 100644 --- a/front/src/stores/whiteboard.ts +++ b/front/src/stores/whiteboard.ts @@ -113,6 +113,7 @@ export const useWhiteboardStore = defineStore('whiteboard', () => { whiteboardHubService.onAccepted(() => { const infoStore = useWhiteboardsStore() infoStore.stopWaitingToJoin() + isLoading.value = false }) whiteboardHubService.onRejected(() => {