Files
felhom-controller/controller/internal/stacks/appinfo_address.go
T
admin 05a447ef02 R-498: the app page's first steps name the household's address, not wiki.DOMAIN
AppInfo.WithAddress fills the catalog placeholder (<label>.DOMAIN -> the
effective subdomain + customer domain, bare DOMAIN -> the domain) on a
copy; appDetailHandler applies it. Pinned per catalog template (both
languages) and on the rendered page.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-05 23:12:59 +02:00

52 lines
1.8 KiB
Go

package stacks
import "regexp"
// reDomainPlaceholder matches the catalog's address placeholder in app copy: a bare `DOMAIN` or a
// `<label>.DOMAIN` (wiki.DOMAIN, https://paste.DOMAIN/…). `\b` keeps SUBDOMAIN and MAIL_DOMAIN out —
// the letter or underscore before them is a word character, so no boundary falls inside them.
var reDomainPlaceholder = regexp.MustCompile(`(?:([a-z0-9-]+)\.)?\bDOMAIN\b`)
// WithAddress returns a copy of the app copy with the catalog's `DOMAIN` placeholder filled in
// (R-498): `<label>.DOMAIN` becomes `<subdomain>.<domain>` — the app's EFFECTIVE subdomain (the one
// the household chose at install), or the catalog label when none is known — and a bare `DOMAIN`
// becomes `<domain>`. With no domain configured the copy is returned unchanged: a placeholder is
// better than an address that is wrong. The receiver is not modified (slices are copied), because the
// stack's metadata is shared with every other page. Pinned by TestR498_* (stacks and web).
func (ai AppInfo) WithAddress(subdomain, domain string) AppInfo {
if domain == "" {
return ai
}
fill := func(s string) string {
return reDomainPlaceholder.ReplaceAllStringFunc(s, func(m string) string {
sub := reDomainPlaceholder.FindStringSubmatch(m)
if sub[1] == "" {
return domain
}
label := sub[1]
if subdomain != "" {
label = subdomain
}
return label + "." + domain
})
}
list := func(in []string) []string {
if in == nil {
return nil
}
out := make([]string, len(in))
for i, s := range in {
out[i] = fill(s)
}
return out
}
out := ai
out.Tagline = fill(ai.Tagline)
out.UseCases = list(ai.UseCases)
out.FirstSteps = list(ai.FirstSteps)
out.Prerequisites = list(ai.Prerequisites)
out.DefaultCreds = fill(ai.DefaultCreds)
out.AddPeople = fill(ai.AddPeople)
return out
}