feat(mail): Add isAnnounceAddress() and parseAnnounceName() helpers
Add announce address detection to internal/mail/router.go following the same pattern as isListAddress/parseListName and isQueueAddress/ parseQueueName. Added: - isAnnounceAddress(address string) bool - returns true for 'announce:' prefix - parseAnnounceName(address string) string - extracts channel name - ErrUnknownAnnounce error variable (gt-pn2fq) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -20,6 +20,9 @@ var ErrUnknownList = errors.New("unknown mailing list")
|
||||
// ErrUnknownQueue indicates a queue name was not found in configuration.
|
||||
var ErrUnknownQueue = errors.New("unknown queue")
|
||||
|
||||
// ErrUnknownAnnounce indicates an announce channel name was not found in configuration.
|
||||
var ErrUnknownAnnounce = errors.New("unknown announce channel")
|
||||
|
||||
// Router handles message delivery via beads.
|
||||
// It routes messages to the correct beads database based on address:
|
||||
// - Town-level (mayor/, deacon/) -> {townRoot}/.beads
|
||||
@@ -73,6 +76,16 @@ func parseQueueName(address string) string {
|
||||
return strings.TrimPrefix(address, "queue:")
|
||||
}
|
||||
|
||||
// isAnnounceAddress returns true if the address uses announce:name syntax.
|
||||
func isAnnounceAddress(address string) bool {
|
||||
return strings.HasPrefix(address, "announce:")
|
||||
}
|
||||
|
||||
// parseAnnounceName extracts the announce channel name from an announce:name address.
|
||||
func parseAnnounceName(address string) string {
|
||||
return strings.TrimPrefix(address, "announce:")
|
||||
}
|
||||
|
||||
// expandList returns the recipients for a mailing list.
|
||||
// Returns ErrUnknownList if the list is not found.
|
||||
func (r *Router) expandList(listName string) ([]string, error) {
|
||||
|
||||
@@ -493,6 +493,55 @@ func TestExpandQueueNoTownRoot(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// ============ Announce Address Tests ============
|
||||
|
||||
func TestIsAnnounceAddress(t *testing.T) {
|
||||
tests := []struct {
|
||||
address string
|
||||
want bool
|
||||
}{
|
||||
{"announce:bulletin", true},
|
||||
{"announce:gastown/updates", true},
|
||||
{"announce:", true}, // Edge case: empty announce name (will fail on expand)
|
||||
{"mayor/", false},
|
||||
{"gastown/witness", false},
|
||||
{"announcebulletin", false}, // Missing colon
|
||||
{"list:oncall", false},
|
||||
{"queue:work", false},
|
||||
{"", false},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.address, func(t *testing.T) {
|
||||
got := isAnnounceAddress(tt.address)
|
||||
if got != tt.want {
|
||||
t.Errorf("isAnnounceAddress(%q) = %v, want %v", tt.address, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseAnnounceName(t *testing.T) {
|
||||
tests := []struct {
|
||||
address string
|
||||
want string
|
||||
}{
|
||||
{"announce:bulletin", "bulletin"},
|
||||
{"announce:gastown/updates", "gastown/updates"},
|
||||
{"announce:", ""},
|
||||
{"announce:priority-alerts", "priority-alerts"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.address, func(t *testing.T) {
|
||||
got := parseAnnounceName(tt.address)
|
||||
if got != tt.want {
|
||||
t.Errorf("parseAnnounceName(%q) = %q, want %q", tt.address, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// contains checks if s contains substr (helper for error checking)
|
||||
func contains(s, substr string) bool {
|
||||
return len(s) >= len(substr) && (s == substr || len(s) > 0 && containsHelper(s, substr))
|
||||
|
||||
Reference in New Issue
Block a user