-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvalidate.go
More file actions
145 lines (119 loc) · 3.45 KB
/
validate.go
File metadata and controls
145 lines (119 loc) · 3.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package napi
import (
"fmt"
"reflect"
"strings"
"unicode"
"github.com/go-playground/locales/en"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
enTranslations "github.com/go-playground/validator/v10/translations/en"
"github.com/gofiber/fiber/v2"
)
type CanValidate struct{}
func (v CanValidate) Validate(c *fiber.Ctx, req interface{}) *ValidationError {
_ = c.BodyParser(req)
if vErr := validateRequest(req); vErr != nil {
return &ValidationError{bag: vErr}
}
return nil
}
type errorBag map[string]string
type ValidationError struct {
error error
bag errorBag
}
func (ve ValidationError) Error() map[string]string {
if len(ve.bag) > 0 {
return ve.bag
}
return errorBag{"error": ve.error.Error()}
}
// //////////////////////
// ERROR TRANSLATIONS
// //////////////////////
var (
errStartsWith string = "{0} must start with '{1}'"
passwordErrorMessage = "Password must contain an uppercase letter and a number"
)
//var validate *validator.Validate
func validateRequest[T any](s T) map[string]string {
validate := validator.New()
_ = validate.RegisterValidation("password", validatePassword)
validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
if name == "-" {
return ""
}
return name
})
english := en.New()
uni := ut.New(english, english)
trans, _ := uni.GetTranslator("en")
// Register the custom error message for the password validation function
if err := validate.RegisterTranslation("password", trans, func(ut ut.Translator) error {
return ut.Add("password", passwordErrorMessage, true)
}, func(ut ut.Translator, fe validator.FieldError) string {
t, _ := ut.T("password", fe.Field())
return t
}); err != nil {
// FIXME: don't leave this
panic(err)
}
_ = enTranslations.RegisterDefaultTranslations(validate, trans)
addTranslation(validate, trans, "startswith", errStartsWith)
err := validate.Struct(s)
if err != nil {
return translateError(err, trans)
}
return nil
}
func addTranslation(validate *validator.Validate, trans ut.Translator, tag string, errMessage string) {
registerFn := func(ut ut.Translator) error {
return ut.Add(tag, errMessage, false)
}
transFn := func(ut ut.Translator, fe validator.FieldError) string {
param := fe.Param()
tag := fe.Tag()
t, err := ut.T(tag, fe.Field(), param)
if err != nil {
return fe.(error).Error()
}
return t
}
_ = validate.RegisterTranslation(tag, trans, registerFn, transFn)
}
func translateError(err error, trans ut.Translator) (errs map[string]string) {
if err == nil {
return nil
}
errs = make(map[string]string, 0)
validatorErrs := err.(validator.ValidationErrors)
for _, e := range validatorErrs {
translatedErr := fmt.Errorf(e.Translate(trans))
msg := strings.Replace(translatedErr.Error(), e.Field(), ToCamelCase(e.Field()), -1)
errs[e.Field()] = msg
//errs = append(errs, dtos.NewFieldError(e.Field(), e.Value(), msg))
}
return errs
}
func validatePassword(fl validator.FieldLevel) bool {
password := fl.Field().String()
// Check if password contains at least one number
hasNumber := false
for _, char := range password {
if unicode.IsNumber(char) {
hasNumber = true
break
}
}
// Check if password contains at least one upper case letter
hasUpperCase := false
for _, char := range password {
if unicode.IsUpper(char) {
hasUpperCase = true
break
}
}
return hasNumber && hasUpperCase
}