validator.go 3.7 KB

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