Refactor friend request services and add SignalR error handling

Split IFriendRequestService into command and query interfaces, refactor related services and tests, and update dependency injection. Add HubResult response model and a SignalR HubExceptionFilter for consistent error handling. Move and update FriendsHub to use new command service and result pattern. Update username validation to allow digits after Cyrillic letters. Add new controllers and configuration for SignalR. Remove obsolete IFriendRequestService and related code.
This commit is contained in:
Artemy
2025-07-10 15:31:57 +07:00
parent b1f3aa0266
commit 437bedb117
20 changed files with 571 additions and 205 deletions
@@ -0,0 +1,76 @@
using Govor.Application.Exceptions.FriendsService;
using Govor.Application.Interfaces.Friends;
using Govor.Core.Models;
using Govor.Core.Repositories.Friendships;
using Govor.Data.Repositories.Exceptions;
namespace Govor.Application.Services.Friends;
public class FriendRequestCommandService : IFriendRequestCommandService
{
private readonly IFriendshipsRepository _friendshipsRepository;
public FriendRequestCommandService(IFriendshipsRepository friendshipsRepository)
{
_friendshipsRepository = friendshipsRepository;
}
public async Task SendAsync(Guid fromUserId, Guid toUserId)
{
if (fromUserId == toUserId)
throw new InvalidOperationException("Cannot send a request to self user");
if (_friendshipsRepository.Exist(fromUserId, toUserId))
throw new RequestAlreadySentException(fromUserId, toUserId);
await _friendshipsRepository.AddAsync(new Friendship
{
Id = Guid.NewGuid(),
RequesterId = fromUserId,
AddresseeId = toUserId,
Status = FriendshipStatus.Pending
});
}
public async Task AcceptAsync(Guid requestId, Guid currentUserId)
{
try
{
var friendship = await _friendshipsRepository.GetByIdAsync(requestId);
if (friendship.AddresseeId != currentUserId)
throw new UnauthorizedAccessException("You cannot accept this request");
if (friendship.Status != FriendshipStatus.Pending)
throw new InvalidOperationException("Request is already accepted");
friendship.Status = FriendshipStatus.Accepted;
await _friendshipsRepository.UpdateAsync(friendship);
}
catch (NotFoundByKeyException<Guid> ex)
{
throw new InvalidOperationException("Friendship not found! You cant accept request!", ex);
}
}
public async Task RejectAsync(Guid requestId, Guid currentUserId)
{
try
{
var friendship = await _friendshipsRepository.GetByIdAsync(requestId);
if (friendship.AddresseeId != currentUserId)
throw new UnauthorizedAccessException("You cannot accept this request");
if (friendship.Status != FriendshipStatus.Pending && friendship.Status != FriendshipStatus.Rejected)
throw new InvalidOperationException($"Request is already {friendship.Status}");
friendship.Status = FriendshipStatus.Rejected;
await _friendshipsRepository.UpdateAsync(friendship);
}
catch (NotFoundByKeyException<Guid> ex)
{
throw new InvalidOperationException("Friendship not found! You cant reject request!", ex);
}
}
}