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.
|
// ErrUnknownQueue indicates a queue name was not found in configuration.
|
||||||
var ErrUnknownQueue = errors.New("unknown queue")
|
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.
|
// Router handles message delivery via beads.
|
||||||
// It routes messages to the correct beads database based on address:
|
// It routes messages to the correct beads database based on address:
|
||||||
// - Town-level (mayor/, deacon/) -> {townRoot}/.beads
|
// - Town-level (mayor/, deacon/) -> {townRoot}/.beads
|
||||||
@@ -73,6 +76,16 @@ func parseQueueName(address string) string {
|
|||||||
return strings.TrimPrefix(address, "queue:")
|
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.
|
// expandList returns the recipients for a mailing list.
|
||||||
// Returns ErrUnknownList if the list is not found.
|
// Returns ErrUnknownList if the list is not found.
|
||||||
func (r *Router) expandList(listName string) ([]string, error) {
|
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)
|
// contains checks if s contains substr (helper for error checking)
|
||||||
func contains(s, substr string) bool {
|
func contains(s, substr string) bool {
|
||||||
return len(s) >= len(substr) && (s == substr || len(s) > 0 && containsHelper(s, substr))
|
return len(s) >= len(substr) && (s == substr || len(s) > 0 && containsHelper(s, substr))
|
||||||
|
|||||||
Reference in New Issue
Block a user