feat(sms): stamp Notification.Type from list at ingest (S4)
This commit is contained in:
@@ -174,11 +174,12 @@ public class NotificationOutboxActor : ReceiveActor, IWithTimers
|
||||
private void HandleSubmit(NotificationSubmit msg)
|
||||
{
|
||||
var sender = Sender;
|
||||
var notification = BuildNotification(msg);
|
||||
|
||||
// The success projection fires for both a fresh insert and an existing row;
|
||||
// only a thrown repository error reaches the failure projection.
|
||||
PersistAsync(notification).PipeTo(
|
||||
// only a thrown repository error reaches the failure projection. The list
|
||||
// lookup that stamps the channel Type happens inside PersistAsync so it can
|
||||
// share the same DI scope as the insert.
|
||||
PersistAsync(msg).PipeTo(
|
||||
Self,
|
||||
success: () => new InternalMessages.IngestPersisted(
|
||||
msg.NotificationId, sender, Succeeded: true, Error: null),
|
||||
@@ -187,16 +188,31 @@ public class NotificationOutboxActor : ReceiveActor, IWithTimers
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves a scoped <see cref="INotificationOutboxRepository"/> and inserts the
|
||||
/// notification if a row with the same id does not already exist. The boolean result
|
||||
/// of <c>InsertIfNotExistsAsync</c> is intentionally ignored: an existing row is an
|
||||
/// idempotent re-submission and is acked just like a fresh insert so the site can
|
||||
/// clear its forward buffer. Only a thrown error must surface to the caller.
|
||||
/// Resolves the target notification list to stamp the delivery channel
|
||||
/// <see cref="NotificationType"/> on a fresh row, then inserts the notification if a row
|
||||
/// with the same id does not already exist. The boolean result of
|
||||
/// <c>InsertIfNotExistsAsync</c> is intentionally ignored: an existing row is an
|
||||
/// idempotent re-submission and is acked just like a fresh insert (and its persisted
|
||||
/// Type is left untouched) so the site can clear its forward buffer. Only a thrown
|
||||
/// error must surface to the caller.
|
||||
/// </summary>
|
||||
private async Task PersistAsync(Notification notification)
|
||||
private async Task PersistAsync(NotificationSubmit msg)
|
||||
{
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
var repository = scope.ServiceProvider.GetRequiredService<INotificationOutboxRepository>();
|
||||
|
||||
// The list's Type is the authoritative delivery channel. Resolve it here so a
|
||||
// fresh row is stamped with the right channel (Email/Sms/...). GetService (not
|
||||
// GetRequiredService) so the lookup is optional: a host without INotification
|
||||
// Repository, or a missing list, falls back to Email — the notification then
|
||||
// parks at delivery with "list not found", which is the unchanged behaviour.
|
||||
var listRepository = scope.ServiceProvider.GetService<INotificationRepository>();
|
||||
var list = listRepository is null
|
||||
? null
|
||||
: await listRepository.GetListByNameAsync(msg.ListName);
|
||||
var type = list?.Type ?? NotificationType.Email;
|
||||
|
||||
var notification = BuildNotification(msg, type);
|
||||
await repository.InsertIfNotExistsAsync(notification);
|
||||
}
|
||||
|
||||
@@ -1139,12 +1155,13 @@ public class NotificationOutboxActor : ReceiveActor, IWithTimers
|
||||
return Enum.TryParse<TEnum>(value, ignoreCase: true, out var parsed) ? parsed : null;
|
||||
}
|
||||
|
||||
private static Notification BuildNotification(NotificationSubmit msg)
|
||||
private static Notification BuildNotification(NotificationSubmit msg, NotificationType type)
|
||||
{
|
||||
// All current notifications are email; NotificationType has only the Email member.
|
||||
// The delivery channel is taken from the target list's Type (resolved by the
|
||||
// caller); it defaults to Email when the list cannot be resolved.
|
||||
return new Notification(
|
||||
msg.NotificationId,
|
||||
NotificationType.Email,
|
||||
type,
|
||||
msg.ListName,
|
||||
msg.Subject,
|
||||
msg.Body,
|
||||
|
||||
Reference in New Issue
Block a user