diff --git a/internal/sub/remark_vars.go b/internal/sub/remark_vars.go index 529d7f64e..029c7eeb1 100644 --- a/internal/sub/remark_vars.go +++ b/internal/sub/remark_vars.go @@ -481,6 +481,15 @@ var connectionTokens = map[string]bool{ var displayRemoveTokens = mergeTokenSets(usageInfoTokens, connectionTokens) +// firstLinkOnlyBodyTokens are stripped from every subscription-body link after a +// client's first one: the usage/info tokens plus the per-client EMAIL/USERNAME +// identity. A client app needs the email once, so repeating it on every link of +// the same subscription is noise — show it on the first link only, like traffic. +var firstLinkOnlyBodyTokens = mergeTokenSets(usageInfoTokens, map[string]bool{ + "EMAIL": true, + "USERNAME": true, +}) + func mergeTokenSets(sets ...map[string]bool) map[string]bool { out := make(map[string]bool) for _, set := range sets { @@ -551,7 +560,7 @@ func (s *SubService) effectiveTemplate(email string) string { s.usageShown = map[string]bool{} } if s.usageShown[email] { - return filterRemarkTemplate(translated, usageInfoTokens) + return filterRemarkTemplate(translated, firstLinkOnlyBodyTokens) } s.usageShown[email] = true return translated diff --git a/internal/sub/remark_vars_test.go b/internal/sub/remark_vars_test.go index 21235980f..b291a0ed5 100644 --- a/internal/sub/remark_vars_test.go +++ b/internal/sub/remark_vars_test.go @@ -386,8 +386,8 @@ func TestIdentityTokenBodyVsDisplay(t *testing.T) { body := &SubService{remarkTemplate: tmpl, subscriptionBody: true, usageShown: map[string]bool{}} _ = body.genTemplatedRemark(inbound, client, "", "ws") // first link consumes the usage block - if second := body.genTemplatedRemark(inbound, client, "", "ws"); !strings.Contains(second, "john@x") { - t.Fatalf("repeat body link %q must keep the identity token", second) + if second := body.genTemplatedRemark(inbound, client, "", "ws"); strings.Contains(second, "john@x") { + t.Fatalf("repeat body link %q must drop the identity token", second) } display := &SubService{remarkTemplate: tmpl, subscriptionBody: false} @@ -624,7 +624,7 @@ func TestUsageOnFirstLinkOnly_SingleBracket(t *testing.T) { } } -func TestEmailOnEveryLink(t *testing.T) { +func TestEmailOnFirstLinkOnly(t *testing.T) { s := &SubService{ remarkTemplate: "{{INBOUND}} {{EMAIL}}|📊{{TRAFFIC_LEFT}}", subscriptionBody: true, @@ -640,22 +640,15 @@ func TestEmailOnEveryLink(t *testing.T) { } client := model.Client{Email: "alice@x"} first := s.genTemplatedRemark(inbound, client, "", "ws") + s.usageShown["alice@x"] = true second := s.genTemplatedRemark(inbound, client, "", "ws") - third := s.genTemplatedRemark(inbound, client, "", "ws") - for i, remark := range []string{first, second, third} { - if !strings.Contains(remark, "alice@x") { - t.Fatalf("link %d must carry the client email: %q", i+1, remark) - } - if !strings.Contains(remark, "DE") { - t.Fatalf("link %d must carry the inbound name: %q", i+1, remark) - } + if !strings.Contains(first, "alice@x") { + t.Fatalf("first link should carry email: %q", first) } - if !strings.Contains(first, "📊") { - t.Fatalf("first link should carry the usage block: %q", first) + if strings.Contains(second, "alice@x") { + t.Fatalf("second link must not carry email: %q", second) } - for i, remark := range []string{second, third} { - if strings.Contains(remark, "📊") { - t.Fatalf("repeat link %d must still drop the usage block: %q", i+2, remark) - } + if !strings.Contains(second, "DE") { + t.Fatalf("second link should still carry the inbound name: %q", second) } }