Validate cookie policy link in banner description
Translations are no longer part of the version snapshot, so the
banner_description text must be validated at write time to ensure
the {{cookie_policy_link}} placeholder is present. Without it
the cookie policy URL silently disappears from the rendered banner.
Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
@@ -68,6 +68,30 @@ func MaxLen(maxLength int) ValidatorFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// ContainsSubstring validates that a string contains the specified substring.
|
||||
func ContainsSubstring(substr string) ValidatorFunc {
|
||||
return func(value any) *ValidationError {
|
||||
actualValue, isNil := dereferenceValue(value)
|
||||
if isNil {
|
||||
return nil
|
||||
}
|
||||
|
||||
str, ok := actualValue.(string)
|
||||
if !ok {
|
||||
return newValidationError(ErrorCodeInvalidFormat, "value must be a string")
|
||||
}
|
||||
|
||||
if !strings.Contains(str, substr) {
|
||||
return newValidationError(
|
||||
ErrorCodeInvalidFormat,
|
||||
fmt.Sprintf("must contain %q", substr),
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// OneOfSlice validates that a value is one of the allowed values in the slice.
|
||||
// Accepts a slice of any type. Compares by value first, then by string representation.
|
||||
func OneOfSlice[T any](allowed []T) ValidatorFunc {
|
||||
|
||||
@@ -67,6 +67,31 @@ func TestMaxLen(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainsSubstring(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
value any
|
||||
substr string
|
||||
wantError bool
|
||||
}{
|
||||
{"contains substring", "hello {{cookie_policy_link}} world", "{{cookie_policy_link}}", false},
|
||||
{"missing substring", "hello world", "{{cookie_policy_link}}", true},
|
||||
{"exact match", "{{cookie_policy_link}}", "{{cookie_policy_link}}", false},
|
||||
{"empty string", "", "{{cookie_policy_link}}", true},
|
||||
{"nil pointer", (*string)(nil), "{{cookie_policy_link}}", false},
|
||||
{"non-string", 123, "foo", true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := ContainsSubstring(tt.substr)(tt.value)
|
||||
if (err != nil) != tt.wantError {
|
||||
t.Errorf("ContainsSubstring() error = %v, wantError %v", err, tt.wantError)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestOneOf(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
Reference in New Issue
Block a user