Harden notifications: bump MailKit, bound webhook body, share truncation, skip soft-deleted members

This commit is contained in:
Chris Chen
2026-06-23 19:29:23 -07:00
parent fd71f5a107
commit 5a915ebdd1
6 changed files with 44 additions and 8 deletions
@@ -12,8 +12,6 @@ namespace ROLAC.API.Services.Notifications;
/// </summary>
public sealed class EmailService : IEmailService
{
private const int BodyLogMaxLength = 8000;
private readonly AppDbContext _db;
private readonly ISmtpDispatcher _dispatcher;
private readonly CurrentUserAccessor _currentUser;
@@ -44,7 +42,7 @@ public sealed class EmailService : IEmailService
TargetExternalId = recipient.Address,
Subject = message.Subject,
MemberId = recipient.MemberId,
Body = Truncate(message.HtmlBody),
Body = NotificationLogText.Truncate(message.HtmlBody),
SentByUserId = sentBy,
SentAt = DateTime.UtcNow,
};
@@ -97,6 +95,4 @@ public sealed class EmailService : IEmailService
return resolved;
}
private static string Truncate(string body) =>
body.Length <= BodyLogMaxLength ? body : body[..BodyLogMaxLength] + "…[truncated]";
}
@@ -31,8 +31,12 @@ public sealed class LineNotificationService : ILineNotificationService
var failures = new List<NotificationFailure>();
var sentCount = 0;
var liveMemberIds = await _db.Members
.Where(m => memberIds.Contains(m.Id))
.Select(m => m.Id)
.ToListAsync(ct);
var bindings = await _db.MemberChannelBindings
.Where(b => b.Channel == Channel && memberIds.Contains(b.MemberId))
.Where(b => b.Channel == Channel && liveMemberIds.Contains(b.MemberId))
.ToListAsync(ct);
foreach (var binding in bindings)
{
@@ -146,7 +150,7 @@ public sealed class LineNotificationService : ILineNotificationService
TargetExternalId = externalId,
MemberId = memberId,
MessagingGroupId = groupId,
Body = body,
Body = NotificationLogText.Truncate(body),
Status = result.Success ? NotificationStatuses.Sent : NotificationStatuses.Failed,
Error = result.Error,
SentByUserId = sentBy,
@@ -47,3 +47,13 @@ public sealed record EmailMessage(
string HtmlBody,
IReadOnlyList<EmailAttachment>? Attachments = null,
string? SentByUserId = null);
/// <summary>Helpers for building NotificationLog rows consistently across channels.</summary>
public static class NotificationLogText
{
public const int BodyMaxLength = 8000;
/// <summary>Caps a body string so an oversized message can't bloat the log table.</summary>
public static string Truncate(string body) =>
body.Length <= BodyMaxLength ? body : body[..BodyMaxLength] + "…[truncated]";
}