feat: implement notification system with repository, service, and controller layers

This commit is contained in:
2026-10-20 16:45:48 +05:30
parent 28c465f59b
commit d1c3d4e22f
10 changed files with 656 additions and 0 deletions
@@ -0,0 +1,53 @@
namespace Distribution.Features.Notifications;
public class NotificationRecipientResolver(INotificationRepository repo)
{
/// <summary>
/// Expands the rules into a de-duplicated list of active user ids, never including
/// <paramref name="actingUserId"/>.
/// </summary>
public async Task<List<Guid>> ResolveAsync(IEnumerable<RecipientRule> rules, Guid? actingUserId)
{
var ids = new HashSet<Guid>();
foreach (var rule in rules)
ids.UnionWith(await ResolveRuleAsync(rule));
if (actingUserId is { } actor)
ids.Remove(actor);
if (ids.Count == 0) return [];
return await repo.FilterActiveUserIdsAsync(ids);
}
private async Task<IEnumerable<Guid>> ResolveRuleAsync(RecipientRule rule)
{
switch (rule)
{
case UsersRule r:
return r.Ids;
case PermissionRule r:
return await repo.GetUserIdsByPermissionAsync(r.Code);
case ScopeRule r:
return await repo.GetUserIdsByScopeAsync(r.Kind, r.Id);
case PermissionInScopeRule r:
var withPermission = await repo.GetUserIdsByPermissionAsync(r.Code);
var inScope = await repo.GetUserIdsByScopeAsync(r.Kind, r.Id);
return withPermission.Intersect(inScope);
case ReportsToRule r:
var supervisor = await repo.GetReportsToUserIdAsync(r.UserId);
return supervisor is { } s ? [s] : [];
case RouteOwnerRule r:
var owner = await repo.GetRouteOwnerUserIdAsync(r.Kind, r.Id);
return owner is { } o ? [o] : [];
default:
throw new NotSupportedException($"Unknown recipient rule {rule.GetType().Name}.");
}
}
}