Add cron support (#1045)

pull/1081/head
Alberto Forcato 2 years ago committed by GitHub
parent 89b91cea99
commit 3ee65f8c59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      README.md
  2. 7
      baked_in.go
  3. 6
      doc.go
  4. 2
      regexes.go
  5. 5
      translations/en/en.go
  6. 5
      translations/it/it.go
  7. 34
      validator_test.go

@ -155,6 +155,7 @@ Baked-in Validations
| btc_addr | Bitcoin Address | | btc_addr | Bitcoin Address |
| btc_addr_bech32 | Bitcoin Bech32 Address (segwit) | | btc_addr_bech32 | Bitcoin Bech32 Address (segwit) |
| credit_card | Credit Card Number | | credit_card | Credit Card Number |
| cron | Cron |
| datetime | Datetime | | datetime | Datetime |
| e164 | e164 formatted phone number | | e164 | e164 formatted phone number |
| email | E-mail String | email | E-mail String

@ -218,6 +218,7 @@ var (
"semver": isSemverFormat, "semver": isSemverFormat,
"dns_rfc1035_label": isDnsRFC1035LabelFormat, "dns_rfc1035_label": isDnsRFC1035LabelFormat,
"credit_card": isCreditCard, "credit_card": isCreditCard,
"cron": isCron,
} }
) )
@ -2579,3 +2580,9 @@ func isCreditCard(fl FieldLevel) bool {
} }
return (sum % 10) == 0 return (sum % 10) == 0
} }
// isCron is the validation function for validating if the current field's value is a valid cron expression
func isCron(fl FieldLevel) bool {
cronString := fl.Field().String()
return cronRegex.MatchString(cronString)
}

@ -1323,6 +1323,12 @@ This validates that a string value contains a valid credit card number using Luh
Usage: credit_card Usage: credit_card
Cron
This validates that a string value contains a valid cron expression.
Usage: cron
Alias Validators and Tags Alias Validators and Tags
NOTE: When returning an error, the tag returned in "FieldError" will be NOTE: When returning an error, the tag returned in "FieldError" will be

@ -64,6 +64,7 @@ const (
bicRegexString = `^[A-Za-z]{6}[A-Za-z0-9]{2}([A-Za-z0-9]{3})?$` bicRegexString = `^[A-Za-z]{6}[A-Za-z0-9]{2}([A-Za-z0-9]{3})?$`
semverRegexString = `^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$` // numbered capture groups https://semver.org/ semverRegexString = `^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$` // numbered capture groups https://semver.org/
dnsRegexStringRFC1035Label = "^[a-z]([-a-z0-9]*[a-z0-9]){0,62}$" dnsRegexStringRFC1035Label = "^[a-z]([-a-z0-9]*[a-z0-9]){0,62}$"
cronRegexString = `(@(annually|yearly|monthly|weekly|daily|hourly|reboot))|(@every (\d+(ns|us|µs|ms|s|m|h))+)|((((\d+,)+\d+|(\d+(\/|-)\d+)|\d+|\*) ?){5,7})`
) )
var ( var (
@ -126,4 +127,5 @@ var (
bicRegex = regexp.MustCompile(bicRegexString) bicRegex = regexp.MustCompile(bicRegexString)
semverRegex = regexp.MustCompile(semverRegexString) semverRegex = regexp.MustCompile(semverRegexString)
dnsRegexRFC1035Label = regexp.MustCompile(dnsRegexStringRFC1035Label) dnsRegexRFC1035Label = regexp.MustCompile(dnsRegexStringRFC1035Label)
cronRegex = regexp.MustCompile(cronRegexString)
) )

@ -1281,6 +1281,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} must be a valid color", translation: "{0} must be a valid color",
override: false, override: false,
}, },
{
tag: "cron",
translation: "{0} must be a valid cron expression",
override: false,
},
{ {
tag: "oneof", tag: "oneof",
translation: "{0} must be one of [{1}]", translation: "{0} must be one of [{1}]",

@ -1132,6 +1132,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} deve essere un colore valido", translation: "{0} deve essere un colore valido",
override: false, override: false,
}, },
{
tag: "cron",
translation: "{0} deve essere una stringa cron valida",
override: false,
},
{ {
tag: "oneof", tag: "oneof",
translation: "{0} deve essere uno di [{1}]", translation: "{0} deve essere uno di [{1}]",

@ -12524,3 +12524,37 @@ func TestMultiOrOperatorGroup(t *testing.T) {
} }
} }
} }
func TestCronExpressionValidation(t *testing.T) {
tests := []struct {
value string `validate:"cron"`
tag string
expected bool
}{
{"0 0 12 * * ?", "cron", true},
{"0 15 10 ? * *", "cron", true},
{"0 15 10 * * ?", "cron", true},
{"0 15 10 * * ? 2005", "cron", true},
{"0 15 10 ? * 6L", "cron", true},
{"0 15 10 ? * 6L 2002-2005", "cron", true},
{"*/20 * * * *", "cron", true},
{"0 15 10 ? * MON-FRI", "cron", true},
{"0 15 10 ? * 6#3", "cron", true},
{"wrong", "cron", false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.value, test.tag)
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf(`Index: %d cron "%s" failed Error: %s`, i, test.value, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf(`Index: %d cron "%s" should have errs`, i, test.value)
}
}
}
}

Loading…
Cancel
Save