Compare commits

...

1 Commits

5 changed files with 103 additions and 13 deletions

View File

@@ -4,20 +4,23 @@ using GozareshgirProgramManager.Domain.ProjectAgg.Events;
using MediatR; using MediatR;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace GozareshgirProgramManager.Application.DomainEventHandlers.ProjectSection; namespace GozareshgirProgramManager.Application.DomainEventHandlers.TaskSection;
public class ProjectSectionAddedHandler:INotificationHandler<DomainEventNotification<ProjectSectionAddedEvent>> public class ProjectSectionAddedHandler:INotificationHandler<DomainEventNotification<TaskSectionAddedEvent>>
{ {
private readonly ILogger<CustomerRegisteredHandler> _logger; private readonly ILogger<CustomerRegisteredHandler> _logger;
private readonly IBoardNotificationPublisher _boardNotificationPublisher;
public ProjectSectionAddedHandler(ILogger<CustomerRegisteredHandler> logger) public ProjectSectionAddedHandler(ILogger<CustomerRegisteredHandler> logger, IBoardNotificationPublisher boardNotificationPublisher)
{ {
_logger = logger; _logger = logger;
_boardNotificationPublisher = boardNotificationPublisher;
} }
public Task Handle(DomainEventNotification<ProjectSectionAddedEvent> notification, CancellationToken cancellationToken) public Task Handle(DomainEventNotification<TaskSectionAddedEvent> notification, CancellationToken cancellationToken)
{ {
var domainEvent = notification.DomainEvent;
//_boardNotificationPublisher.NotifyTaskCreated()
return Task.CompletedTask; return Task.CompletedTask;
} }
} }

View File

@@ -2,7 +2,7 @@ using GozareshgirProgramManager.Application._Common.Models;
using GozareshgirProgramManager.Domain.ProjectAgg.Events; using GozareshgirProgramManager.Domain.ProjectAgg.Events;
using MediatR; using MediatR;
namespace GozareshgirProgramManager.Application.DomainEventHandlers.ProjectSection; namespace GozareshgirProgramManager.Application.DomainEventHandlers.TaskSection;
public class ProjectSectionAssignedHandler:INotificationHandler<DomainEventNotification<ProjectSectionAssignedEvent>> public class ProjectSectionAssignedHandler:INotificationHandler<DomainEventNotification<ProjectSectionAssignedEvent>>
{ {

View File

@@ -3,7 +3,7 @@ using GozareshgirProgramManager.Application.Interfaces;
using GozareshgirProgramManager.Domain.ProjectAgg.Events; using GozareshgirProgramManager.Domain.ProjectAgg.Events;
using MediatR; using MediatR;
namespace GozareshgirProgramManager.Application.DomainEventHandlers.ProjectSection; namespace GozareshgirProgramManager.Application.DomainEventHandlers.TaskSection;
public class TaskSectionStatusChangedHandler:INotificationHandler<DomainEventNotification<TaskSectionStatusChangedEvent>> public class TaskSectionStatusChangedHandler:INotificationHandler<DomainEventNotification<TaskSectionStatusChangedEvent>>
{ {
@@ -17,7 +17,7 @@ public class TaskSectionStatusChangedHandler:INotificationHandler<DomainEventNot
public Task Handle(DomainEventNotification<TaskSectionStatusChangedEvent> notification, CancellationToken cancellationToken) public Task Handle(DomainEventNotification<TaskSectionStatusChangedEvent> notification, CancellationToken cancellationToken)
{ {
var domainEvent = notification.DomainEvent; var domainEvent = notification.DomainEvent;
_boardNotificationPublisher.SendProjectStatusChanged(domainEvent.UserId,domainEvent.OldStatus,domainEvent.NewStatus,domainEvent.SectionId); _boardNotificationPublisher.NotifyTaskStatusChanged(domainEvent.UserId,domainEvent.OldStatus,domainEvent.NewStatus,domainEvent.SectionId);
return Task.CompletedTask; return Task.CompletedTask;
} }
} }

View File

@@ -1,9 +1,19 @@
using GozareshgirProgramManager.Domain.ProjectAgg.Enums; using GozareshgirProgramManager.Domain.ProjectAgg.Entities;
using GozareshgirProgramManager.Domain.ProjectAgg.Enums;
namespace GozareshgirProgramManager.Application.Interfaces; namespace GozareshgirProgramManager.Application.Interfaces;
public interface IBoardNotificationPublisher public interface IBoardNotificationPublisher
{ {
Task SendProjectStatusChanged(long userId, TaskSectionStatus oldStatus, Task NotifyTaskStatusChanged(long userId, TaskSectionStatus oldStatus,
TaskSectionStatus newStatus, Guid sectionId); TaskSectionStatus newStatus, Guid sectionId);
Task NotifyTaskCreated(TaskSection taskSection);
Task NotifyTaskAssigned(long userId, Guid sectionId);
Task NotifyTaskRemoved(long userId, Guid sectionId);
} }

View File

@@ -1,12 +1,14 @@
using System.Collections.Concurrent;
using GozareshgirProgramManager.Application._Common.Constants; using GozareshgirProgramManager.Application._Common.Constants;
using GozareshgirProgramManager.Application.Interfaces; using GozareshgirProgramManager.Application.Interfaces;
using GozareshgirProgramManager.Domain.ProjectAgg.Entities;
using GozareshgirProgramManager.Domain.ProjectAgg.Enums; using GozareshgirProgramManager.Domain.ProjectAgg.Enums;
using Microsoft.AspNetCore.SignalR; using Microsoft.AspNetCore.SignalR;
using ServiceHost.Hubs.ProgramManager; using ServiceHost.Hubs.ProgramManager;
namespace ServiceHost.Notifications.ProgramManager; namespace ServiceHost.Notifications.ProgramManager;
public class SignalRBoardNotificationPublisher:IBoardNotificationPublisher public class SignalRBoardNotificationPublisher : IBoardNotificationPublisher
{ {
private readonly IHubContext<ProjectBoardHub> _hubContext; private readonly IHubContext<ProjectBoardHub> _hubContext;
@@ -15,12 +17,12 @@ public class SignalRBoardNotificationPublisher:IBoardNotificationPublisher
_hubContext = hubContext; _hubContext = hubContext;
} }
public Task SendProjectStatusChanged(long userId, TaskSectionStatus oldStatus, public Task NotifyTaskStatusChanged(long userId, TaskSectionStatus oldStatus,
TaskSectionStatus newStatus, Guid sectionId) TaskSectionStatus newStatus, Guid sectionId)
{ {
var payload = new var payload = new
{ {
UserId= userId, UserId = userId,
OldStatus = oldStatus, OldStatus = oldStatus,
NewStatus = newStatus, NewStatus = newStatus,
SectionId = sectionId SectionId = sectionId
@@ -36,4 +38,79 @@ public class SignalRBoardNotificationPublisher:IBoardNotificationPublisher
return _hubContext.Clients.Groups(taskGroup, permissionGroup) return _hubContext.Clients.Groups(taskGroup, permissionGroup)
.SendAsync("ReceiveProjectStatusChanged", payload); .SendAsync("ReceiveProjectStatusChanged", payload);
} }
public async Task NotifyTaskCreated(TaskSection taskSection)
{
var sectionId = taskSection.Id;
var userId = taskSection.CurrentAssignedUserId;
var taskGroup = $"pm.task:{taskSection.Id}";
var adminGroup = $"pm.perm:{ProgramManagerPermissionCode.Board.All.ViewAll}";
// Add assignee connections to task group automatically
await AddAssigneeConnectionsToTaskGroup(userId, sectionId);
var payload = new
{
TaskId = sectionId,
AssignedTo = userId,
};
await _hubContext.Clients.Groups(taskGroup, adminGroup)
.SendAsync("TaskCreated", payload);
}
public Task NotifyTaskAssigned(long userId, Guid sectionId)
{
throw new NotImplementedException();
}
public Task NotifyTaskRemoved(long userId, Guid sectionId)
{
throw new NotImplementedException();
}
private async Task AddAssigneeConnectionsToTaskGroup(long userId, Guid taskId)
{
// Retrieve all connectionIds that have this claim
var connections = ConnectionMapping.GetConnectionsByClaim("pm.userId", userId.ToString());
var taskGroup = $"pm.task:{taskId}";
var joinTasks = connections
.Select(connId => _hubContext.Groups.AddToGroupAsync(connId, taskGroup));
await Task.WhenAll(joinTasks);
}
}
public static class ConnectionMapping
{
private static readonly ConcurrentDictionary<string, HashSet<string>> _map = new();
public static void Add(string claimType, string claimValue, string connectionId)
{
var key = $"{claimType}:{claimValue}";
_map.AddOrUpdate(key,
_ => new HashSet<string> { connectionId },
(_, set) => { set.Add(connectionId); return set; });
}
public static void Remove(string claimType, string claimValue, string connectionId)
{
var key = $"{claimType}:{claimValue}";
if (_map.TryGetValue(key, out var set))
{
set.Remove(connectionId);
if (!set.Any()) _map.TryRemove(key, out _);
}
}
public static IEnumerable<string> GetConnectionsByClaim(string claimType, string claimValue)
{
var key = $"{claimType}:{claimValue}";
return _map.TryGetValue(key, out var set) ? set : Enumerable.Empty<string>();
}
} }