mirror of
https://github.com/Govor-team/Govor.git
synced 2026-07-21 11:44:56 +00:00
Add user online presence tracking and notification
Introduced interfaces and services for tracking user online status, including IOnlineUserStore, IUserNotificationScopeService, and IUserPresenceReader. Added PresenceHub for real-time presence updates via SignalR. Updated OnlinePingingController to use new services and return online status and last seen. Extended UserDto with IsOnline property. Updated dependency injection and privacy settings enum. Removed obsolete IUserPresenceService.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
using Govor.Application.Interfaces;
|
||||
using Govor.Application.Interfaces.Infrastructure.Extensions;
|
||||
using Govor.Core.Repositories.Users;
|
||||
using Govor.Application.Interfaces.UserOnlineStatus;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
@@ -13,7 +13,8 @@ public class OnlinePingingController : Controller
|
||||
{
|
||||
private readonly ILogger<OnlinePingingController> _logger;
|
||||
private readonly IPingHandlerService _ping;
|
||||
private readonly IUserPresenceService _presenceService;
|
||||
private readonly IUserPresenceReader _presenceReader;
|
||||
private readonly IOnlineUserStore _userOnlineStore;
|
||||
private readonly ICurrentUserService _currentUserService;
|
||||
|
||||
public OnlinePingingController(ILogger<OnlinePingingController> logger,
|
||||
@@ -57,11 +58,17 @@ public class OnlinePingingController : Controller
|
||||
}
|
||||
|
||||
[HttpGet("status/{userId}")]
|
||||
public IActionResult GetStatus(Guid userId)
|
||||
public async Task<IActionResult> GetStatus(Guid userId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Ok(_presenceService.WhenUserWasOnline(userId));
|
||||
var isOnline = _userOnlineStore.IsOnline(userId);
|
||||
var lastSeen = await _presenceReader.GetLastSeenAsync(userId);
|
||||
|
||||
return Ok(new {
|
||||
isOnline,
|
||||
lastSeen
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -7,12 +7,14 @@ using Govor.Application.Interfaces.Friends;
|
||||
using Govor.Application.Interfaces.Infrastructure.Extensions;
|
||||
using Govor.Application.Interfaces.Medias;
|
||||
using Govor.Application.Interfaces.Messages;
|
||||
using Govor.Application.Interfaces.UserOnlineStatus;
|
||||
using Govor.Application.Interfaces.UserSession;
|
||||
using Govor.Application.Services;
|
||||
using Govor.Application.Services.Authentication;
|
||||
using Govor.Application.Services.Friends;
|
||||
using Govor.Application.Services.Medias;
|
||||
using Govor.Application.Services.Messages;
|
||||
using Govor.Application.Services.UserOnlineStatus;
|
||||
using Govor.Application.Services.UserSessions;
|
||||
using Govor.Core.Infrastructure.Extensions;
|
||||
using Govor.Core.Infrastructure.Validators;
|
||||
@@ -74,6 +76,11 @@ public static class ConfigurationProgramExtensions
|
||||
// UserSession
|
||||
services.AddScoped<IUserSessionOpener, UserSessionOpener>();
|
||||
services.AddScoped<IUserSessionRefresher, UserSessionRefresher>();
|
||||
|
||||
services.AddScoped<IUserNotificationScopeService, UserNotificationScopeService>();
|
||||
services.AddScoped<IUserPresenceReader, UserPresenceReader>();
|
||||
services.AddSingleton<IOnlineUserStore, OnlineUserStore>();
|
||||
|
||||
// Auto Mapper
|
||||
services.AddAutoMapper(typeof(MappingProfile));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
using Govor.Application.Interfaces;
|
||||
using Govor.Application.Interfaces.Infrastructure.Extensions;
|
||||
using Govor.Application.Interfaces.UserOnlineStatus;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
|
||||
namespace Govor.API.Hubs;
|
||||
|
||||
[Authorize(Roles = "Admin, User")]
|
||||
[Route("hubs/presence")]
|
||||
public class PresenceHub : Hub
|
||||
{
|
||||
private readonly ILogger<PresenceHub> _logger;
|
||||
private readonly IUserNotificationScopeService _notificationScopeService;
|
||||
private readonly IOnlineUserStore _onlineUserStore;
|
||||
|
||||
public PresenceHub(ILogger<PresenceHub> logger, IUserNotificationScopeService notificationScopeService, IOnlineUserStore onlineUserStore)
|
||||
{
|
||||
_logger = logger;
|
||||
_notificationScopeService = notificationScopeService;
|
||||
_onlineUserStore = onlineUserStore;
|
||||
}
|
||||
|
||||
public override async Task OnConnectedAsync()
|
||||
{
|
||||
var userId = GetUserId();
|
||||
if (userId == Guid.Empty)
|
||||
{
|
||||
_logger.LogWarning("User connected with invalid UserID claim.");
|
||||
Context.Abort();
|
||||
return;
|
||||
}
|
||||
|
||||
_onlineUserStore.SetOnlineUser(userId);
|
||||
await Groups.AddToGroupAsync(Context.ConnectionId, userId.ToString());
|
||||
|
||||
var friends = await _notificationScopeService.GetNotifiedUsers(userId);
|
||||
|
||||
foreach (var recipient in friends)
|
||||
{
|
||||
await Clients.Group(recipient.ToString())
|
||||
.SendAsync("UserOnline", userId);
|
||||
}
|
||||
|
||||
await base.OnConnectedAsync();
|
||||
}
|
||||
|
||||
public override async Task OnDisconnectedAsync(Exception? exception)
|
||||
{
|
||||
var userId = GetUserId();
|
||||
if (userId == Guid.Empty) return;
|
||||
|
||||
_onlineUserStore.SetOfflineUser(userId);
|
||||
|
||||
var friends = await _notificationScopeService.GetNotifiedUsers(userId);
|
||||
|
||||
foreach (var recipient in friends)
|
||||
{
|
||||
await Clients.Group(recipient.ToString())
|
||||
.SendAsync("UserOffline", userId);
|
||||
}
|
||||
|
||||
await base.OnDisconnectedAsync(exception);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user