123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700 |
- package validator
- import (
- "fmt"
- "net/url"
- "reflect"
- "strconv"
- "time"
- )
- // BakedInValidators is the default map of ValidationFunc
- // you can add, remove or even replace items to suite your needs,
- // or even disregard and use your own map if so desired.
- var BakedInValidators = map[string]ValidationFunc{
- "required": hasValue,
- "len": hasLengthOf,
- "min": hasMinOf,
- "max": hasMaxOf,
- "lt": isLt,
- "lte": isLte,
- "gt": isGt,
- "gte": isGte,
- "gtefield": isGteField,
- "gtfield": isGtField,
- "ltefield": isLteField,
- "ltfield": isLtField,
- "alpha": isAlpha,
- "alphanum": isAlphanum,
- "numeric": isNumeric,
- "number": isNumber,
- "hexadecimal": isHexadecimal,
- "hexcolor": isHexcolor,
- "rgb": isRgb,
- "rgba": isRgba,
- "hsl": isHsl,
- "hsla": isHsla,
- "email": isEmail,
- "url": isURL,
- "uri": isURI,
- }
- func isURI(top interface{}, current interface{}, field interface{}, param string) bool {
- st := reflect.ValueOf(field)
- switch st.Kind() {
- case reflect.String:
- _, err := url.ParseRequestURI(field.(string))
- return err == nil
- }
- panic(fmt.Sprintf("Bad field type %T", field))
- }
- func isURL(top interface{}, current interface{}, field interface{}, param string) bool {
- st := reflect.ValueOf(field)
- switch st.Kind() {
- case reflect.String:
- url, err := url.ParseRequestURI(field.(string))
- if err != nil {
- return false
- }
- if len(url.Scheme) == 0 {
- return false
- }
- return err == nil
- }
- panic(fmt.Sprintf("Bad field type %T", field))
- }
- func isEmail(top interface{}, current interface{}, field interface{}, param string) bool {
- return matchesRegex(emailRegex, field)
- }
- func isHsla(top interface{}, current interface{}, field interface{}, param string) bool {
- return matchesRegex(hslaRegex, field)
- }
- func isHsl(top interface{}, current interface{}, field interface{}, param string) bool {
- return matchesRegex(hslRegex, field)
- }
- func isRgba(top interface{}, current interface{}, field interface{}, param string) bool {
- return matchesRegex(rgbaRegex, field)
- }
- func isRgb(top interface{}, current interface{}, field interface{}, param string) bool {
- return matchesRegex(rgbRegex, field)
- }
- func isHexcolor(top interface{}, current interface{}, field interface{}, param string) bool {
- return matchesRegex(hexcolorRegex, field)
- }
- func isHexadecimal(top interface{}, current interface{}, field interface{}, param string) bool {
- return matchesRegex(hexadecimalRegex, field)
- }
- func isNumber(top interface{}, current interface{}, field interface{}, param string) bool {
- return matchesRegex(numberRegex, field)
- }
- func isNumeric(top interface{}, current interface{}, field interface{}, param string) bool {
- return matchesRegex(numericRegex, field)
- }
- func isAlphanum(top interface{}, current interface{}, field interface{}, param string) bool {
- return matchesRegex(alphaNumericRegex, field)
- }
- func isAlpha(top interface{}, current interface{}, field interface{}, param string) bool {
- return matchesRegex(alphaRegex, field)
- }
- func hasValue(top interface{}, current interface{}, field interface{}, param string) bool {
- st := reflect.ValueOf(field)
- switch st.Kind() {
- case reflect.Slice, reflect.Map, reflect.Array:
- return field != nil && int64(st.Len()) > 0
- default:
- return field != nil && field != reflect.Zero(reflect.TypeOf(field)).Interface()
- }
- }
- func isGteField(top interface{}, current interface{}, field interface{}, param string) bool {
- if current == nil {
- panic("struct not passed for cross validation")
- }
- currentVal := reflect.ValueOf(current)
- if currentVal.Kind() == reflect.Ptr && !currentVal.IsNil() {
- currentVal = reflect.ValueOf(currentVal.Elem().Interface())
- }
- var currentFielVal reflect.Value
- switch currentVal.Kind() {
- case reflect.Struct:
- if currentVal.Type() == reflect.TypeOf(time.Time{}) {
- currentFielVal = currentVal
- break
- }
- f := currentVal.FieldByName(param)
- if f.Kind() == reflect.Invalid {
- panic(fmt.Sprintf("Field \"%s\" not found in struct", param))
- }
- currentFielVal = f
- default:
- currentFielVal = currentVal
- }
- if currentFielVal.Kind() == reflect.Ptr && !currentFielVal.IsNil() {
- currentFielVal = reflect.ValueOf(currentFielVal.Elem().Interface())
- }
- fv := reflect.ValueOf(field)
- switch fv.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return fv.Int() >= currentFielVal.Int()
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- return fv.Uint() >= currentFielVal.Uint()
- case reflect.Float32, reflect.Float64:
- return fv.Float() >= currentFielVal.Float()
- case reflect.Struct:
- if fv.Type() == reflect.TypeOf(time.Time{}) {
- if currentFielVal.Type() != reflect.TypeOf(time.Time{}) {
- panic("Bad Top Level field type")
- }
- t := currentFielVal.Interface().(time.Time)
- fieldTime := field.(time.Time)
- return fieldTime.After(t) || fieldTime.Equal(t)
- }
- }
- panic(fmt.Sprintf("Bad field type %T", field))
- }
- func isGtField(top interface{}, current interface{}, field interface{}, param string) bool {
- if current == nil {
- panic("struct not passed for cross validation")
- }
- currentVal := reflect.ValueOf(current)
- if currentVal.Kind() == reflect.Ptr && !currentVal.IsNil() {
- currentVal = reflect.ValueOf(currentVal.Elem().Interface())
- }
- var currentFielVal reflect.Value
- switch currentVal.Kind() {
- case reflect.Struct:
- if currentVal.Type() == reflect.TypeOf(time.Time{}) {
- currentFielVal = currentVal
- break
- }
- f := currentVal.FieldByName(param)
- if f.Kind() == reflect.Invalid {
- panic(fmt.Sprintf("Field \"%s\" not found in struct", param))
- }
- currentFielVal = f
- default:
- currentFielVal = currentVal
- }
- if currentFielVal.Kind() == reflect.Ptr && !currentFielVal.IsNil() {
- currentFielVal = reflect.ValueOf(currentFielVal.Elem().Interface())
- }
- fv := reflect.ValueOf(field)
- switch fv.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return fv.Int() > currentFielVal.Int()
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- return fv.Uint() > currentFielVal.Uint()
- case reflect.Float32, reflect.Float64:
- return fv.Float() > currentFielVal.Float()
- case reflect.Struct:
- if fv.Type() == reflect.TypeOf(time.Time{}) {
- if currentFielVal.Type() != reflect.TypeOf(time.Time{}) {
- panic("Bad Top Level field type")
- }
- t := currentFielVal.Interface().(time.Time)
- fieldTime := field.(time.Time)
- return fieldTime.After(t)
- }
- }
- panic(fmt.Sprintf("Bad field type %T", field))
- }
- func isGte(top interface{}, current interface{}, field interface{}, param string) bool {
- st := reflect.ValueOf(field)
- switch st.Kind() {
- case reflect.String:
- p := asInt(param)
- return int64(len(st.String())) >= p
- case reflect.Slice, reflect.Map, reflect.Array:
- p := asInt(param)
- return int64(st.Len()) >= p
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- p := asInt(param)
- return st.Int() >= p
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- p := asUint(param)
- return st.Uint() >= p
- case reflect.Float32, reflect.Float64:
- p := asFloat(param)
- return st.Float() >= p
- case reflect.Struct:
- if st.Type() == reflect.TypeOf(time.Time{}) {
- now := time.Now().UTC()
- t := field.(time.Time)
- return t.After(now) || t.Equal(now)
- }
- }
- panic(fmt.Sprintf("Bad field type %T", field))
- }
- func isGt(top interface{}, current interface{}, field interface{}, param string) bool {
- st := reflect.ValueOf(field)
- switch st.Kind() {
- case reflect.String:
- p := asInt(param)
- return int64(len(st.String())) > p
- case reflect.Slice, reflect.Map, reflect.Array:
- p := asInt(param)
- return int64(st.Len()) > p
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- p := asInt(param)
- return st.Int() > p
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- p := asUint(param)
- return st.Uint() > p
- case reflect.Float32, reflect.Float64:
- p := asFloat(param)
- return st.Float() > p
- case reflect.Struct:
- if st.Type() == reflect.TypeOf(time.Time{}) {
- return field.(time.Time).After(time.Now().UTC())
- }
- }
- panic(fmt.Sprintf("Bad field type %T", field))
- }
- // length tests whether a variable's length is equal to a given
- // value. For strings it tests the number of characters whereas
- // for maps and slices it tests the number of items.
- func hasLengthOf(top interface{}, current interface{}, field interface{}, param string) bool {
- st := reflect.ValueOf(field)
- switch st.Kind() {
- case reflect.String:
- p := asInt(param)
- return int64(len(st.String())) == p
- case reflect.Slice, reflect.Map, reflect.Array:
- p := asInt(param)
- return int64(st.Len()) == p
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- p := asInt(param)
- return st.Int() == p
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- p := asUint(param)
- return st.Uint() == p
- case reflect.Float32, reflect.Float64:
- p := asFloat(param)
- return st.Float() == p
- }
- panic(fmt.Sprintf("Bad field type %T", field))
- }
- // min tests whether a variable value is larger or equal to a given
- // number. For number types, it's a simple lesser-than test; for
- // strings it tests the number of characters whereas for maps
- // and slices it tests the number of items.
- func hasMinOf(top interface{}, current interface{}, field interface{}, param string) bool {
- return isGte(top, current, field, param)
- }
- func isLteField(top interface{}, current interface{}, field interface{}, param string) bool {
- if current == nil {
- panic("struct not passed for cross validation")
- }
- currentVal := reflect.ValueOf(current)
- if currentVal.Kind() == reflect.Ptr && !currentVal.IsNil() {
- currentVal = reflect.ValueOf(currentVal.Elem().Interface())
- }
- var currentFielVal reflect.Value
- switch currentVal.Kind() {
- case reflect.Struct:
- if currentVal.Type() == reflect.TypeOf(time.Time{}) {
- currentFielVal = currentVal
- break
- }
- f := currentVal.FieldByName(param)
- if f.Kind() == reflect.Invalid {
- panic(fmt.Sprintf("Field \"%s\" not found in struct", param))
- }
- currentFielVal = f
- default:
- currentFielVal = currentVal
- }
- if currentFielVal.Kind() == reflect.Ptr && !currentFielVal.IsNil() {
- currentFielVal = reflect.ValueOf(currentFielVal.Elem().Interface())
- }
- fv := reflect.ValueOf(field)
- switch fv.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return fv.Int() <= currentFielVal.Int()
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- return fv.Uint() <= currentFielVal.Uint()
- case reflect.Float32, reflect.Float64:
- return fv.Float() <= currentFielVal.Float()
- case reflect.Struct:
- if fv.Type() == reflect.TypeOf(time.Time{}) {
- if currentFielVal.Type() != reflect.TypeOf(time.Time{}) {
- panic("Bad Top Level field type")
- }
- t := currentFielVal.Interface().(time.Time)
- fieldTime := field.(time.Time)
- return fieldTime.Before(t) || fieldTime.Equal(t)
- }
- }
- panic(fmt.Sprintf("Bad field type %T", field))
- }
- func isLtField(top interface{}, current interface{}, field interface{}, param string) bool {
- if current == nil {
- panic("struct not passed for cross validation")
- }
- currentVal := reflect.ValueOf(current)
- if currentVal.Kind() == reflect.Ptr && !currentVal.IsNil() {
- currentVal = reflect.ValueOf(currentVal.Elem().Interface())
- }
- var currentFielVal reflect.Value
- switch currentVal.Kind() {
- case reflect.Struct:
- if currentVal.Type() == reflect.TypeOf(time.Time{}) {
- currentFielVal = currentVal
- break
- }
- f := currentVal.FieldByName(param)
- if f.Kind() == reflect.Invalid {
- panic(fmt.Sprintf("Field \"%s\" not found in struct", param))
- }
- currentFielVal = f
- default:
- currentFielVal = currentVal
- }
- if currentFielVal.Kind() == reflect.Ptr && !currentFielVal.IsNil() {
- currentFielVal = reflect.ValueOf(currentFielVal.Elem().Interface())
- }
- fv := reflect.ValueOf(field)
- switch fv.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return fv.Int() < currentFielVal.Int()
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- return fv.Uint() < currentFielVal.Uint()
- case reflect.Float32, reflect.Float64:
- return fv.Float() < currentFielVal.Float()
- case reflect.Struct:
- if fv.Type() == reflect.TypeOf(time.Time{}) {
- if currentFielVal.Type() != reflect.TypeOf(time.Time{}) {
- panic("Bad Top Level field type")
- }
- t := currentFielVal.Interface().(time.Time)
- fieldTime := field.(time.Time)
- return fieldTime.Before(t)
- }
- }
- panic(fmt.Sprintf("Bad field type %T", field))
- }
- func isLte(top interface{}, current interface{}, field interface{}, param string) bool {
- st := reflect.ValueOf(field)
- switch st.Kind() {
- case reflect.String:
- p := asInt(param)
- return int64(len(st.String())) <= p
- case reflect.Slice, reflect.Map, reflect.Array:
- p := asInt(param)
- return int64(st.Len()) <= p
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- p := asInt(param)
- return st.Int() <= p
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- p := asUint(param)
- return st.Uint() <= p
- case reflect.Float32, reflect.Float64:
- p := asFloat(param)
- return st.Float() <= p
- case reflect.Struct:
- if st.Type() == reflect.TypeOf(time.Time{}) {
- now := time.Now().UTC()
- t := field.(time.Time)
- return t.Before(now) || t.Equal(now)
- }
- }
- panic(fmt.Sprintf("Bad field type %T", field))
- }
- func isLt(top interface{}, current interface{}, field interface{}, param string) bool {
- st := reflect.ValueOf(field)
- switch st.Kind() {
- case reflect.String:
- p := asInt(param)
- return int64(len(st.String())) < p
- case reflect.Slice, reflect.Map, reflect.Array:
- p := asInt(param)
- return int64(st.Len()) < p
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- p := asInt(param)
- return st.Int() < p
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- p := asUint(param)
- return st.Uint() < p
- case reflect.Float32, reflect.Float64:
- p := asFloat(param)
- return st.Float() < p
- case reflect.Struct:
- if st.Type() == reflect.TypeOf(time.Time{}) {
- return field.(time.Time).Before(time.Now().UTC())
- }
- }
- panic(fmt.Sprintf("Bad field type %T", field))
- }
- // max tests whether a variable value is lesser than a given
- // value. For numbers, it's a simple lesser-than test; for
- // strings it tests the number of characters whereas for maps
- // and slices it tests the number of items.
- func hasMaxOf(top interface{}, current interface{}, field interface{}, param string) bool {
- return isLte(top, current, field, param)
- }
- // asInt retuns the parameter as a int64
- // or panics if it can't convert
- func asInt(param string) int64 {
- i, err := strconv.ParseInt(param, 0, 64)
- panicIf(err)
- return i
- }
- // 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)
- return i
- }
- // asFloat returns the parameter as a float64
- // or panics if it can't convert
- func asFloat(param string) float64 {
- i, err := strconv.ParseFloat(param, 64)
- panicIf(err)
- return i
- }
- func panicIf(err error) {
- if err != nil {
- panic(err.Error())
- }
- }
|