From 877b7747e8a32b1f94de52e2465b3ebd8bfffdbf Mon Sep 17 00:00:00 2001 From: Anirudh Oppiliappan Date: Wed, 22 Jul 2026 19:08:48 +0300 Subject: [PATCH] appview/notify/email: cap at 10 notifs This still marks the unshown ones as "emailed" so we don't send them in the next digest tick. Signed-off-by: Anirudh Oppiliappan --- appview/notify/email/dispatcher.go | 56 +++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/appview/notify/email/dispatcher.go b/appview/notify/email/dispatcher.go index a76391b8..ec0c9ef1 100644 --- a/appview/notify/email/dispatcher.go +++ b/appview/notify/email/dispatcher.go @@ -24,8 +24,9 @@ You have {{.Count}} new notification(s) on Tangled: {{range .Groups}}- {{wrap 70 " " .Header}}{{if .EntityRef}} {{wrap 70 " " .EntityRef}}{{end}} {{.URL}} -{{end}} ---- +{{end}}{{if .HasMore}} +View more notifications: {{.NotificationsURL}} +{{end}}--- Manage notifications: {{.SettingsURL}} ` @@ -73,6 +74,11 @@ const digestHTMLTmpl = ` {{end}} + {{if .HasMore}} +

+ View more notifications +

+ {{end}} @@ -189,12 +195,18 @@ func wordwrap(width int, indent, text string) string { return b.String() } +// digestMaxGroups caps how many notifications are itemized in a digest email; +// beyond this a "View more" link points to the notifications page. +const digestMaxGroups = 10 + type digestData struct { - RecipientHandle string - Count int - Groups []digestGroup - SettingsURL string - AssetsURL string + RecipientHandle string + Count int + Groups []digestGroup + HasMore bool + NotificationsURL string + SettingsURL string + AssetsURL string } // Dispatcher polls the notifications table and sends digest emails. @@ -326,9 +338,16 @@ func (d *Dispatcher) sendDigest(ctx context.Context, recipientDid string, cutoff } func (d *Dispatcher) renderDigest(ctx context.Context, recipientHandle string, notifs []*models.NotificationWithEntity) (subject, text, html string, err error) { - groups := make([]digestGroup, 0, len(notifs)) + count := len(notifs) + + shown := notifs + if len(shown) > digestMaxGroups { + shown = shown[:digestMaxGroups] + } + + groups := make([]digestGroup, 0, len(shown)) - for _, n := range notifs { + for _, n := range shown { actorHandle := n.ActorDid if id, err2 := d.resolver.ResolveIdent(ctx, n.ActorDid); err2 == nil && !id.Handle.IsInvalidHandle() { actorHandle = id.Handle.String() @@ -354,16 +373,21 @@ func (d *Dispatcher) renderDigest(ctx context.Context, recipientHandle string, n }) } - count := len(notifs) data := digestData{ - RecipientHandle: recipientHandle, - Count: count, - Groups: groups, - SettingsURL: d.baseURL + "/settings/notifications", - AssetsURL: d.assetsURL, + RecipientHandle: recipientHandle, + Count: count, + Groups: groups, + HasMore: count > digestMaxGroups, + NotificationsURL: d.baseURL + "/notifications", + SettingsURL: d.baseURL + "/settings/notifications", + AssetsURL: d.assetsURL, } - subject = fmt.Sprintf("[%s] %d notification(s)", recipientHandle, count) + if count > digestMaxGroups { + subject = fmt.Sprintf("[%s] %d+ notifications", recipientHandle, digestMaxGroups) + } else { + subject = fmt.Sprintf("[%s] %d notification(s)", recipientHandle, count) + } var textBuf bytes.Buffer if err = d.textTmpl.Execute(&textBuf, data); err != nil { -- 2.51.2