diff --git a/src/Core/Abstractions/IUserPreferencesService.cs b/src/Core/Abstractions/IUserPreferencesService.cs index c0f6b03..ab6b16e 100644 --- a/src/Core/Abstractions/IUserPreferencesService.cs +++ b/src/Core/Abstractions/IUserPreferencesService.cs @@ -8,4 +8,6 @@ public interface IUserPreferencesService Task> CreateUserPreferences(string userId, CancellationToken ct); Task> UpdateUserPreferences( UserPreferencesDto userPreferences, CancellationToken ct); -} \ No newline at end of file + Task> GetChannelDeliveryInfo( + string recipientUserId, string channel, CancellationToken ct); +} diff --git a/src/Core/Errors/UserPreferencesErrors.cs b/src/Core/Errors/UserPreferencesErrors.cs index 2a874f9..d562144 100644 --- a/src/Core/Errors/UserPreferencesErrors.cs +++ b/src/Core/Errors/UserPreferencesErrors.cs @@ -13,4 +13,7 @@ internal static ErrorOr FailedToUpdate internal static ErrorOr NotFound => Error.NotFound("UserPreferences.NotFound", "User preferences not found"); -} \ No newline at end of file + + internal static ErrorOr ChannelNotFound + => Error.NotFound("UserPreferences.Channel.NotFound", "User preferences for channel not found"); +} diff --git a/src/Core/Mappers/UserPreferencesMapper.cs b/src/Core/Mappers/UserPreferencesMapper.cs index 9767915..2b8d006 100644 --- a/src/Core/Mappers/UserPreferencesMapper.cs +++ b/src/Core/Mappers/UserPreferencesMapper.cs @@ -5,6 +5,29 @@ namespace Core.Mappers; +public static class UserPreferencesChannelMapper +{ + public static ChannelDescriptorBaseDto ToDto(ChannelDescriptorBase e) + { + return new ChannelDescriptorBaseDto + { + Enabled = e.Enabled, + Description = e.Description, + Metadata = e.Metadata + }; + } + + public static ChannelDescriptorBase ToEntity(ChannelDescriptorBaseDto dto) + { + return new ChannelDescriptorBase + { + Enabled = dto.Enabled, + Description = dto.Description, + Metadata = dto.Metadata + }; + } +} + public static class UserPreferencesMapper { internal static UserPreferencesDto ToDto(UserPreferences e) @@ -13,12 +36,7 @@ internal static UserPreferencesDto ToDto(UserPreferences e) { Id = e.Id.ToString(), UserId = e.UserId, - Channels = e.Channels.ToDictionary(x => x.Key, d => new ChannelDescriptorBaseDto - { - Enabled = d.Value.Enabled, - Description = d.Value.Description, - Metadata = d.Value.Metadata - }) + Channels = e.Channels.ToDictionary(x => x.Key, d => UserPreferencesChannelMapper.ToDto(d.Value)) }; } @@ -70,12 +88,7 @@ public static UserPreferences ToEntity(UserPreferencesDto dto) { Id = id, UserId = dto.UserId, - Channels = dto.Channels.ToDictionary(x => x.Key, d => new ChannelDescriptorBase - { - Enabled = d.Value.Enabled, - Description = d.Value.Description, - Metadata = d.Value.Metadata - }), + Channels = dto.Channels.ToDictionary(x => x.Key, d => UserPreferencesChannelMapper.ToEntity(d.Value)), LastUpdated = DateTimeOffset.UtcNow }; } diff --git a/src/Core/Services/NotificationService.cs b/src/Core/Services/NotificationService.cs index 67e2e13..19480db 100644 --- a/src/Core/Services/NotificationService.cs +++ b/src/Core/Services/NotificationService.cs @@ -11,6 +11,7 @@ namespace Core.Services; internal class NotificationService( ITemplateFillerClient massTransitClient, + IUserPreferencesService userPreferencesService, INotificationsAnalyticsClient notificationsAnalyticsClient, INotificationsRepository notificationsRepository) : INotificationsService @@ -24,7 +25,7 @@ public async Task> CreateNotification( await notificationsRepository.InsertOne(notification); dto = dto with { Id = notification.Id.ToString() }; - var deliveryRequests = CreateDeliveryRequests(dto).ToList(); + var deliveryRequests = await CreateDeliveryRequests(dto, ct); await massTransitClient.SendMessages(deliveryRequests, string.Empty); foreach (var deliveryRequest in deliveryRequests) @@ -36,10 +37,35 @@ await notificationsAnalyticsClient return dto; } - private IEnumerable CreateDeliveryRequests(NotificationDto dto) + private async Task> CreateDeliveryRequests(NotificationDto dto, CancellationToken ct) { - return dto.Recipients! + return await dto.Recipients! + .ToAsyncEnumerable() .Select(recipient => Mappers.External.DeliveryRequestMapper.ToRequest(dto, recipient)) - .ToList(); + .SelectAwait(deliveryRequest => PopulateDeliveryInfo(deliveryRequest, ct)) + .ToListAsync(cancellationToken: ct); + } + + private async ValueTask PopulateDeliveryInfo(Notification notification, CancellationToken ct) + { + ct.ThrowIfCancellationRequested(); + + var channel = notification.Recipient.Channel; + var deliveryInfo = await userPreferencesService + .GetChannelDeliveryInfo(notification.Recipient.UserId, channel, ct); + if (deliveryInfo.IsError) + { + return notification; + } + + notification = notification with + { + Recipient = notification.Recipient with + { + DeliveryInfo = deliveryInfo.Value + } + }; + + return notification; } } \ No newline at end of file diff --git a/src/Core/Services/UserPreferencesService.cs b/src/Core/Services/UserPreferencesService.cs index 8c637d2..b9597e0 100644 --- a/src/Core/Services/UserPreferencesService.cs +++ b/src/Core/Services/UserPreferencesService.cs @@ -1,5 +1,6 @@ using Core.Abstractions; using Core.Errors; +using Core.Extensions; using Core.Mappers; using Core.Models.UserPreferences; using ErrorOr; @@ -74,4 +75,22 @@ await _userAnalyticsClient.SendUserAction( return UserPreferencesErrors.FailedToUpdate; } } + + public async Task> GetChannelDeliveryInfo( + string recipientUserId, string channel, CancellationToken ct) + { + var byUserId = new AdHocSpecification( + x => x.UserId == recipientUserId); + var currentUserPreferences = await _userPreferencesRepository.FirstOrDefault(byUserId); + if (currentUserPreferences is null) + { + return UserPreferencesErrors.ChannelNotFound; + } + + var channelKey = channel.ToPascalCase(); + var channelDescriptor = currentUserPreferences.Channels.GetValueOrDefault(channelKey); + return channelDescriptor is null + ? UserPreferencesErrors.ChannelNotFound + : UserPreferencesChannelMapper.ToDto(channelDescriptor); + } } \ No newline at end of file