package utils import ( "regexp" "strings" ) // MaxJSONKeyLength caps a custom-field key so one row can't push an // unbounded string into the JSONB column. const MaxJSONKeyLength = 255 // jsonKeyPattern is the set of custom-field keys the whole product can // actually address. A key is either a plain identifier ("role") or // identifier segments joined by spaces/dashes ("Company Mobile", // "first-name"). That is exactly what the campaign template engine can // resolve: tasks.rewriteSpacedFieldRefs turns `{{.Company Mobile}}` // into `(index . "Company Mobile")`, so spaced and dashed keys work // everywhere a plain one does. Anything outside this set would produce a // field the user can never reference in an email. var jsonKeyPattern = regexp.MustCompile(`^[A-Za-z0-9_]+(?:[ -]+[A-Za-z0-9_]+)*$`) // JSONKeyRules is the human-readable version of jsonKeyPattern, for // error messages the user has to act on. const JSONKeyRules = "use letters, numbers, underscores, spaces or dashes" // NormalizeJSONKey trims a custom-field key and collapses internal // whitespace runs to a single space. CSV headers routinely arrive with a // trailing space or a tab, and "Company Mobile" and "Company Mobile" // must not become two different fields. func NormalizeJSONKey(key string) string { return strings.Join(strings.Fields(key), " ") } // IsValidJSONKey reports whether key is usable as a contact custom-field // key. Callers should NormalizeJSONKey first. func IsValidJSONKey(key string) bool { if len(key) == 0 || len(key) > MaxJSONKeyLength { return false } return jsonKeyPattern.MatchString(key) }