Files
Govor/Govor.API/Hubs/FriendsHub.cs
T
Artemy 6063aafd9e Refactor friend request and media services, remove console commands
Refactored the friend request command service and SignalR hub to return and broadcast FriendshipDto objects, improving real-time updates. Enhanced media upload and download logic to support file storage and retrieval, including database integration. Removed all command classes and related infrastructure from the Govor.Console project, streamlining the console client. Updated dependency injection and interfaces to reflect these changes.
2025-07-13 19:03:01 +07:00

185 lines
6.7 KiB
C#

using System.ComponentModel.DataAnnotations;
using AutoMapper;
using Govor.Application.Exceptions.FriendsService;
using Govor.Application.Interfaces.Friends;
using Govor.Application.Interfaces.Infrastructure.Extensions;
using Govor.Contracts.DTOs;
using Govor.Contracts.Responses.SignalR;
using Microsoft.AspNetCore.SignalR;
namespace Govor.API.Hubs;
public class FriendsHub : Hub
{
private readonly ILogger<FriendsHub> _logger;
private readonly IFriendRequestCommandService _friendRequestService;
private readonly ICurrentUserService _currentUserService;
private readonly IMapper _mapper;
public FriendsHub(IFriendRequestCommandService friendRequestService,
ICurrentUserService currentUserService,
ILogger<FriendsHub> logger,
IMapper mapper)
{
_friendRequestService = friendRequestService;
_currentUserService = currentUserService;
_logger = logger;
_mapper = mapper;
}
public override async Task OnConnectedAsync()
{
var userId = GetUserId();
if (userId == Guid.Empty)
{
_logger.LogWarning("User connected with invalid UserID claim.");
Context.Abort(); // Abort connection if userID is invalid
return;
}
// Add user to their own group (for private messages and notifications)
await Groups.AddToGroupAsync(Context.ConnectionId, userId.ToString());
_logger.LogInformation("User {UserId} connected with ConnectionId {ConnectionId} and added to their group",
userId, Context.ConnectionId);
await base.OnConnectedAsync();
}
public override async Task OnDisconnectedAsync(Exception? exception)
{
var userId =
GetUserId(suppressException: true); // Suppress exception if userID is not found (e.g. connection aborted early)
if (userId != Guid.Empty)
{
// Remove user from their own group
await Groups.RemoveFromGroupAsync(Context.ConnectionId, userId.ToString());
_logger.LogInformation(
"User {UserId} disconnected with ConnectionId {ConnectionId} and removed from their group", userId,
Context.ConnectionId);
}
else if (exception != null)
{
_logger.LogWarning(exception,
"User disconnected with an exception and invalid UserID claim. ConnectionId: {ConnectionId}",
Context.ConnectionId);
}
else
{
_logger.LogInformation(
"User disconnected with no exception and invalid UserID claim. ConnectionId: {ConnectionId}",
Context.ConnectionId);
}
await base.OnDisconnectedAsync(exception);
}
public async Task<HubResult<object>> SendRequest(Guid targetUserId)
{
try
{
var userId = _currentUserService.GetCurrentUserId();
var friendship = await _friendRequestService.SendAsync(userId, targetUserId);
await Clients.Group(targetUserId.ToString())
.SendAsync("FriendRequestReceived", _mapper.Map<FriendshipDto>(friendship));
_logger.LogInformation($"Friend request received for user {targetUserId} from {userId}.");
return HubResult<object>.Created();
}
catch (InvalidOperationException ex)
{
_logger.LogWarning(ex, ex.Message);
return HubResult<object>.BadRequest(ex.Message);
}
catch (RequestAlreadySentException ex)
{
_logger.LogWarning(ex, ex.Message);
return HubResult<object>.Conflict(ex.Message);
}
catch (UnauthorizedAccessException ex)
{
_logger.LogWarning(ex, ex.Message);
return HubResult<object>.Unauthorized(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, ex.Message);
return HubResult<object>.Error("Unexpected error! Please try later!");
}
}
public async Task<HubResult<object>> AcceptRequest(Guid friendshipId)
{
try
{
var userId = _currentUserService.GetCurrentUserId();
var friendship = await _friendRequestService.AcceptAsync(friendshipId, userId);
await Clients.Group(userId.ToString())
.SendAsync("FriendRequestAccepted", _mapper.Map<FriendshipDto>(friendship));
_logger.LogInformation($"Friend request accepted for user {userId} from {userId}.");
return HubResult<object>.Ok();
}
catch (InvalidOperationException ex)
{
_logger.LogWarning(ex, ex.Message);
return HubResult<object>.BadRequest(ex.Message);
}
catch (UnauthorizedAccessException ex)
{
_logger.LogWarning(ex, ex.Message);
return HubResult<object>.Unauthorized(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, ex.Message);
return HubResult<object>.Error("Unexpected error! Please try later!");
}
}
public async Task<HubResult<object>> RejectRequest(Guid friendshipId)
{
try
{
var userId = _currentUserService.GetCurrentUserId();
var friendship = await _friendRequestService.RejectAsync(friendshipId, userId);
await Clients.Group(userId.ToString())
.SendAsync("FriendRequestRejected", _mapper.Map<FriendshipDto>(friendship));
_logger.LogInformation($"Friend request rejected for user {userId} from {userId}.");
return HubResult<object>.Ok();
}
catch (InvalidOperationException ex)
{
_logger.LogWarning(ex, ex.Message);
return HubResult<object>.BadRequest(ex.Message);
}
catch (UnauthorizedAccessException ex)
{
_logger.LogWarning(ex, ex.Message);
return HubResult<object>.Unauthorized(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, ex.Message);
return HubResult<object>.Error("Unexpected error! Please try later!");
}
}
private Guid GetUserId(bool suppressException = false)
{
var userIdClaim = Context.User?.FindFirst("userId")?.Value;
if (string.IsNullOrEmpty(userIdClaim) || !Guid.TryParse(userIdClaim, out var userId))
{
if (!suppressException)
{
_logger.LogError("Could not retrieve sender userId. Claim was: {UserIDClaim}", userIdClaim);
throw new UnauthorizedAccessException("userID claim is missing or invalid.");
}
return Guid.Empty;
}
return userId;
}
}