validator.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. // Package validator предоставляет кастомные валидаторы на базе go-playground/validator.
  2. // Реализованы валидации: uuid, slug, latitude, longitude, place_type, user_role,
  3. // currency, user_status, place_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("datetime", validateDateTime)
  30. }
  31. // Validate validates a struct and returns ValidationErrors if any
  32. func Validate(s interface{}) error {
  33. return validate.Struct(s)
  34. }
  35. // ValidateVar validates a single variable
  36. func ValidateVar(field interface{}, tag string) error {
  37. return validate.Var(field, tag)
  38. }
  39. // ValidationErrors — алиас для go-playground/validator.ValidationErrors.
  40. // Позволяет использовать errors.As в хендлерах для проверки ошибок валидации.
  41. type ValidationErrors = validator.ValidationErrors
  42. // Custom validators
  43. func validateUUID(fl validator.FieldLevel) bool {
  44. return uuidRegex.MatchString(fl.Field().String())
  45. }
  46. func validateSlug(fl validator.FieldLevel) bool {
  47. return slugRegex.MatchString(fl.Field().String())
  48. }
  49. func validateLatitude(fl validator.FieldLevel) bool {
  50. lat := fl.Field().Float()
  51. return lat >= -90 && lat <= 90
  52. }
  53. func validateLongitude(fl validator.FieldLevel) bool {
  54. lng := fl.Field().Float()
  55. return lng >= -180 && lng <= 180
  56. }
  57. func validatePlaceType(fl validator.FieldLevel) bool {
  58. v := fl.Field().String()
  59. return v == "place" || v == "studio"
  60. }
  61. func validateUserRole(fl validator.FieldLevel) bool {
  62. roles := map[string]bool{
  63. "customer": true, "landlord": true, "executor": true,
  64. "moderator": true, "superadmin": true,
  65. }
  66. return roles[fl.Field().String()]
  67. }
  68. func validateCurrency(fl validator.FieldLevel) bool {
  69. return currencyRegex.MatchString(fl.Field().String())
  70. }
  71. func validateUserStatus(fl validator.FieldLevel) bool {
  72. statuses := map[string]bool{"active": true, "banned": true, "pending_verification": true}
  73. return statuses[fl.Field().String()]
  74. }
  75. func validatePlaceStatus(fl validator.FieldLevel) bool {
  76. statuses := map[string]bool{
  77. "draft": true, "pending_moderation": true, "published": true,
  78. "rejected": true, "revision": true, "archived": true, "deleted": true,
  79. }
  80. return statuses[fl.Field().String()]
  81. }
  82. func validateDateTime(fl validator.FieldLevel) bool {
  83. _, err := time.Parse(time.RFC3339, fl.Field().String())
  84. return err == nil
  85. }