mirror of
https://github.com/Dvorinka/Primora.git
synced 2026-06-04 04:23:00 +00:00
179 lines
4.3 KiB
Go
179 lines
4.3 KiB
Go
package validation
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
var (
|
|
// SlugRegex matches valid slugs (lowercase alphanumeric with hyphens)
|
|
SlugRegex = regexp.MustCompile(`^[a-z0-9]+(?:-[a-z0-9]+)*$`)
|
|
|
|
// EmailRegex matches valid email addresses
|
|
EmailRegex = regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)
|
|
|
|
// BucketNameRegex matches valid bucket names
|
|
BucketNameRegex = regexp.MustCompile(`^[a-z0-9][a-z0-9-]*[a-z0-9]$`)
|
|
)
|
|
|
|
// ValidationError represents a validation error
|
|
type ValidationError struct {
|
|
Field string `json:"field"`
|
|
Message string `json:"message"`
|
|
}
|
|
|
|
// Error implements the error interface
|
|
func (ve ValidationError) Error() string {
|
|
return fmt.Sprintf("%s: %s", ve.Field, ve.Message)
|
|
}
|
|
|
|
// ValidationErrors is a collection of validation errors
|
|
type ValidationErrors []ValidationError
|
|
|
|
// Error implements the error interface
|
|
func (ve ValidationErrors) Error() string {
|
|
if len(ve) == 0 {
|
|
return ""
|
|
}
|
|
|
|
var messages []string
|
|
for _, err := range ve {
|
|
messages = append(messages, err.Error())
|
|
}
|
|
return strings.Join(messages, "; ")
|
|
}
|
|
|
|
// Validator provides validation functions
|
|
type Validator struct {
|
|
errors ValidationErrors
|
|
}
|
|
|
|
// New creates a new validator
|
|
func New() *Validator {
|
|
return &Validator{
|
|
errors: make(ValidationErrors, 0),
|
|
}
|
|
}
|
|
|
|
// Required checks if a field is not empty
|
|
func (v *Validator) Required(field, value string) *Validator {
|
|
if strings.TrimSpace(value) == "" {
|
|
v.errors = append(v.errors, ValidationError{
|
|
Field: field,
|
|
Message: "is required",
|
|
})
|
|
}
|
|
return v
|
|
}
|
|
|
|
// MinLength checks if a field meets minimum length
|
|
func (v *Validator) MinLength(field, value string, min int) *Validator {
|
|
if len(value) < min {
|
|
v.errors = append(v.errors, ValidationError{
|
|
Field: field,
|
|
Message: fmt.Sprintf("must be at least %d characters", min),
|
|
})
|
|
}
|
|
return v
|
|
}
|
|
|
|
// MaxLength checks if a field doesn't exceed maximum length
|
|
func (v *Validator) MaxLength(field, value string, max int) *Validator {
|
|
if len(value) > max {
|
|
v.errors = append(v.errors, ValidationError{
|
|
Field: field,
|
|
Message: fmt.Sprintf("must not exceed %d characters", max),
|
|
})
|
|
}
|
|
return v
|
|
}
|
|
|
|
// Email checks if a field is a valid email
|
|
func (v *Validator) Email(field, value string) *Validator {
|
|
if value != "" && !EmailRegex.MatchString(value) {
|
|
v.errors = append(v.errors, ValidationError{
|
|
Field: field,
|
|
Message: "must be a valid email address",
|
|
})
|
|
}
|
|
return v
|
|
}
|
|
|
|
// Slug checks if a field is a valid slug
|
|
func (v *Validator) Slug(field, value string) *Validator {
|
|
if value != "" && !SlugRegex.MatchString(value) {
|
|
v.errors = append(v.errors, ValidationError{
|
|
Field: field,
|
|
Message: "must be a valid slug (lowercase letters, numbers, and hyphens)",
|
|
})
|
|
}
|
|
return v
|
|
}
|
|
|
|
// BucketName checks if a field is a valid bucket name
|
|
func (v *Validator) BucketName(field, value string) *Validator {
|
|
if value != "" {
|
|
if !BucketNameRegex.MatchString(value) {
|
|
v.errors = append(v.errors, ValidationError{
|
|
Field: field,
|
|
Message: "must be a valid bucket name (lowercase letters, numbers, and hyphens, cannot start or end with hyphen)",
|
|
})
|
|
}
|
|
if len(value) < 3 || len(value) > 63 {
|
|
v.errors = append(v.errors, ValidationError{
|
|
Field: field,
|
|
Message: "must be between 3 and 63 characters",
|
|
})
|
|
}
|
|
}
|
|
return v
|
|
}
|
|
|
|
// OneOf checks if a field value is one of the allowed values
|
|
func (v *Validator) OneOf(field, value string, allowed []string) *Validator {
|
|
if value != "" {
|
|
found := false
|
|
for _, a := range allowed {
|
|
if value == a {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
v.errors = append(v.errors, ValidationError{
|
|
Field: field,
|
|
Message: fmt.Sprintf("must be one of: %s", strings.Join(allowed, ", ")),
|
|
})
|
|
}
|
|
}
|
|
return v
|
|
}
|
|
|
|
// Custom adds a custom validation error
|
|
func (v *Validator) Custom(field, message string) *Validator {
|
|
v.errors = append(v.errors, ValidationError{
|
|
Field: field,
|
|
Message: message,
|
|
})
|
|
return v
|
|
}
|
|
|
|
// Valid returns true if there are no validation errors
|
|
func (v *Validator) Valid() bool {
|
|
return len(v.errors) == 0
|
|
}
|
|
|
|
// Errors returns all validation errors
|
|
func (v *Validator) Errors() ValidationErrors {
|
|
return v.errors
|
|
}
|
|
|
|
// FirstError returns the first validation error or nil
|
|
func (v *Validator) FirstError() error {
|
|
if len(v.errors) > 0 {
|
|
return v.errors[0]
|
|
}
|
|
return nil
|
|
}
|