diff --git a/go.mod b/go.mod index 3b308eb6..8acf290e 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/dromara/carbon/v2 v2.6.11 github.com/eclipse/paho.mqtt.golang v1.5.0 github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df - github.com/go-playground/validator/v10 v10.26.0 + github.com/go-playground/validator/v10 v10.27.0 github.com/gregdel/pushover v1.3.1 github.com/hashicorp/nomad/api v0.0.0-20231213195942-64e3dca9274b // v1.7.2 github.com/jedib0t/go-pretty/v6 v6.6.7 diff --git a/go.sum b/go.sum index 8cd92ce4..c586b69b 100644 --- a/go.sum +++ b/go.sum @@ -130,8 +130,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= -github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= +github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4= +github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= diff --git a/vendor/github.com/go-playground/validator/v10/.golangci.yaml b/vendor/github.com/go-playground/validator/v10/.golangci.yaml index eab557ee..dd9c05cc 100644 --- a/vendor/github.com/go-playground/validator/v10/.golangci.yaml +++ b/vendor/github.com/go-playground/validator/v10/.golangci.yaml @@ -2,101 +2,53 @@ version: "2" linters: default: all disable: - - asasalint - - asciicheck - - bidichk - - bodyclose - - canonicalheader - - containedctx - - contextcheck + - noinlineerr + - wsl_v5 - copyloopvar - cyclop - - decorder - depguard - dogsled - dupl - dupword - - durationcheck - err113 - - errcheck - - errchkjson - - errname - errorlint - exhaustive - exhaustruct - - exptostd - - fatcontext - forbidigo - forcetypeassert - funlen - - ginkgolinter - - gocheckcompilerdirectives - gochecknoglobals - - gochecknoinits - - gochecksumtype - gocognit - goconst - gocritic - gocyclo - godot - - godox - - goheader - - gomoddirectives - - gomodguard - - goprintffuncname - gosec - gosmopolitan - - govet - - grouper - - iface - - importas - - inamedparam - - ineffassign - interfacebloat - intrange - ireturn - lll - - loggercheck - maintidx - - makezero - - mirror - misspell - mnd - - musttag - nakedret - nestif - - nilerr - - nilnesserr - nilnil - nlreturn - - noctx - - nolintlint - nonamedreturns - - nosprintfhostport - paralleltest - perfsprint - prealloc - - predeclared - - promlinter - - protogetter - - reassign - recvcheck - revive - - rowserrcheck - - sloglint - - spancheck - - sqlclosecheck - staticcheck - tagalign - tagliatelle - - testableexamples - - testifylint - testpackage - thelper - tparallel - unparam - varnamelen - - whitespace - wrapcheck - wsl - - zerologlint \ No newline at end of file diff --git a/vendor/github.com/go-playground/validator/v10/README.md b/vendor/github.com/go-playground/validator/v10/README.md index 368b966a..28f7e159 100644 --- a/vendor/github.com/go-playground/validator/v10/README.md +++ b/vendor/github.com/go-playground/validator/v10/README.md @@ -1,6 +1,6 @@ Package validator ================= -![Project status](https://img.shields.io/badge/version-10.25.0-green.svg) +[![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/go-playground/validator)](https://github.com/go-playground/validator/releases) [![Build Status](https://github.com/go-playground/validator/actions/workflows/workflow.yml/badge.svg)](https://github.com/go-playground/validator/actions) [![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=master&service=github)](https://coveralls.io/github/go-playground/validator?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator) @@ -262,6 +262,8 @@ validate := validator.New(validator.WithRequiredStructEnabled()) | excluded_without | Excluded Without | | excluded_without_all | Excluded Without All | | unique | Unique | +| validateFn | Verify if the method `Validate() error` does not return an error (or any specified method) | + #### Aliases: | Tag | Description | diff --git a/vendor/github.com/go-playground/validator/v10/baked_in.go b/vendor/github.com/go-playground/validator/v10/baked_in.go index 5332cf3f..c968ad4a 100644 --- a/vendor/github.com/go-playground/validator/v10/baked_in.go +++ b/vendor/github.com/go-playground/validator/v10/baked_in.go @@ -2,10 +2,12 @@ package validator import ( "bytes" + "cmp" "context" "crypto/sha256" "encoding/hex" "encoding/json" + "errors" "fmt" "io/fs" "net" @@ -244,6 +246,7 @@ var ( "cron": isCron, "spicedb": isSpiceDB, "ein": isEIN, + "validateFn": isValidateFn, } ) @@ -294,7 +297,7 @@ func isOneOf(fl FieldLevel) bool { case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: v = strconv.FormatUint(field.Uint(), 10) default: - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } for i := 0; i < len(vals); i++ { if vals[i] == v { @@ -310,7 +313,7 @@ func isOneOfCI(fl FieldLevel) bool { field := fl.Field() if field.Kind() != reflect.String { - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } v := field.String() for _, val := range vals { @@ -384,13 +387,13 @@ func isUnique(fl FieldLevel) bool { } if uniqueField.Kind() != field.Kind() { - panic(fmt.Sprintf("Bad field type %T:%T", field.Interface(), uniqueField.Interface())) + panic(fmt.Sprintf("Bad field type %s:%s", field.Type(), uniqueField.Type())) } - return field.Interface() != uniqueField.Interface() + return getValue(field) != getValue(uniqueField) } - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } } @@ -471,7 +474,7 @@ func isLongitude(fl FieldLevel) bool { case reflect.Float64: v = strconv.FormatFloat(field.Float(), 'f', -1, 64) default: - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } return longitudeRegex().MatchString(v) @@ -494,7 +497,7 @@ func isLatitude(fl FieldLevel) bool { case reflect.Float64: v = strconv.FormatFloat(field.Float(), 'f', -1, 64) default: - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } return latitudeRegex().MatchString(v) @@ -945,7 +948,6 @@ func isNeField(fl FieldLevel) bool { } switch kind { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() != currentField.Int() @@ -966,9 +968,8 @@ func isNeField(fl FieldLevel) bool { fieldType := field.Type() if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) { - - t := currentField.Interface().(time.Time) - fieldTime := field.Interface().(time.Time) + t := getValue(currentField).(time.Time) + fieldTime := getValue(field).(time.Time) return !fieldTime.Equal(t) } @@ -1005,7 +1006,6 @@ func isLteCrossStructField(fl FieldLevel) bool { } switch kind { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() <= topField.Int() @@ -1023,9 +1023,8 @@ func isLteCrossStructField(fl FieldLevel) bool { fieldType := field.Type() if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) { - - fieldTime := field.Convert(timeType).Interface().(time.Time) - topTime := topField.Convert(timeType).Interface().(time.Time) + fieldTime := getValue(field.Convert(timeType)).(time.Time) + topTime := getValue(topField.Convert(timeType)).(time.Time) return fieldTime.Before(topTime) || fieldTime.Equal(topTime) } @@ -1052,7 +1051,6 @@ func isLtCrossStructField(fl FieldLevel) bool { } switch kind { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() < topField.Int() @@ -1070,9 +1068,8 @@ func isLtCrossStructField(fl FieldLevel) bool { fieldType := field.Type() if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) { - - fieldTime := field.Convert(timeType).Interface().(time.Time) - topTime := topField.Convert(timeType).Interface().(time.Time) + fieldTime := getValue(field.Convert(timeType)).(time.Time) + topTime := getValue(topField.Convert(timeType)).(time.Time) return fieldTime.Before(topTime) } @@ -1098,7 +1095,6 @@ func isGteCrossStructField(fl FieldLevel) bool { } switch kind { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() >= topField.Int() @@ -1116,9 +1112,8 @@ func isGteCrossStructField(fl FieldLevel) bool { fieldType := field.Type() if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) { - - fieldTime := field.Convert(timeType).Interface().(time.Time) - topTime := topField.Convert(timeType).Interface().(time.Time) + fieldTime := getValue(field.Convert(timeType)).(time.Time) + topTime := getValue(topField.Convert(timeType)).(time.Time) return fieldTime.After(topTime) || fieldTime.Equal(topTime) } @@ -1144,7 +1139,6 @@ func isGtCrossStructField(fl FieldLevel) bool { } switch kind { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() > topField.Int() @@ -1162,9 +1156,8 @@ func isGtCrossStructField(fl FieldLevel) bool { fieldType := field.Type() if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) { - - fieldTime := field.Convert(timeType).Interface().(time.Time) - topTime := topField.Convert(timeType).Interface().(time.Time) + fieldTime := getValue(field.Convert(timeType)).(time.Time) + topTime := getValue(topField.Convert(timeType)).(time.Time) return fieldTime.After(topTime) } @@ -1190,7 +1183,6 @@ func isNeCrossStructField(fl FieldLevel) bool { } switch kind { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return topField.Int() != field.Int() @@ -1211,9 +1203,8 @@ func isNeCrossStructField(fl FieldLevel) bool { fieldType := field.Type() if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) { - - t := field.Convert(timeType).Interface().(time.Time) - fieldTime := topField.Convert(timeType).Interface().(time.Time) + t := getValue(field.Convert(timeType)).(time.Time) + fieldTime := getValue(topField.Convert(timeType)).(time.Time) return !fieldTime.Equal(t) } @@ -1239,7 +1230,6 @@ func isEqCrossStructField(fl FieldLevel) bool { } switch kind { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return topField.Int() == field.Int() @@ -1260,9 +1250,8 @@ func isEqCrossStructField(fl FieldLevel) bool { fieldType := field.Type() if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) { - - t := field.Convert(timeType).Interface().(time.Time) - fieldTime := topField.Convert(timeType).Interface().(time.Time) + t := getValue(field.Convert(timeType)).(time.Time) + fieldTime := getValue(topField.Convert(timeType)).(time.Time) return fieldTime.Equal(t) } @@ -1288,7 +1277,6 @@ func isEqField(fl FieldLevel) bool { } switch kind { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() == currentField.Int() @@ -1309,9 +1297,8 @@ func isEqField(fl FieldLevel) bool { fieldType := field.Type() if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) { - - t := currentField.Convert(timeType).Interface().(time.Time) - fieldTime := field.Convert(timeType).Interface().(time.Time) + t := getValue(currentField.Convert(timeType)).(time.Time) + fieldTime := getValue(field.Convert(timeType)).(time.Time) return fieldTime.Equal(t) } @@ -1332,7 +1319,6 @@ func isEq(fl FieldLevel) bool { param := fl.Param() switch field.Kind() { - case reflect.String: return field.String() == param @@ -1367,7 +1353,7 @@ func isEq(fl FieldLevel) bool { return field.Bool() == p } - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } // isEqIgnoreCase is the validation function for validating if the current field's string value is @@ -1382,7 +1368,7 @@ func isEqIgnoreCase(fl FieldLevel) bool { return strings.EqualFold(field.String(), param) } - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } // isPostcodeByIso3166Alpha2 validates by value which is country code in iso 3166 alpha 2 @@ -1416,7 +1402,7 @@ func isPostcodeByIso3166Alpha2Field(fl FieldLevel) bool { } if kind != reflect.String { - panic(fmt.Sprintf("Bad field type %T", currentField.Interface())) + panic(fmt.Sprintf("Bad field type %s", currentField.Type())) } postcodeRegexInit.Do(initPostcodes) @@ -1472,16 +1458,7 @@ func isURI(fl FieldLevel) bool { return err == nil } - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// isFileURL is the helper function for validating if the `path` valid file URL as per RFC8089 -func isFileURL(path string) bool { - if !strings.HasPrefix(path, "file:/") { - return false - } - _, err := url.ParseRequestURI(path) - return err == nil + panic(fmt.Sprintf("Bad field type %s", field.Type())) } // isURL is the validation function for validating if the current field's value is a valid URL. @@ -1497,23 +1474,20 @@ func isURL(fl FieldLevel) bool { return false } - if isFileURL(s) { - return true - } - url, err := url.Parse(s) if err != nil || url.Scheme == "" { return false } + isFileScheme := url.Scheme == "file" - if url.Host == "" && url.Fragment == "" && url.Opaque == "" { + if (isFileScheme && (len(url.Path) == 0 || url.Path == "/")) || (!isFileScheme && len(url.Host) == 0 && len(url.Fragment) == 0 && len(url.Opaque) == 0) { return false } return true } - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } // isHttpURL is the validation function for validating if the current field's value is a valid HTTP(s) URL. @@ -1536,7 +1510,7 @@ func isHttpURL(fl FieldLevel) bool { return url.Scheme == "http" || url.Scheme == "https" } - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } // isUrnRFC2141 is the validation function for validating if the current field's value is a valid URN as per RFC 2141. @@ -1553,7 +1527,7 @@ func isUrnRFC2141(fl FieldLevel) bool { return match } - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } // isFile is the validation function for validating if the current field's value is a valid existing file path. @@ -1570,7 +1544,7 @@ func isFile(fl FieldLevel) bool { return !fileInfo.IsDir() } - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } // isImage is the validation function for validating if the current field's value contains the path to a valid image file @@ -1632,7 +1606,8 @@ func isImage(fl FieldLevel) bool { return true } } - return false + + panic(fmt.Sprintf("Bad field type %s", field.Type())) } // isFilePath is the validation function for validating if the current field's value is a valid file path. @@ -1686,7 +1661,7 @@ func isFilePath(fl FieldLevel) bool { } } - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } // isE164 is the validation function for validating if the current field's value is a valid e.164 formatted phone number. @@ -1796,7 +1771,7 @@ func hasValue(fl FieldLevel) bool { case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func: return !field.IsNil() default: - if fl.(*validate).fldIsPointer && field.Interface() != nil { + if fl.(*validate).fldIsPointer && getValue(field) != nil { return true } return field.IsValid() && !field.IsZero() @@ -1807,10 +1782,13 @@ func hasValue(fl FieldLevel) bool { func hasNotZeroValue(fl FieldLevel) bool { field := fl.Field() switch field.Kind() { - case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func: + case reflect.Slice, reflect.Map: + // For slices and maps, consider them "not zero" only if they're both non-nil AND have elements + return !field.IsNil() && field.Len() > 0 + case reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func: return !field.IsNil() default: - if fl.(*validate).fldIsPointer && field.Interface() != nil { + if fl.(*validate).fldIsPointer && getValue(field) != nil { return !field.IsZero() } return field.IsValid() && !field.IsZero() @@ -1834,7 +1812,7 @@ func requireCheckFieldKind(fl FieldLevel, param string, defaultNotFoundValue boo case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func: return field.IsNil() default: - if nullable && field.Interface() != nil { + if nullable && getValue(field) != nil { return false } return field.IsValid() && field.IsZero() @@ -1851,7 +1829,6 @@ func requireCheckFieldValue( } switch kind { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() == asInt(value) @@ -1864,7 +1841,13 @@ func requireCheckFieldValue( case reflect.Float64: return field.Float() == asFloat64(value) - case reflect.Slice, reflect.Map, reflect.Array: + case reflect.Slice, reflect.Map: + if value == "nil" { + return field.IsNil() + } + return int64(field.Len()) == asInt(value) + case reflect.Array: + // Arrays can't be nil, so only compare lengths return int64(field.Len()) == asInt(value) case reflect.Bool: @@ -2019,8 +2002,11 @@ func excludedWithout(fl FieldLevel) bool { // requiredWithout is the validation function // The field under validation must be present and not empty only when any of the other specified fields are not present. func requiredWithout(fl FieldLevel) bool { - if requireCheckFieldKind(fl, strings.TrimSpace(fl.Param()), true) { - return hasValue(fl) + params := parseOneOfParam2(fl.Param()) + for _, param := range params { + if requireCheckFieldKind(fl, param, true) { + return hasValue(fl) + } } return true } @@ -2060,7 +2046,6 @@ func isGteField(fl FieldLevel) bool { } switch kind { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() >= currentField.Int() @@ -2078,9 +2063,8 @@ func isGteField(fl FieldLevel) bool { fieldType := field.Type() if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) { - - t := currentField.Convert(timeType).Interface().(time.Time) - fieldTime := field.Convert(timeType).Interface().(time.Time) + t := getValue(currentField.Convert(timeType)).(time.Time) + fieldTime := getValue(field.Convert(timeType)).(time.Time) return fieldTime.After(t) || fieldTime.Equal(t) } @@ -2106,7 +2090,6 @@ func isGtField(fl FieldLevel) bool { } switch kind { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() > currentField.Int() @@ -2124,9 +2107,8 @@ func isGtField(fl FieldLevel) bool { fieldType := field.Type() if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) { - - t := currentField.Convert(timeType).Interface().(time.Time) - fieldTime := field.Convert(timeType).Interface().(time.Time) + t := getValue(currentField.Convert(timeType)).(time.Time) + fieldTime := getValue(field.Convert(timeType)).(time.Time) return fieldTime.After(t) } @@ -2147,7 +2129,6 @@ func isGte(fl FieldLevel) bool { param := fl.Param() switch field.Kind() { - case reflect.String: p := asInt(param) @@ -2181,15 +2162,14 @@ func isGte(fl FieldLevel) bool { case reflect.Struct: if field.Type().ConvertibleTo(timeType) { - now := time.Now().UTC() - t := field.Convert(timeType).Interface().(time.Time) + t := getValue(field.Convert(timeType)).(time.Time) return t.After(now) || t.Equal(now) } } - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } // isGt is the validation function for validating if the current field's value is greater than the param's value. @@ -2198,7 +2178,6 @@ func isGt(fl FieldLevel) bool { param := fl.Param() switch field.Kind() { - case reflect.String: p := asInt(param) @@ -2232,11 +2211,11 @@ func isGt(fl FieldLevel) bool { case reflect.Struct: if field.Type().ConvertibleTo(timeType) { - return field.Convert(timeType).Interface().(time.Time).After(time.Now().UTC()) + return getValue(field.Convert(timeType)).(time.Time).After(time.Now().UTC()) } } - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } // hasLengthOf is the validation function for validating if the current field's value is equal to the param's value. @@ -2245,7 +2224,6 @@ func hasLengthOf(fl FieldLevel) bool { param := fl.Param() switch field.Kind() { - case reflect.String: p := asInt(param) @@ -2277,7 +2255,7 @@ func hasLengthOf(fl FieldLevel) bool { return field.Float() == p } - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } // hasMinOf is the validation function for validating if the current field's value is greater than or equal to the param's value. @@ -2296,7 +2274,6 @@ func isLteField(fl FieldLevel) bool { } switch kind { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() <= currentField.Int() @@ -2314,9 +2291,8 @@ func isLteField(fl FieldLevel) bool { fieldType := field.Type() if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) { - - t := currentField.Convert(timeType).Interface().(time.Time) - fieldTime := field.Convert(timeType).Interface().(time.Time) + t := getValue(currentField.Convert(timeType)).(time.Time) + fieldTime := getValue(field.Convert(timeType)).(time.Time) return fieldTime.Before(t) || fieldTime.Equal(t) } @@ -2342,7 +2318,6 @@ func isLtField(fl FieldLevel) bool { } switch kind { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() < currentField.Int() @@ -2360,9 +2335,8 @@ func isLtField(fl FieldLevel) bool { fieldType := field.Type() if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) { - - t := currentField.Convert(timeType).Interface().(time.Time) - fieldTime := field.Convert(timeType).Interface().(time.Time) + t := getValue(currentField.Convert(timeType)).(time.Time) + fieldTime := getValue(field.Convert(timeType)).(time.Time) return fieldTime.Before(t) } @@ -2383,7 +2357,6 @@ func isLte(fl FieldLevel) bool { param := fl.Param() switch field.Kind() { - case reflect.String: p := asInt(param) @@ -2417,15 +2390,14 @@ func isLte(fl FieldLevel) bool { case reflect.Struct: if field.Type().ConvertibleTo(timeType) { - now := time.Now().UTC() - t := field.Convert(timeType).Interface().(time.Time) + t := getValue(field.Convert(timeType)).(time.Time) return t.Before(now) || t.Equal(now) } } - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } // isLt is the validation function for validating if the current field's value is less than the param's value. @@ -2434,7 +2406,6 @@ func isLt(fl FieldLevel) bool { param := fl.Param() switch field.Kind() { - case reflect.String: p := asInt(param) @@ -2468,11 +2439,11 @@ func isLt(fl FieldLevel) bool { case reflect.Struct: if field.Type().ConvertibleTo(timeType) { - return field.Convert(timeType).Interface().(time.Time).Before(time.Now().UTC()) + return getValue(field.Convert(timeType)).(time.Time).Before(time.Now().UTC()) } } - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } // hasMaxOf is the validation function for validating if the current field's value is less than or equal to the param's value. @@ -2642,7 +2613,7 @@ func isDir(fl FieldLevel) bool { return fileInfo.IsDir() } - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } // isDirPath is the validation function for validating if the current field's value is a valid directory. @@ -2699,7 +2670,7 @@ func isDirPath(fl FieldLevel) bool { } } - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } // isJSON is the validation function for validating if the current field's value is a valid json string. @@ -2714,12 +2685,12 @@ func isJSON(fl FieldLevel) bool { fieldType := field.Type() if fieldType.ConvertibleTo(byteSliceType) { - b := field.Convert(byteSliceType).Interface().([]byte) + b := getValue(field.Convert(byteSliceType)).([]byte) return json.Valid(b) } } - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } // isJWT is the validation function for validating if the current field's value is a valid JWT string. @@ -2766,7 +2737,7 @@ func isLowercase(fl FieldLevel) bool { return field.String() == strings.ToLower(field.String()) } - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } // isUppercase is the validation function for validating if the current field's value is an uppercase string. @@ -2780,7 +2751,7 @@ func isUppercase(fl FieldLevel) bool { return field.String() == strings.ToUpper(field.String()) } - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } // isDatetime is the validation function for validating if the current field's value is a valid datetime string. @@ -2794,7 +2765,7 @@ func isDatetime(fl FieldLevel) bool { return err == nil } - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } // isTimeZone is the validation function for validating if the current field's value is a valid time zone string. @@ -2816,7 +2787,7 @@ func isTimeZone(fl FieldLevel) bool { return err == nil } - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } // isIso3166Alpha2 is the validation function for validating if the current field's value is a valid iso3166-1 alpha-2 country code. @@ -2860,7 +2831,7 @@ func isIso3166AlphaNumeric(fl FieldLevel) bool { case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: code = int(field.Uint() % 1000) default: - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } _, ok := iso3166_1_alpha_numeric[code] @@ -2884,7 +2855,7 @@ func isIso3166AlphaNumericEU(fl FieldLevel) bool { case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: code = int(field.Uint() % 1000) default: - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } _, ok := iso3166_1_alpha_numeric_eu[code] @@ -2914,7 +2885,7 @@ func isIso4217Numeric(fl FieldLevel) bool { case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: code = int(field.Uint()) default: - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } _, ok := iso4217_numeric[code] @@ -2930,7 +2901,7 @@ func isBCP47LanguageTag(fl FieldLevel) bool { return err == nil } - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } // isIsoBicFormat is the validation function for validating if the current field's value is a valid Business Identifier Code (SWIFT code), defined in ISO 9362 @@ -3053,7 +3024,7 @@ func hasLuhnChecksum(fl FieldLevel) bool { case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: str = strconv.FormatUint(field.Uint(), 10) default: - panic(fmt.Sprintf("Bad field type %T", field.Interface())) + panic(fmt.Sprintf("Bad field type %s", field.Type())) } size := len(str) if size < 2 { // there has to be at least one digit that carries a meaning + the checksum @@ -3079,3 +3050,60 @@ func isEIN(fl FieldLevel) bool { return einRegex().MatchString(field.String()) } + +func isValidateFn(fl FieldLevel) bool { + const defaultParam = `Validate` + + field := fl.Field() + validateFn := cmp.Or(fl.Param(), defaultParam) + + ok, err := tryCallValidateFn(field, validateFn) + if err != nil { + return false + } + + return ok +} + +var ( + errMethodNotFound = errors.New(`method not found`) + errMethodReturnNoValues = errors.New(`method return o values (void)`) + errMethodReturnInvalidType = errors.New(`method should return invalid type`) +) + +func tryCallValidateFn(field reflect.Value, validateFn string) (bool, error) { + method := field.MethodByName(validateFn) + if field.CanAddr() && !method.IsValid() { + method = field.Addr().MethodByName(validateFn) + } + + if !method.IsValid() { + return false, fmt.Errorf("unable to call %q on type %q: %w", + validateFn, field.Type().String(), errMethodNotFound) + } + + returnValues := method.Call([]reflect.Value{}) + if len(returnValues) == 0 { + return false, fmt.Errorf("unable to use result of method %q on type %q: %w", + validateFn, field.Type().String(), errMethodReturnNoValues) + } + + firstReturnValue := returnValues[0] + + switch firstReturnValue.Kind() { + case reflect.Bool: + return firstReturnValue.Bool(), nil + case reflect.Interface: + errorType := reflect.TypeOf((*error)(nil)).Elem() + + if firstReturnValue.Type().Implements(errorType) { + return firstReturnValue.IsNil(), nil + } + + return false, fmt.Errorf("unable to use result of method %q on type %q: %w (got interface %v expect error)", + validateFn, field.Type().String(), errMethodReturnInvalidType, firstReturnValue.Type().String()) + default: + return false, fmt.Errorf("unable to use result of method %q on type %q: %w (got %v expect error or bool)", + validateFn, field.Type().String(), errMethodReturnInvalidType, firstReturnValue.Type().String()) + } +} diff --git a/vendor/github.com/go-playground/validator/v10/cache.go b/vendor/github.com/go-playground/validator/v10/cache.go index 41d40bfe..fb101b06 100644 --- a/vendor/github.com/go-playground/validator/v10/cache.go +++ b/vendor/github.com/go-playground/validator/v10/cache.go @@ -124,7 +124,6 @@ func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStr var customName string for i := 0; i < numFields; i++ { - fld = typ.Field(i) if !v.privateFieldValidation && !fld.Anonymous && len(fld.PkgPath) > 0 { @@ -191,7 +190,6 @@ func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias s } else { next, curr := v.parseFieldTagsRecursive(tagsVal, fieldName, t, true) current.next, current = next, curr - } continue } @@ -210,7 +208,6 @@ func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias s switch t { case diveTag: current.typeof = typeDive - continue case keysTag: current.typeof = typeKeys @@ -219,8 +216,6 @@ func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias s panic(fmt.Sprintf("'%s' tag must be immediately preceded by the '%s' tag", keysTag, diveTag)) } - current.typeof = typeKeys - // need to pass along only keys tag // need to increment i to skip over the keys tags b := make([]byte, 0, 64) @@ -228,7 +223,6 @@ func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias s i++ for ; i < len(tags); i++ { - b = append(b, tags[i]...) b = append(b, ',') @@ -238,7 +232,6 @@ func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias s } current.keys, _ = v.parseFieldTagsRecursive(string(b[:len(b)-1]), fieldName, "", false) - continue case endKeysTag: current.typeof = typeEndKeys @@ -256,19 +249,15 @@ func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias s case omitempty: current.typeof = typeOmitEmpty - continue case omitnil: current.typeof = typeOmitNil - continue case structOnlyTag: current.typeof = typeStructOnly - continue case noStructLevelTag: current.typeof = typeNoStructLevel - continue default: if t == isdefault { diff --git a/vendor/github.com/go-playground/validator/v10/doc.go b/vendor/github.com/go-playground/validator/v10/doc.go index e7a241fb..23cce991 100644 --- a/vendor/github.com/go-playground/validator/v10/doc.go +++ b/vendor/github.com/go-playground/validator/v10/doc.go @@ -188,7 +188,7 @@ Same as structonly tag except that any struct level validations will not run. # Omit Empty -Allows conditional validation, for example if a field is not set with +Allows conditional validation, for example, if a field is not set with a value (Determined by the "required" validator) then other validation such as min or max won't run, but if a value is set validation will run. @@ -756,6 +756,20 @@ in a field of the struct specified via a parameter. // For slices of struct: Usage: unique=field +# ValidateFn + +This validates that an object responds to a method that can return error or bool. +By default it expects an interface `Validate() error` and check that the method +does not return an error. Other methods can be specified using two signatures: +If the method returns an error, it check if the return value is nil. +If the method returns a boolean, it checks if the value is true. + + // to use the default method Validate() error + Usage: validateFn + + // to use the custom method IsValid() bool (or error) + Usage: validateFn=IsValid + # Alpha Only This validates that a string value contains ASCII alpha characters only diff --git a/vendor/github.com/go-playground/validator/v10/errors.go b/vendor/github.com/go-playground/validator/v10/errors.go index be2676e9..fd906256 100644 --- a/vendor/github.com/go-playground/validator/v10/errors.go +++ b/vendor/github.com/go-playground/validator/v10/errors.go @@ -24,7 +24,6 @@ type InvalidValidationError struct { // Error returns InvalidValidationError message func (e *InvalidValidationError) Error() string { - if e.Type == nil { return "validator: (nil)" } @@ -41,11 +40,9 @@ type ValidationErrors []FieldError // All information to create an error message specific to your application is contained within // the FieldError found within the ValidationErrors array func (ve ValidationErrors) Error() string { - buff := bytes.NewBufferString("") for i := 0; i < len(ve); i++ { - buff.WriteString(ve[i].Error()) buff.WriteString("\n") } @@ -55,7 +52,6 @@ func (ve ValidationErrors) Error() string { // Translate translates all of the ValidationErrors func (ve ValidationErrors) Translate(ut ut.Translator) ValidationErrorsTranslations { - trans := make(ValidationErrorsTranslations) var fe *fieldError @@ -109,22 +105,24 @@ type FieldError interface { // StructNamespace returns the namespace for the field error, with the field's // actual name. // - // eq. "User.FirstName" see Namespace for comparison + // eg. "User.FirstName" see Namespace for comparison // // NOTE: this field can be blank when validating a single primitive field // using validate.Field(...) as there is no way to extract its name StructNamespace() string - // Field returns the fields name with the tag name taking precedence over the + // Field returns the field's name with the tag name taking precedence over the // field's actual name. // - // eq. JSON name "fname" + // `RegisterTagNameFunc` must be registered to get tag value. + // + // eg. JSON name "fname" // see StructField for comparison Field() string // StructField returns the field's actual name from the struct, when able to determine. // - // eq. "FirstName" + // eg. "FirstName" // see Field for comparison StructField() string @@ -204,7 +202,6 @@ func (fe *fieldError) StructNamespace() string { // Field returns the field's name with the tag name taking precedence over the // field's actual name. func (fe *fieldError) Field() string { - return fe.ns[len(fe.ns)-int(fe.fieldLen):] // // return fe.field // fld := fe.ns[len(fe.ns)-int(fe.fieldLen):] diff --git a/vendor/github.com/go-playground/validator/v10/struct_level.go b/vendor/github.com/go-playground/validator/v10/struct_level.go index fa7af9dd..129b2872 100644 --- a/vendor/github.com/go-playground/validator/v10/struct_level.go +++ b/vendor/github.com/go-playground/validator/v10/struct_level.go @@ -107,7 +107,6 @@ func (v *validate) ExtractType(field reflect.Value) (reflect.Value, reflect.Kind // ReportError reports an error just by passing the field and tag information func (v *validate) ReportError(field interface{}, fieldName, structFieldName, tag, param string) { - fv, kind, _ := v.extractTypeInternal(reflect.ValueOf(field), false) if len(structFieldName) == 0 { @@ -123,7 +122,6 @@ func (v *validate) ReportError(field interface{}, fieldName, structFieldName, ta } if kind == reflect.Invalid { - v.errs = append(v.errs, &fieldError{ v: v.v, @@ -149,7 +147,7 @@ func (v *validate) ReportError(field interface{}, fieldName, structFieldName, ta structNs: v.str2, fieldLen: uint8(len(fieldName)), structfieldLen: uint8(len(structFieldName)), - value: fv.Interface(), + value: getValue(fv), param: param, kind: kind, typ: fv.Type(), @@ -161,11 +159,9 @@ func (v *validate) ReportError(field interface{}, fieldName, structFieldName, ta // // NOTE: this function prepends the current namespace to the relative ones. func (v *validate) ReportValidationErrors(relativeNamespace, relativeStructNamespace string, errs ValidationErrors) { - var err *fieldError for i := 0; i < len(errs); i++ { - err = errs[i].(*fieldError) err.ns = string(append(append(v.ns, relativeNamespace...), err.ns...)) err.structNs = string(append(append(v.actualNs, relativeStructNamespace...), err.structNs...)) diff --git a/vendor/github.com/go-playground/validator/v10/util.go b/vendor/github.com/go-playground/validator/v10/util.go index 9285223a..b1fd8cc1 100644 --- a/vendor/github.com/go-playground/validator/v10/util.go +++ b/vendor/github.com/go-playground/validator/v10/util.go @@ -13,7 +13,6 @@ import ( // It will dive into pointers, customTypes and return you the // underlying value and it's kind. func (v *validate) extractTypeInternal(current reflect.Value, nullable bool) (reflect.Value, reflect.Kind, bool) { - BEGIN: switch current.Kind() { case reflect.Ptr: @@ -44,7 +43,6 @@ BEGIN: default: if v.v.hasCustomFuncs { - if fn, ok := v.v.customFuncs[current.Type()]; ok { current = reflect.ValueOf(fn(current)) goto BEGIN @@ -61,7 +59,6 @@ BEGIN: // NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field // could not be retrieved because it didn't exist. func (v *validate) getStructFieldOKInternal(val reflect.Value, namespace string) (current reflect.Value, kind reflect.Kind, nullable bool, found bool) { - BEGIN: current, kind, nullable = v.ExtractType(val) if kind == reflect.Invalid { @@ -74,7 +71,6 @@ BEGIN: } switch kind { - case reflect.Ptr, reflect.Interface: return @@ -85,7 +81,6 @@ BEGIN: var ns string if !typ.ConvertibleTo(timeType) { - idx := strings.Index(namespace, namespaceSeparator) if idx != -1 { @@ -222,7 +217,7 @@ BEGIN: panic("Invalid field namespace") } -// asInt returns the parameter as a int64 +// asInt returns the parameter as an int64 // or panics if it can't convert func asInt(param string) int64 { i, err := strconv.ParseInt(param, 0, 64) @@ -256,7 +251,6 @@ func asIntFromType(t reflect.Type, param string) int64 { // asUint returns the parameter as a uint64 // or panics if it can't convert func asUint(param string) uint64 { - i, err := strconv.ParseUint(param, 0, 64) panicIf(err) @@ -282,7 +276,6 @@ func asFloat32(param string) float64 { // asBool returns the parameter as a bool // or panics if it can't convert func asBool(param string) bool { - i, err := strconv.ParseBool(param) panicIf(err) @@ -303,7 +296,7 @@ func fieldMatchesRegexByStringerValOrString(regexFn func() *regexp.Regexp, fl Fi case reflect.String: return regex.MatchString(fl.Field().String()) default: - if stringer, ok := fl.Field().Interface().(fmt.Stringer); ok { + if stringer, ok := getValue(fl.Field()).(fmt.Stringer); ok { return regex.MatchString(stringer.String()) } else { return regex.MatchString(fl.Field().String()) diff --git a/vendor/github.com/go-playground/validator/v10/validator.go b/vendor/github.com/go-playground/validator/v10/validator.go index d7c2e658..995b0e19 100644 --- a/vendor/github.com/go-playground/validator/v10/validator.go +++ b/vendor/github.com/go-playground/validator/v10/validator.go @@ -32,14 +32,12 @@ type validate struct { // parent and current will be the same the first run of validateStruct func (v *validate) validateStruct(ctx context.Context, parent reflect.Value, current reflect.Value, typ reflect.Type, ns []byte, structNs []byte, ct *cTag) { - cs, ok := v.v.structCache.Get(typ) if !ok { cs = v.v.extractStructCache(current, typ.Name()) } if len(ns) == 0 && len(cs.name) != 0 { - ns = append(ns, cs.name...) ns = append(ns, '.') @@ -50,21 +48,17 @@ func (v *validate) validateStruct(ctx context.Context, parent reflect.Value, cur // ct is nil on top level struct, and structs as fields that have no tag info // so if nil or if not nil and the structonly tag isn't present if ct == nil || ct.typeof != typeStructOnly { - var f *cField for i := 0; i < len(cs.fields); i++ { - f = cs.fields[i] if v.isPartial { - if v.ffn != nil { // used with StructFiltered if v.ffn(append(structNs, f.name...)) { continue } - } else { // used with StructPartial & StructExcept _, ok = v.includeExclude[string(append(structNs, f.name...))] @@ -83,7 +77,6 @@ func (v *validate) validateStruct(ctx context.Context, parent reflect.Value, cur // first iteration will have no info about nostructlevel tag, and is checked prior to // calling the next iteration of validateStruct called from traverseField. if cs.fn != nil { - v.slflParent = parent v.slCurrent = current v.ns = ns @@ -267,7 +260,7 @@ OUTER: return } default: - if v.fldIsPointer && field.Interface() == nil { + if v.fldIsPointer && getValue(field) == nil { return } } @@ -291,7 +284,6 @@ OUTER: reusableCF := &cField{} for i := 0; i < current.Len(); i++ { - i64 = int64(i) v.misc = append(v.misc[0:0], cf.name...) @@ -304,7 +296,6 @@ OUTER: if cf.namesEqual { reusableCF.altName = reusableCF.name } else { - v.misc = append(v.misc[0:0], cf.altName...) v.misc = append(v.misc, '[') v.misc = strconv.AppendInt(v.misc, i64, 10) @@ -321,8 +312,7 @@ OUTER: reusableCF := &cField{} for _, key := range current.MapKeys() { - - pv = fmt.Sprintf("%v", key.Interface()) + pv = fmt.Sprintf("%v", key) v.misc = append(v.misc[0:0], cf.name...) v.misc = append(v.misc, '[') @@ -347,6 +337,18 @@ OUTER: // can be nil when just keys being validated if ct.next != nil { v.traverseField(ctx, parent, current.MapIndex(key), ns, structNs, reusableCF, ct.next) + } else { + // Struct fallback when map values are structs + val := current.MapIndex(key) + switch val.Kind() { + case reflect.Ptr: + if val.Elem().Kind() == reflect.Struct { + // Dive into the struct so its own tags run + v.traverseField(ctx, parent, val, ns, structNs, reusableCF, nil) + } + case reflect.Struct: + v.traverseField(ctx, parent, val, ns, structNs, reusableCF, nil) + } } } else { v.traverseField(ctx, parent, current.MapIndex(key), ns, structNs, reusableCF, ct) @@ -366,7 +368,6 @@ OUTER: v.misc = v.misc[0:0] for { - // set Field Level fields v.slflParent = parent v.flField = current @@ -381,7 +382,6 @@ OUTER: // drain rest of the 'or' values, then continue or leave for { - ct = ct.next if ct == nil { @@ -418,7 +418,6 @@ OUTER: } if ct.hasAlias { - v.errs = append(v.errs, &fieldError{ v: v.v, @@ -434,9 +433,7 @@ OUTER: typ: typ, }, ) - } else { - tVal := string(v.misc)[1:] v.errs = append(v.errs, @@ -500,7 +497,6 @@ OUTER: ct = ct.next } } - } func getValue(val reflect.Value) interface{} { diff --git a/vendor/github.com/go-playground/validator/v10/validator_instance.go b/vendor/github.com/go-playground/validator/v10/validator_instance.go index 779f689a..9362cd73 100644 --- a/vendor/github.com/go-playground/validator/v10/validator_instance.go +++ b/vendor/github.com/go-playground/validator/v10/validator_instance.go @@ -104,7 +104,6 @@ type Validate struct { // in essence only parsing your validation tags once per struct type. // Using multiple instances neglects the benefit of caching. func New(options ...Option) *Validate { - tc := new(tagCache) tc.m.Store(make(map[string]*cTag)) @@ -126,7 +125,6 @@ func New(options ...Option) *Validate { // must copy validators for separate validations to be used in each instance for k, val := range bakedInValidators { - switch k { // these require that even if the value is nil that the validation should run, omitempty still overrides this behaviour case requiredIfTag, requiredUnlessTag, requiredWithTag, requiredWithAllTag, requiredWithoutTag, requiredWithoutAllTag, @@ -233,30 +231,12 @@ func (v *Validate) RegisterValidationCtx(tag string, fn FuncCtx, callValidationE return v.registerValidation(tag, fn, false, nilCheckable) } -func (v *Validate) registerValidation(tag string, fn FuncCtx, bakedIn bool, nilCheckable bool) error { - if len(tag) == 0 { - return errors.New("function Key cannot be empty") - } - - if fn == nil { - return errors.New("function cannot be empty") - } - - _, ok := restrictedTags[tag] - if !bakedIn && (ok || strings.ContainsAny(tag, restrictedTagChars)) { - panic(fmt.Sprintf(restrictedTagErr, tag)) - } - v.validations[tag] = internalValidationFuncWrapper{fn: fn, runValidationOnNil: nilCheckable} - return nil -} - // RegisterAlias registers a mapping of a single validation tag that // defines a common or complex set of validation(s) to simplify adding validation // to structs. // // NOTE: this function is not thread-safe it is intended that these all be registered prior to any validation func (v *Validate) RegisterAlias(alias, tags string) { - _, ok := restrictedTags[alias] if ok || strings.ContainsAny(alias, restrictedTagChars) { @@ -280,7 +260,6 @@ func (v *Validate) RegisterStructValidation(fn StructLevelFunc, types ...interfa // NOTE: // - this method is not thread-safe it is intended that these all be registered prior to any validation func (v *Validate) RegisterStructValidationCtx(fn StructLevelFuncCtx, types ...interface{}) { - if v.structLevelFuncs == nil { v.structLevelFuncs = make(map[reflect.Type]StructLevelFuncCtx) } @@ -327,7 +306,6 @@ func (v *Validate) RegisterStructValidationMapRules(rules map[string]string, typ // // NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation func (v *Validate) RegisterCustomTypeFunc(fn CustomTypeFunc, types ...interface{}) { - if v.customFuncs == nil { v.customFuncs = make(map[reflect.Type]CustomTypeFunc) } @@ -341,7 +319,6 @@ func (v *Validate) RegisterCustomTypeFunc(fn CustomTypeFunc, types ...interface{ // RegisterTranslation registers translations against the provided tag. func (v *Validate) RegisterTranslation(tag string, trans ut.Translator, registerFn RegisterTranslationsFunc, translationFn TranslationFunc) (err error) { - if v.transTagFunc == nil { v.transTagFunc = make(map[ut.Translator]map[string]TranslationFunc) } @@ -375,7 +352,6 @@ func (v *Validate) Struct(s interface{}) error { // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. func (v *Validate) StructCtx(ctx context.Context, s interface{}) (err error) { - val := reflect.ValueOf(s) top := val @@ -492,10 +468,8 @@ func (v *Validate) StructPartialCtx(ctx context.Context, s interface{}, fields . name := typ.Name() for _, k := range fields { - flds := strings.Split(k, namespaceSeparator) if len(flds) > 0 { - vd.misc = append(vd.misc[0:0], name...) // Don't append empty name for unnamed structs if len(vd.misc) != 0 { @@ -503,7 +477,6 @@ func (v *Validate) StructPartialCtx(ctx context.Context, s interface{}, fields . } for _, s := range flds { - idx := strings.Index(s, leftBracket) if idx != -1 { @@ -519,7 +492,6 @@ func (v *Validate) StructPartialCtx(ctx context.Context, s interface{}, fields . idx = strings.Index(s, leftBracket) } } else { - vd.misc = append(vd.misc, s...) vd.includeExclude[string(vd.misc)] = struct{}{} } @@ -582,7 +554,6 @@ func (v *Validate) StructExceptCtx(ctx context.Context, s interface{}, fields .. name := typ.Name() for _, key := range fields { - vd.misc = vd.misc[0:0] if len(name) > 0 { @@ -709,3 +680,20 @@ func (v *Validate) VarWithValueCtx(ctx context.Context, field interface{}, other v.pool.Put(vd) return } + +func (v *Validate) registerValidation(tag string, fn FuncCtx, bakedIn bool, nilCheckable bool) error { + if len(tag) == 0 { + return errors.New("function Key cannot be empty") + } + + if fn == nil { + return errors.New("function cannot be empty") + } + + _, ok := restrictedTags[tag] + if !bakedIn && (ok || strings.ContainsAny(tag, restrictedTagChars)) { + panic(fmt.Sprintf(restrictedTagErr, tag)) + } + v.validations[tag] = internalValidationFuncWrapper{fn: fn, runValidationOnNil: nilCheckable} + return nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index bb0ed3a0..48be686a 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -232,7 +232,7 @@ github.com/go-playground/locales/currency # github.com/go-playground/universal-translator v0.18.1 ## explicit; go 1.18 github.com/go-playground/universal-translator -# github.com/go-playground/validator/v10 v10.26.0 +# github.com/go-playground/validator/v10 v10.27.0 ## explicit; go 1.20 github.com/go-playground/validator/v10 # github.com/gogo/protobuf v1.3.2