@@ -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;
|
||||
@@ -0,0 +1,19 @@
|
||||
using AipsCore.Application.Abstract;
|
||||
using AipsCore.Application.Abstract.MessageBroking;
|
||||
|
||||
namespace AipsCore.Application.Common.Message.UserCanceledRequestToJoin;
|
||||
|
||||
public class UserCanceledRequestToJoinMessageHandler : IMessageHandler<UserCanceledRequestToJoinMessage>
|
||||
{
|
||||
private readonly IDispatcher _dispatcher;
|
||||
|
||||
public UserCanceledRequestToJoinMessageHandler(IDispatcher dispatcher)
|
||||
{
|
||||
_dispatcher = dispatcher;
|
||||
}
|
||||
|
||||
public async Task Handle(UserCanceledRequestToJoinMessage message, CancellationToken cancellationToken)
|
||||
{
|
||||
await _dispatcher.Execute(message.Command, cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
using AipsCore.Application.Abstract.Command;
|
||||
|
||||
namespace AipsCore.Application.Models.Whiteboard.Command.UserCanceledRequestToJoin;
|
||||
|
||||
public record UserCanceledRequestToJoinCommand(string WhiteboardId, string UserId): ICommand;
|
||||
@@ -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<UserCanceledRequestToJoinCommand>
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -28,7 +28,8 @@ public class GetWhiteboardService
|
||||
{
|
||||
WhiteboardId = entity.Id,
|
||||
OwnerId = entity.OwnerId,
|
||||
Owner = new User(entity.Owner.Id, entity.Owner.UserName!, entity.Owner.Email!)
|
||||
Owner = new User(entity.Owner.Id, entity.Owner.UserName!, entity.Owner.Email!),
|
||||
Code = entity.Code,
|
||||
};
|
||||
|
||||
foreach (var membership in entity.Memberships)
|
||||
|
||||
@@ -10,12 +10,13 @@ public class Whiteboard
|
||||
public Guid OwnerId { get; set; }
|
||||
public User Owner { get; set; } = null!;
|
||||
|
||||
public string Code {get; set;}
|
||||
|
||||
public List<User> Users { get; } = [];
|
||||
|
||||
public List<User> ActiveUsers { get; } = [];
|
||||
public void AddActiveUser(User user) => ActiveUsers.Add(user);
|
||||
public void RemoveActiveUser(Guid userId)
|
||||
=> ActiveUsers.RemoveAll(u => u.UserId == userId);
|
||||
public void RemoveActiveUser(Guid userId) => ActiveUsers.RemoveAll(u => u.UserId == userId);
|
||||
|
||||
public List<Shape> Shapes { get; } = [];
|
||||
|
||||
@@ -48,5 +49,11 @@ public class Whiteboard
|
||||
TextShapes.Add(shape);
|
||||
}
|
||||
|
||||
public void AddUser(User user) => Users.Add(user);
|
||||
public void AddUser(User user)
|
||||
{
|
||||
if (!Users.Contains(user))
|
||||
{
|
||||
Users.Add(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ builder.Services.AddSingleton<IErrorMessageHandleStrategy, RtErrorHandleStrategy
|
||||
builder.Services.AddHostedService<ErrorSubscriberBackgroundService>();
|
||||
|
||||
builder.Services.AddTransient<MembershipService>();
|
||||
builder.Services.AddTransient<GetUserService>();
|
||||
builder.Services.AddTransient<UserService>();
|
||||
|
||||
builder.Services.AddScoped<GetWhiteboardService>();
|
||||
builder.Services.AddSingleton<WhiteboardManager>();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -18,10 +18,17 @@ public class RtErrorHandleStrategy : IErrorMessageHandleStrategy
|
||||
|
||||
public async Task Handle(ErrorMessage message, CancellationToken cancellationToken)
|
||||
{
|
||||
var activeUsers = _whiteboardManager.GetWhiteboard(message.WhiteboardId)!.ActiveUsers;
|
||||
|
||||
await _whiteboardManager.LoadWhiteboard(message.WhiteboardId);
|
||||
|
||||
var whiteboard = _whiteboardManager.GetWhiteboard(message.WhiteboardId)!;
|
||||
|
||||
foreach (var user in activeUsers)
|
||||
{
|
||||
whiteboard.AddActiveUser(user);
|
||||
}
|
||||
|
||||
await _hubContext.Clients
|
||||
.Group(whiteboard.WhiteboardId.ToString())
|
||||
.SendAsync("InitWhiteboard", whiteboard, cancellationToken);
|
||||
|
||||
@@ -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)
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,12 @@ const colors = ['#4f9dff', '#ff4f4f', '#4fff4f', '#ffff4f', '#ff4fff', '#ffffff'
|
||||
|
||||
const isReadOnly = computed(() => sessionStore.selectedTool === 'hand' && !!sessionStore.selectedShape)
|
||||
|
||||
const isOwner = computed(() => {
|
||||
const wb = sessionStore.whiteboard
|
||||
if (!wb || !auth.user) return false
|
||||
return wb.ownerId === auth.user.userId
|
||||
})
|
||||
|
||||
const showProperties = computed(() => {
|
||||
if (['rectangle', 'arrow', 'line', 'text'].includes(sessionStore.selectedTool)) return true
|
||||
if (sessionStore.selectedTool === 'hand' && sessionStore.selectedShape) return true
|
||||
@@ -61,7 +67,7 @@ const displayTextSize = computed(() => {
|
||||
|
||||
const showCopiedTooltip = ref(false)
|
||||
|
||||
const whiteboardCode = computed(() => infoStore.getCurrentWhiteboard()?.code || '')
|
||||
const whiteboardCode = computed(() => sessionStore.whiteboard!.code)
|
||||
|
||||
const copyCodeToClipboard = async () => {
|
||||
console.info(whiteboardCode.value)
|
||||
@@ -166,7 +172,7 @@ const copyCodeToClipboard = async () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="position-relative mb-2">
|
||||
<div v-if="isOwner" class="position-relative mb-2">
|
||||
<button
|
||||
class="btn btn-sm btn-outline-primary w-100"
|
||||
@click="copyCodeToClipboard"
|
||||
|
||||
@@ -22,8 +22,23 @@ export class SignalRService {
|
||||
}
|
||||
|
||||
async start(): Promise<void> {
|
||||
if (this.connection.state === HubConnectionState.Disconnected) {
|
||||
if (this.connection.state !== HubConnectionState.Disconnected) return;
|
||||
|
||||
try {
|
||||
await this.connection.start();
|
||||
} catch (err: any) {
|
||||
if (err.statusCode === 401 || err.message?.includes("401")) {
|
||||
const authStore = useAuthStore();
|
||||
try {
|
||||
await authStore.tryRefresh();
|
||||
|
||||
await this.connection.start();
|
||||
} catch (refreshErr) {
|
||||
throw refreshErr;
|
||||
}
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -151,6 +151,7 @@ export const useAuthStore = defineStore('auth', () => {
|
||||
isAuthenticated,
|
||||
isLoading,
|
||||
error,
|
||||
tryRefresh,
|
||||
initialize,
|
||||
login,
|
||||
signup,
|
||||
|
||||
@@ -113,6 +113,7 @@ export const useWhiteboardStore = defineStore('whiteboard', () => {
|
||||
whiteboardHubService.onAccepted(() => {
|
||||
const infoStore = useWhiteboardsStore()
|
||||
infoStore.stopWaitingToJoin()
|
||||
isLoading.value = false
|
||||
})
|
||||
|
||||
whiteboardHubService.onRejected(() => {
|
||||
|
||||
@@ -33,6 +33,7 @@ export interface TextShape extends Shape {
|
||||
export interface Whiteboard {
|
||||
whiteboardId: string
|
||||
ownerId: string
|
||||
code: string
|
||||
rectangles: Rectangle[]
|
||||
arrows: Arrow[]
|
||||
lines: Line[]
|
||||
|
||||
Reference in New Issue
Block a user