Add slug to cookie categories for stable consent identifiers
The category slug provides a stable, URL-safe key used as the data-cookie-consent attribute value and consent data key, replacing the fragile category name. This prevents breakage when categories are renamed. - Add slug column with unique-per-banner constraint and backfill migration - Add Slug validator (lowercase alphanumeric + hyphens) - Propagate slug through GraphQL schema, service layer, and snapshot - Update console UI with slug field in create/edit forms - Switch cookie-banner widget to use slug as consent data keys Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
package validator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"slices"
|
||||
@@ -25,6 +26,7 @@ import (
|
||||
|
||||
var (
|
||||
domainRegex = regexp.MustCompile(`^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)*[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$`)
|
||||
slugRegex = regexp.MustCompile(`^[a-z0-9]+(-[a-z0-9]+)*$`)
|
||||
)
|
||||
|
||||
// URL validates that a string is a valid URL with http or https scheme.
|
||||
@@ -177,6 +179,36 @@ func Origin() ValidatorFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// Slug validates that a string is a lowercase alphanumeric slug (with hyphens, no
|
||||
// leading/trailing hyphens, no consecutive hyphens) and does not exceed maxLen.
|
||||
func Slug(maxLen int) 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 str == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(str) > maxLen {
|
||||
return newValidationError(ErrorCodeTooLong, fmt.Sprintf("slug must be at most %d characters", maxLen))
|
||||
}
|
||||
|
||||
if !slugRegex.MatchString(str) {
|
||||
return newValidationError(ErrorCodeInvalidFormat, "slug must contain only lowercase letters, numbers, and hyphens")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Domain validates that a string is a valid domain name.
|
||||
func Domain() ValidatorFunc {
|
||||
return func(value any) *ValidationError {
|
||||
|
||||
Reference in New Issue
Block a user