validator.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. package validator
  2. import (
  3. "regexp"
  4. "github.com/go-playground/validator/v10"
  5. )
  6. var (
  7. validate *validator.Validate
  8. uuidRegex = regexp.MustCompile(`^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`)
  9. slugRegex = regexp.MustCompile(`^[a-z0-9-]+$`)
  10. currencyRegex = regexp.MustCompile(`^[A-Z]{3}$`)
  11. )
  12. func init() {
  13. validate = validator.New()
  14. // Custom validators
  15. _ = validate.RegisterValidation("uuid", validateUUID)
  16. _ = validate.RegisterValidation("slug", validateSlug)
  17. _ = validate.RegisterValidation("latitude", validateLatitude)
  18. _ = validate.RegisterValidation("longitude", validateLongitude)
  19. _ = validate.RegisterValidation("place_type", validatePlaceType)
  20. _ = validate.RegisterValidation("user_role", validateUserRole)
  21. _ = validate.RegisterValidation("currency", validateCurrency)
  22. _ = validate.RegisterValidation("user_status", validateUserStatus)
  23. _ = validate.RegisterValidation("place_status", validatePlaceStatus)
  24. _ = validate.RegisterValidation("service_status", validateServiceStatus)
  25. _ = validate.RegisterValidation("booking_status", validateBookingStatus)
  26. }
  27. // Validate validates a struct and returns ValidationErrors if any
  28. func Validate(s interface{}) error {
  29. return validate.Struct(s)
  30. }
  31. // ValidateVar validates a single variable
  32. func ValidateVar(field interface{}, tag string) error {
  33. return validate.Var(field, tag)
  34. }
  35. // ValidationErrors wraps validator.ValidationErrors for easier handling
  36. type ValidationErrors validator.ValidationErrors
  37. func (ve ValidationErrors) Error() string {
  38. return validator.ValidationErrors(ve).Error()
  39. }
  40. // FieldErrors returns a map of field -> error message
  41. func (ve ValidationErrors) FieldErrors() map[string]string {
  42. errs := make(map[string]string)
  43. for _, fe := range ve {
  44. errs[fe.Field()] = fe.Tag()
  45. }
  46. return errs
  47. }
  48. // Custom validators
  49. func validateUUID(fl validator.FieldLevel) bool {
  50. return uuidRegex.MatchString(fl.Field().String())
  51. }
  52. func validateSlug(fl validator.FieldLevel) bool {
  53. return slugRegex.MatchString(fl.Field().String())
  54. }
  55. func validateLatitude(fl validator.FieldLevel) bool {
  56. lat := fl.Field().Float()
  57. return lat >= -90 && lat <= 90
  58. }
  59. func validateLongitude(fl validator.FieldLevel) bool {
  60. lng := fl.Field().Float()
  61. return lng >= -180 && lng <= 180
  62. }
  63. func validatePlaceType(fl validator.FieldLevel) bool {
  64. v := fl.Field().String()
  65. return v == "place" || v == "studio"
  66. }
  67. func validateUserRole(fl validator.FieldLevel) bool {
  68. roles := map[string]bool{
  69. "customer": true, "landlord": true, "executor": true,
  70. "moderator": true, "superadmin": true,
  71. }
  72. return roles[fl.Field().String()]
  73. }
  74. func validateCurrency(fl validator.FieldLevel) bool {
  75. return currencyRegex.MatchString(fl.Field().String())
  76. }
  77. func validateUserStatus(fl validator.FieldLevel) bool {
  78. statuses := map[string]bool{"active": true, "banned": true, "pending_verification": true}
  79. return statuses[fl.Field().String()]
  80. }
  81. func validatePlaceStatus(fl validator.FieldLevel) bool {
  82. statuses := map[string]bool{
  83. "draft": true, "pending_moderation": true, "published": true,
  84. "rejected": true, "archived": true,
  85. }
  86. return statuses[fl.Field().String()]
  87. }
  88. func validateServiceStatus(fl validator.FieldLevel) bool {
  89. statuses := map[string]bool{"draft": true, "published": true, "archived": true}
  90. return statuses[fl.Field().String()]
  91. }
  92. func validateBookingStatus(fl validator.FieldLevel) bool {
  93. statuses := map[string]bool{"pending": true, "confirmed": true, "cancelled": true, "completed": true}
  94. return statuses[fl.Field().String()]
  95. }