validator.go 3.9 KB

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