Skip to content

Commit 0c80f87

Browse files
author
Dean Karn
authored
Merge branch 'master' into json
2 parents 581d269 + 68e8e13 commit 0c80f87

File tree

8 files changed

+2237
-10
lines changed

8 files changed

+2237
-10
lines changed

baked_in.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,9 @@ var (
168168
"url_encoded": isURLEncoded,
169169
"dir": isDir,
170170
"json": isJSON,
171+
"hostname_port": isHostnamePort,
172+
"lowercase": isLowercase,
173+
"uppercase": isUppercase,
171174
}
172175
)
173176

@@ -2017,6 +2020,52 @@ func isJSON(fl FieldLevel) bool {
20172020
if field.Kind() == reflect.String {
20182021
val := field.String()
20192022
return json.Valid([]byte(val))
2023+
}
2024+
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
2025+
}
2026+
2027+
// isHostnamePort validates a <dns>:<port> combination for fields typically used for socket address.
2028+
func isHostnamePort(fl FieldLevel) bool {
2029+
val := fl.Field().String()
2030+
host, port, err := net.SplitHostPort(val)
2031+
if err != nil {
2032+
return false
2033+
}
2034+
// Port must be a iny <= 65535.
2035+
if portNum, err := strconv.ParseInt(port, 10, 32); err != nil || portNum > 65535 || portNum < 1 {
2036+
return false
2037+
}
2038+
2039+
// If host is specified, it should match a DNS name
2040+
if host != "" {
2041+
return hostnameRegexRFC1123.MatchString(host)
2042+
}
2043+
return true
2044+
}
2045+
2046+
// isLowercase is the validation function for validating if the current field's value is a lowercase string.
2047+
func isLowercase(fl FieldLevel) bool {
2048+
field := fl.Field()
2049+
2050+
if field.Kind() == reflect.String {
2051+
if field.String() == "" {
2052+
return false
2053+
}
2054+
return field.String() == strings.ToLower(field.String())
2055+
}
2056+
2057+
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
2058+
}
2059+
2060+
// isUppercase is the validation function for validating if the current field's value is an uppercase string.
2061+
func isUppercase(fl FieldLevel) bool {
2062+
field := fl.Field()
2063+
2064+
if field.Kind() == reflect.String {
2065+
if field.String() == "" {
2066+
return false
2067+
}
2068+
return field.String() == strings.ToUpper(field.String())
20202069
}
20212070

20222071
panic(fmt.Sprintf("Bad field type %T", field.Interface()))

doc.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ handy in ignoring embedded structs from being validated. (Usage: -)
158158
Or Operator
159159
160160
This is the 'or' operator allowing multiple validators to be used and
161-
accepted. (Usage: rbg|rgba) <-- this would allow either rgb or rgba
161+
accepted. (Usage: rgb|rgba) <-- this would allow either rgb or rgba
162162
colors to be accepted. This can also be combined with 'and' for example
163163
( Usage: omitempty,rgb|rgba)
164164
@@ -641,6 +641,18 @@ hashtag (#)
641641
642642
Usage: hexcolor
643643
644+
Lowercase String
645+
646+
This validates that a string value contains only lowercase characters. An empty string is not a valid lowercase string.
647+
648+
Usage: lowercase
649+
650+
Uppercase String
651+
652+
This validates that a string value contains only uppercase characters. An empty string is not a valid uppercase string.
653+
654+
Usage: uppercase
655+
644656
RGB String
645657
646658
This validates that a string value contains a valid rgb color
@@ -1043,6 +1055,13 @@ This is done using os.Stat, which is a platform independent function.
10431055
10441056
Usage: dir
10451057
1058+
HostPort
1059+
1060+
This validates that a string value contains a valid DNS hostname and port that
1061+
can be used to valiate fields typically passed to sockets and connections.
1062+
1063+
Usage: hostname_port
1064+
10461065
Alias Validators and Tags
10471066
10481067
NOTE: When returning an error, the tag returned in "FieldError" will be

regexes.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ const (
3636
latitudeRegexString = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$"
3737
longitudeRegexString = "^[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$"
3838
sSNRegexString = `^[0-9]{3}[ -]?(0[1-9]|[1-9][0-9])[ -]?([1-9][0-9]{3}|[0-9][1-9][0-9]{2}|[0-9]{2}[1-9][0-9]|[0-9]{3}[1-9])$`
39-
hostnameRegexStringRFC952 = `^[a-zA-Z][a-zA-Z0-9\-\.]+[a-zA-Z0-9]$` // https://tools.ietf.org/html/rfc952
40-
hostnameRegexStringRFC1123 = `^[a-zA-Z0-9][a-zA-Z0-9\-\.]+[a-zA-Z0-9]$` // accepts hostname starting with a digit https://tools.ietf.org/html/rfc1123
41-
btcAddressRegexString = `^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$` // bitcoin address
42-
btcAddressUpperRegexStringBech32 = `^BC1[02-9AC-HJ-NP-Z]{7,76}$` // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32
43-
btcAddressLowerRegexStringBech32 = `^bc1[02-9ac-hj-np-z]{7,76}$` // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32
39+
hostnameRegexStringRFC952 = `^[a-zA-Z][a-zA-Z0-9\-\.]+[a-zA-Z0-9]$` // https://tools.ietf.org/html/rfc952
40+
hostnameRegexStringRFC1123 = `^([a-zA-Z0-9]{1}[a-zA-Z0-9_-]{0,62}){1}(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*?$` // accepts hostname starting with a digit https://tools.ietf.org/html/rfc1123
41+
btcAddressRegexString = `^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$` // bitcoin address
42+
btcAddressUpperRegexStringBech32 = `^BC1[02-9AC-HJ-NP-Z]{7,76}$` // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32
43+
btcAddressLowerRegexStringBech32 = `^bc1[02-9ac-hj-np-z]{7,76}$` // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32
4444
ethAddressRegexString = `^0x[0-9a-fA-F]{40}$`
4545
ethAddressUpperRegexString = `^0x[0-9A-F]{40}$`
4646
ethAddressLowerRegexString = `^0x[0-9a-f]{40}$`

translations/en/en.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1324,6 +1324,16 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
13241324
{
13251325
tag: "json",
13261326
translation: "{0} must be a valid json string",
1327+
override: false,
1328+
},
1329+
{
1330+
tag: "lowercase",
1331+
translation: "{0} must be a lowercase string",
1332+
override: false,
1333+
},
1334+
{
1335+
tag: "uppercase",
1336+
translation: "{0} must be an uppercase string",
13271337
override: false,
13281338
},
13291339
}

translations/en/en_test.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import (
44
"testing"
55
"time"
66

7+
. "github.com/go-playground/assert/v2"
78
english "github.com/go-playground/locales/en"
89
ut "github.com/go-playground/universal-translator"
9-
. "github.com/go-playground/assert/v2"
1010
"github.com/go-playground/validator/v10"
1111
)
1212

@@ -142,6 +142,8 @@ func TestTranslations(t *testing.T) {
142142
UniqueArray [3]string `validate:"unique"`
143143
UniqueMap map[string]string `validate:"unique"`
144144
JSONString string `validate:"json"`
145+
LowercaseString string `validate:"lowercase"`
146+
UppercaseString string `validate:"uppercase"`
145147
}
146148

147149
var test Test
@@ -184,6 +186,9 @@ func TestTranslations(t *testing.T) {
184186

185187
test.MultiByte = "1234feerf"
186188

189+
test.LowercaseString = "ABCDEFG"
190+
test.UppercaseString = "abcdefg"
191+
187192
s := "toolong"
188193
test.StrPtrMaxLen = &s
189194
test.StrPtrLen = &s
@@ -637,6 +642,14 @@ func TestTranslations(t *testing.T) {
637642
ns: "Test.JSONString",
638643
expected: "JSONString must be a valid json string",
639644
},
645+
{
646+
ns: "Test.LowercaseString",
647+
expected: "LowercaseString must be a lowercase string",
648+
},
649+
{
650+
ns: "Test.UppercaseString",
651+
expected: "UppercaseString must be an uppercase string",
652+
},
640653
}
641654

642655
for _, tt := range tests {

0 commit comments

Comments
 (0)