package validator import ( "regexp" "github.com/go-playground/validator/v10" ) var ( validate *validator.Validate uuidRegex = regexp.MustCompile(`^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`) slugRegex = regexp.MustCompile(`^[a-z0-9-]+$`) currencyRegex = regexp.MustCompile(`^[A-Z]{3}$`) ) func init() { validate = validator.New() // Custom validators _ = validate.RegisterValidation("uuid", validateUUID) _ = validate.RegisterValidation("slug", validateSlug) _ = validate.RegisterValidation("latitude", validateLatitude) _ = validate.RegisterValidation("longitude", validateLongitude) _ = validate.RegisterValidation("place_type", validatePlaceType) _ = validate.RegisterValidation("user_role", validateUserRole) _ = validate.RegisterValidation("currency", validateCurrency) _ = validate.RegisterValidation("user_status", validateUserStatus) _ = validate.RegisterValidation("place_status", validatePlaceStatus) _ = validate.RegisterValidation("service_status", validateServiceStatus) _ = validate.RegisterValidation("booking_status", validateBookingStatus) } // Validate validates a struct and returns ValidationErrors if any func Validate(s interface{}) error { return validate.Struct(s) } // ValidateVar validates a single variable func ValidateVar(field interface{}, tag string) error { return validate.Var(field, tag) } // ValidationErrors wraps validator.ValidationErrors for easier handling type ValidationErrors validator.ValidationErrors func (ve ValidationErrors) Error() string { return validator.ValidationErrors(ve).Error() } // FieldErrors returns a map of field -> error message func (ve ValidationErrors) FieldErrors() map[string]string { errs := make(map[string]string) for _, fe := range ve { errs[fe.Field()] = fe.Tag() } return errs } // Custom validators func validateUUID(fl validator.FieldLevel) bool { return uuidRegex.MatchString(fl.Field().String()) } func validateSlug(fl validator.FieldLevel) bool { return slugRegex.MatchString(fl.Field().String()) } func validateLatitude(fl validator.FieldLevel) bool { lat := fl.Field().Float() return lat >= -90 && lat <= 90 } func validateLongitude(fl validator.FieldLevel) bool { lng := fl.Field().Float() return lng >= -180 && lng <= 180 } func validatePlaceType(fl validator.FieldLevel) bool { v := fl.Field().String() return v == "place" || v == "studio" } func validateUserRole(fl validator.FieldLevel) bool { roles := map[string]bool{ "customer": true, "landlord": true, "executor": true, "moderator": true, "superadmin": true, } return roles[fl.Field().String()] } func validateCurrency(fl validator.FieldLevel) bool { return currencyRegex.MatchString(fl.Field().String()) } func validateUserStatus(fl validator.FieldLevel) bool { statuses := map[string]bool{"active": true, "banned": true, "pending_verification": true} return statuses[fl.Field().String()] } func validatePlaceStatus(fl validator.FieldLevel) bool { statuses := map[string]bool{ "draft": true, "pending_moderation": true, "published": true, "rejected": true, "archived": true, } return statuses[fl.Field().String()] } func validateServiceStatus(fl validator.FieldLevel) bool { statuses := map[string]bool{"draft": true, "published": true, "archived": true} return statuses[fl.Field().String()] } func validateBookingStatus(fl validator.FieldLevel) bool { statuses := map[string]bool{"pending": true, "confirmed": true, "cancelled": true, "completed": true} return statuses[fl.Field().String()] }