diff --git a/README.md b/README.md index 91144491..e702527e 100644 --- a/README.md +++ b/README.md @@ -251,6 +251,8 @@ validate := validator.New(validator.WithRequiredStructEnabled()) | file | Existing File | | filepath | File Path | | image | Image | +| audio | Audio | +| mimetype | MIME Type | | isdefault | Is Default | | len | Length | | max | Maximum | diff --git a/baked_in.go b/baked_in.go index abb5cfe0..f6c5483c 100644 --- a/baked_in.go +++ b/baked_in.go @@ -161,6 +161,8 @@ var ( "startsnotwith": startsNotWith, "endsnotwith": endsNotWith, "image": isImage, + "audio": isAudio, + "mimetype": isMIMEType, "isbn": isISBN, "isbn10": isISBN10, "isbn13": isISBN13, @@ -1670,6 +1672,63 @@ func isFile(fl FieldLevel) bool { panic(fmt.Sprintf("Bad field type %s", field.Type())) } +func detectFileMIMEType(field reflect.Value) (string, bool) { + switch field.Kind() { + case reflect.String: + filePath := field.String() + fileInfo, err := os.Stat(filePath) + if err != nil || fileInfo.IsDir() { + return "", false + } + + file, err := os.Open(filePath) + if err != nil { + return "", false + } + defer func() { + _ = file.Close() + }() + + mime, err := mimetype.DetectReader(file) + if err != nil { + return "", false + } + + return mime.String(), true + } + + panic(fmt.Sprintf("Bad field type %s", field.Type())) +} + +func matchesMIMEType(mime, expected string) bool { + expectedType, expectedSubtype, ok := strings.Cut(strings.TrimSpace(expected), "/") + if !ok || expectedType == "" || expectedSubtype == "" { + return false + } + + mimeType, mimeSubtype, ok := strings.Cut(mime, "/") + if !ok || mimeType == "" || mimeSubtype == "" { + return false + } + + if expectedSubtype == "*" { + return mimeType == expectedType + } + + return mimeType == expectedType && mimeSubtype == expectedSubtype +} + +// isMIMEType is the validation function for validating if the current field's value contains the path to a file +// whose detected MIME type matches the provided validator param in the form type/subtype or type/*. +func isMIMEType(fl FieldLevel) bool { + mime, ok := detectFileMIMEType(fl.Field()) + if !ok { + return false + } + + return matchesMIMEType(mime, fl.Param()) +} + // isImage is the validation function for validating if the current field's value contains the path to a valid image file func isImage(fl FieldLevel) bool { mimetypes := map[string]bool{ @@ -1698,39 +1757,24 @@ func isImage(fl FieldLevel) bool { "image/x-xpixmap": true, "image/x-xwindowdump": true, } - field := fl.Field() - - switch field.Kind() { - case reflect.String: - filePath := field.String() - fileInfo, err := os.Stat(filePath) - if err != nil { - return false - } - - if fileInfo.IsDir() { - return false - } - file, err := os.Open(filePath) - if err != nil { - return false - } - defer func() { - _ = file.Close() - }() + mime, ok := detectFileMIMEType(fl.Field()) + if !ok { + return false + } - mime, err := mimetype.DetectReader(file) - if err != nil { - return false - } + _, ok = mimetypes[mime] + return ok +} - if _, ok := mimetypes[mime.String()]; ok { - return true - } +// isAudio is the validation function for validating if the current field's value contains the path to a valid audio file +func isAudio(fl FieldLevel) bool { + mime, ok := detectFileMIMEType(fl.Field()) + if !ok { + return false } - panic(fmt.Sprintf("Bad field type %s", field.Type())) + return strings.HasPrefix(mime, "audio/") } // isFilePath is the validation function for validating if the current field's value is a valid file path. diff --git a/doc.go b/doc.go index a8550a62..70b56320 100644 --- a/doc.go +++ b/doc.go @@ -987,6 +987,24 @@ This is done using os.Stat and github.com/gabriel-vasile/mimetype Usage: image +# MIME type path + +This validates that a string value contains a valid file path and that +the file exists on the machine and matches the provided MIME type in the +form type/subtype or type/*. +This is done using os.Stat and github.com/gabriel-vasile/mimetype + + Usage: mimetype=image/png + Usage: mimetype=image/* + +# Audio path + +This validates that a string value contains a valid file path and that +the file exists on the machine and is an audio file. +This is done using os.Stat and github.com/gabriel-vasile/mimetype + + Usage: audio + # File Path This validates that a string value contains a valid file path but does not diff --git a/translations/ar/ar.go b/translations/ar/ar.go index ca45e9ac..da2e5437 100644 --- a/translations/ar/ar.go +++ b/translations/ar/ar.go @@ -1205,6 +1205,16 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "يجب أن تكون {0} صورة صالحة", override: false, }, + { + tag: "audio", + translation: "يجب أن يكون {0} ملفًا صوتيًا صالحًا", + override: false, + }, + { + tag: "mimetype", + translation: "يجب أن يكون {0} نوع MIME صالحًا", + override: false, + }, { tag: "cve", translation: "يجب أن يكون {0} معرف CVE صالح", diff --git a/translations/ar/ar_test.go b/translations/ar/ar_test.go index ec8f8cb0..8dd79374 100644 --- a/translations/ar/ar_test.go +++ b/translations/ar/ar_test.go @@ -151,6 +151,8 @@ func TestTranslations(t *testing.T) { PostCodeCountry string PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"` Image string `validate:"image"` + Audio string `validate:"audio"` + MIMEType string `validate:"mimetype=image/png"` BooleanString string `validate:"boolean"` CveString string `validate:"cve"` FQDN string `validate:"fqdn"` @@ -709,6 +711,14 @@ func TestTranslations(t *testing.T) { ns: "Test.Image", expected: "يجب أن تكون Image صورة صالحة", }, + { + ns: "Test.Audio", + expected: "يجب أن يكون Audio ملفًا صوتيًا صالحًا", + }, + { + ns: "Test.MIMEType", + expected: "يجب أن يكون MIMEType نوع MIME صالحًا", + }, { ns: "Test.BooleanString", expected: "يجب أن يكون BooleanString قيمة منطقية صالحة", diff --git a/translations/de/de.go b/translations/de/de.go index c6b7189b..06b135dc 100644 --- a/translations/de/de.go +++ b/translations/de/de.go @@ -1440,6 +1440,16 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} muss ein Bild sein", override: false, }, + { + tag: "audio", + translation: "{0} muss eine gultige Audiodatei sein", + override: false, + }, + { + tag: "mimetype", + translation: "{0} muss ein gueltiger MIME-Typ sein", + override: false, + }, { tag: "cve", translation: "{0} muss eine gültige CVE-Kennung sein", diff --git a/translations/de/de_test.go b/translations/de/de_test.go index 70e8763b..86cad3a0 100644 --- a/translations/de/de_test.go +++ b/translations/de/de_test.go @@ -178,6 +178,8 @@ func TestTranslations(t *testing.T) { PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"` BooleanString string `validate:"boolean"` Image string `validate:"image"` + Audio string `validate:"audio"` + MIMEType string `validate:"mimetype=image/png"` CveString string `validate:"cve"` } @@ -788,6 +790,14 @@ func TestTranslations(t *testing.T) { ns: "Test.Image", expected: "Image muss ein Bild sein", }, + { + ns: "Test.Audio", + expected: "Audio muss eine gultige Audiodatei sein", + }, + { + ns: "Test.MIMEType", + expected: "MIMEType muss ein gueltiger MIME-Typ sein", + }, { ns: "Test.CveString", expected: "CveString muss eine gültige CVE-Kennung sein", diff --git a/translations/en/en.go b/translations/en/en.go index aef99ae1..89dfc8f4 100644 --- a/translations/en/en.go +++ b/translations/en/en.go @@ -1504,6 +1504,16 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} must be a valid image", override: false, }, + { + tag: "audio", + translation: "{0} must be a valid audio file", + override: false, + }, + { + tag: "mimetype", + translation: "{0} must be a valid MIME type", + override: false, + }, { tag: "cve", translation: "{0} must be a valid cve identifier", diff --git a/translations/en/en_test.go b/translations/en/en_test.go index c9d47334..53e0d1c6 100644 --- a/translations/en/en_test.go +++ b/translations/en/en_test.go @@ -46,66 +46,66 @@ func TestTranslations(t *testing.T) { } type Test struct { - Inner Inner - RequiredString string `validate:"required"` - RequiredNumber int `validate:"required"` - RequiredMultiple []string `validate:"required"` - RequiredIf string `validate:"required_if=Inner.RequiredIf abcd"` - RequiredUnless string `validate:"required_unless=Inner.RequiredUnless abcd"` - RequiredWith string `validate:"required_with=Inner.RequiredWith"` - RequiredWithAll string `validate:"required_with_all=Inner.RequiredWith Inner.RequiredWithAll"` - RequiredWithout string `validate:"required_without=Inner.RequiredWithout"` - RequiredWithoutAll string `validate:"required_without_all=Inner.RequiredWithout Inner.RequiredWithoutAll"` - ExcludedIf string `validate:"excluded_if=Inner.ExcludedIf abcd"` - ExcludedUnless string `validate:"excluded_unless=Inner.ExcludedUnless abcd"` - ExcludedWith string `validate:"excluded_with=Inner.ExcludedWith"` - ExcludedWithout string `validate:"excluded_with_all=Inner.ExcludedWithAll"` - ExcludedWithAll string `validate:"excluded_without=Inner.ExcludedWithout"` - ExcludedWithoutAll string `validate:"excluded_without_all=Inner.ExcludedWithoutAll"` - IsDefault string `validate:"isdefault"` - LenString string `validate:"len=1"` - LenNumber float64 `validate:"len=1113.00"` - LenMultiple []string `validate:"len=7"` - MinString string `validate:"min=1"` - MinNumber float64 `validate:"min=1113.00"` - MinMultiple []string `validate:"min=7"` - MaxString string `validate:"max=3"` - MaxNumber float64 `validate:"max=1113.00"` - MaxMultiple []string `validate:"max=7"` - EqString string `validate:"eq=3"` - EqNumber float64 `validate:"eq=2.33"` - EqMultiple []string `validate:"eq=7"` - NeString string `validate:"ne="` - NeNumber float64 `validate:"ne=0.00"` - NeMultiple []string `validate:"ne=0"` - LtString string `validate:"lt=3"` - LtNumber float64 `validate:"lt=5.56"` - LtMultiple []string `validate:"lt=2"` - LtTime time.Time `validate:"lt"` - LteString string `validate:"lte=3"` - LteNumber float64 `validate:"lte=5.56"` - LteMultiple []string `validate:"lte=2"` - LteTime time.Time `validate:"lte"` - GtString string `validate:"gt=3"` - GtNumber float64 `validate:"gt=5.56"` - GtMultiple []string `validate:"gt=2"` - GtTime time.Time `validate:"gt"` - GteString string `validate:"gte=3"` - GteNumber float64 `validate:"gte=5.56"` - GteMultiple []string `validate:"gte=2"` - GteTime time.Time `validate:"gte"` - EqFieldString string `validate:"eqfield=MaxString"` - EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` - NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` - GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` - GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` - LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` - LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` - NeFieldString string `validate:"nefield=EqFieldString"` - GtFieldString string `validate:"gtfield=MaxString"` - GteFieldString string `validate:"gtefield=MaxString"` - LtFieldString string `validate:"ltfield=MaxString"` - LteFieldString string `validate:"ltefield=MaxString"` + Inner Inner + RequiredString string `validate:"required"` + RequiredNumber int `validate:"required"` + RequiredMultiple []string `validate:"required"` + RequiredIf string `validate:"required_if=Inner.RequiredIf abcd"` + RequiredUnless string `validate:"required_unless=Inner.RequiredUnless abcd"` + RequiredWith string `validate:"required_with=Inner.RequiredWith"` + RequiredWithAll string `validate:"required_with_all=Inner.RequiredWith Inner.RequiredWithAll"` + RequiredWithout string `validate:"required_without=Inner.RequiredWithout"` + RequiredWithoutAll string `validate:"required_without_all=Inner.RequiredWithout Inner.RequiredWithoutAll"` + ExcludedIf string `validate:"excluded_if=Inner.ExcludedIf abcd"` + ExcludedUnless string `validate:"excluded_unless=Inner.ExcludedUnless abcd"` + ExcludedWith string `validate:"excluded_with=Inner.ExcludedWith"` + ExcludedWithout string `validate:"excluded_with_all=Inner.ExcludedWithAll"` + ExcludedWithAll string `validate:"excluded_without=Inner.ExcludedWithout"` + ExcludedWithoutAll string `validate:"excluded_without_all=Inner.ExcludedWithoutAll"` + IsDefault string `validate:"isdefault"` + LenString string `validate:"len=1"` + LenNumber float64 `validate:"len=1113.00"` + LenMultiple []string `validate:"len=7"` + MinString string `validate:"min=1"` + MinNumber float64 `validate:"min=1113.00"` + MinMultiple []string `validate:"min=7"` + MaxString string `validate:"max=3"` + MaxNumber float64 `validate:"max=1113.00"` + MaxMultiple []string `validate:"max=7"` + EqString string `validate:"eq=3"` + EqNumber float64 `validate:"eq=2.33"` + EqMultiple []string `validate:"eq=7"` + NeString string `validate:"ne="` + NeNumber float64 `validate:"ne=0.00"` + NeMultiple []string `validate:"ne=0"` + LtString string `validate:"lt=3"` + LtNumber float64 `validate:"lt=5.56"` + LtMultiple []string `validate:"lt=2"` + LtTime time.Time `validate:"lt"` + LteString string `validate:"lte=3"` + LteNumber float64 `validate:"lte=5.56"` + LteMultiple []string `validate:"lte=2"` + LteTime time.Time `validate:"lte"` + GtString string `validate:"gt=3"` + GtNumber float64 `validate:"gt=5.56"` + GtMultiple []string `validate:"gt=2"` + GtTime time.Time `validate:"gt"` + GteString string `validate:"gte=3"` + GteNumber float64 `validate:"gte=5.56"` + GteMultiple []string `validate:"gte=2"` + GteTime time.Time `validate:"gte"` + EqFieldString string `validate:"eqfield=MaxString"` + EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` + NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` + GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` + GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` + LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` + LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` + NeFieldString string `validate:"nefield=EqFieldString"` + GtFieldString string `validate:"gtfield=MaxString"` + GteFieldString string `validate:"gtefield=MaxString"` + LtFieldString string `validate:"ltfield=MaxString"` + LteFieldString string `validate:"ltefield=MaxString"` AlphaString string `validate:"alpha"` AlphanumString string `validate:"alphanum"` AlphaSpaceString string `validate:"alphaspace"` @@ -113,84 +113,86 @@ func TestTranslations(t *testing.T) { AlphaUnicodeString string `validate:"alphaunicode"` AlphaNumUnicodeString string `validate:"alphanumunicode"` NumericString string `validate:"numeric"` - NumberString string `validate:"number"` - HexadecimalString string `validate:"hexadecimal"` - HexColorString string `validate:"hexcolor"` - RGBColorString string `validate:"rgb"` - RGBAColorString string `validate:"rgba"` - HSLColorString string `validate:"hsl"` - HSLAColorString string `validate:"hsla"` - Email string `validate:"email"` - URL string `validate:"url"` - URI string `validate:"uri"` - Base64 string `validate:"base64"` - Contains string `validate:"contains=purpose"` - ContainsAny string `validate:"containsany=!@#$"` - Excludes string `validate:"excludes=text"` - ExcludesAll string `validate:"excludesall=!@#$"` - ExcludesRune string `validate:"excludesrune=☻"` - ISBN string `validate:"isbn"` - ISBN10 string `validate:"isbn10"` - ISBN13 string `validate:"isbn13"` - ISSN string `validate:"issn"` - URN string `validate:"urn_rfc2141"` - UUID string `validate:"uuid"` - UUID3 string `validate:"uuid3"` - UUID4 string `validate:"uuid4"` - UUID5 string `validate:"uuid5"` - ULID string `validate:"ulid"` - ASCII string `validate:"ascii"` - PrintableASCII string `validate:"printascii"` - MultiByte string `validate:"multibyte"` - DataURI string `validate:"datauri"` - Latitude string `validate:"latitude"` - Longitude string `validate:"longitude"` - SSN string `validate:"ssn"` - IP string `validate:"ip"` - IPv4 string `validate:"ipv4"` - IPv6 string `validate:"ipv6"` - CIDR string `validate:"cidr"` - CIDRv4 string `validate:"cidrv4"` - CIDRv6 string `validate:"cidrv6"` - TCPAddr string `validate:"tcp_addr"` - TCPAddrv4 string `validate:"tcp4_addr"` - TCPAddrv6 string `validate:"tcp6_addr"` - UDPAddr string `validate:"udp_addr"` - UDPAddrv4 string `validate:"udp4_addr"` - UDPAddrv6 string `validate:"udp6_addr"` - IPAddr string `validate:"ip_addr"` - IPAddrv4 string `validate:"ip4_addr"` - IPAddrv6 string `validate:"ip6_addr"` - UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future - MAC string `validate:"mac"` - FQDN string `validate:"fqdn"` - IsColor string `validate:"iscolor"` - StrPtrMinLen *string `validate:"min=10"` - StrPtrMaxLen *string `validate:"max=1"` - StrPtrLen *string `validate:"len=2"` - StrPtrLt *string `validate:"lt=1"` - StrPtrLte *string `validate:"lte=1"` - StrPtrGt *string `validate:"gt=10"` - StrPtrGte *string `validate:"gte=10"` - OneOfString string `validate:"oneof=red green"` - OneOfInt int `validate:"oneof=5 63"` - UniqueSlice []string `validate:"unique"` - UniqueArray [3]string `validate:"unique"` - UniqueMap map[string]string `validate:"unique"` - JSONString string `validate:"json"` - JWTString string `validate:"jwt"` - LowercaseString string `validate:"lowercase"` - UppercaseString string `validate:"uppercase"` - Datetime string `validate:"datetime=2006-01-02"` - PostCode string `validate:"postcode_iso3166_alpha2=SG"` - PostCodeCountry string - PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"` - BooleanString string `validate:"boolean"` - Image string `validate:"image"` - CveString string `validate:"cve"` - MinDuration time.Duration `validate:"min=1h30m,max=2h"` - MaxDuration time.Duration `validate:"min=1h30m,max=2h"` - ValidateFn Foo `validate:"validateFn=IsBar"` + NumberString string `validate:"number"` + HexadecimalString string `validate:"hexadecimal"` + HexColorString string `validate:"hexcolor"` + RGBColorString string `validate:"rgb"` + RGBAColorString string `validate:"rgba"` + HSLColorString string `validate:"hsl"` + HSLAColorString string `validate:"hsla"` + Email string `validate:"email"` + URL string `validate:"url"` + URI string `validate:"uri"` + Base64 string `validate:"base64"` + Contains string `validate:"contains=purpose"` + ContainsAny string `validate:"containsany=!@#$"` + Excludes string `validate:"excludes=text"` + ExcludesAll string `validate:"excludesall=!@#$"` + ExcludesRune string `validate:"excludesrune=☻"` + ISBN string `validate:"isbn"` + ISBN10 string `validate:"isbn10"` + ISBN13 string `validate:"isbn13"` + ISSN string `validate:"issn"` + URN string `validate:"urn_rfc2141"` + UUID string `validate:"uuid"` + UUID3 string `validate:"uuid3"` + UUID4 string `validate:"uuid4"` + UUID5 string `validate:"uuid5"` + ULID string `validate:"ulid"` + ASCII string `validate:"ascii"` + PrintableASCII string `validate:"printascii"` + MultiByte string `validate:"multibyte"` + DataURI string `validate:"datauri"` + Latitude string `validate:"latitude"` + Longitude string `validate:"longitude"` + SSN string `validate:"ssn"` + IP string `validate:"ip"` + IPv4 string `validate:"ipv4"` + IPv6 string `validate:"ipv6"` + CIDR string `validate:"cidr"` + CIDRv4 string `validate:"cidrv4"` + CIDRv6 string `validate:"cidrv6"` + TCPAddr string `validate:"tcp_addr"` + TCPAddrv4 string `validate:"tcp4_addr"` + TCPAddrv6 string `validate:"tcp6_addr"` + UDPAddr string `validate:"udp_addr"` + UDPAddrv4 string `validate:"udp4_addr"` + UDPAddrv6 string `validate:"udp6_addr"` + IPAddr string `validate:"ip_addr"` + IPAddrv4 string `validate:"ip4_addr"` + IPAddrv6 string `validate:"ip6_addr"` + UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future + MAC string `validate:"mac"` + FQDN string `validate:"fqdn"` + IsColor string `validate:"iscolor"` + StrPtrMinLen *string `validate:"min=10"` + StrPtrMaxLen *string `validate:"max=1"` + StrPtrLen *string `validate:"len=2"` + StrPtrLt *string `validate:"lt=1"` + StrPtrLte *string `validate:"lte=1"` + StrPtrGt *string `validate:"gt=10"` + StrPtrGte *string `validate:"gte=10"` + OneOfString string `validate:"oneof=red green"` + OneOfInt int `validate:"oneof=5 63"` + UniqueSlice []string `validate:"unique"` + UniqueArray [3]string `validate:"unique"` + UniqueMap map[string]string `validate:"unique"` + JSONString string `validate:"json"` + JWTString string `validate:"jwt"` + LowercaseString string `validate:"lowercase"` + UppercaseString string `validate:"uppercase"` + Datetime string `validate:"datetime=2006-01-02"` + PostCode string `validate:"postcode_iso3166_alpha2=SG"` + PostCodeCountry string + PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"` + BooleanString string `validate:"boolean"` + Image string `validate:"image"` + Audio string `validate:"audio"` + MIMEType string `validate:"mimetype=image/png"` + CveString string `validate:"cve"` + MinDuration time.Duration `validate:"min=1h30m,max=2h"` + MaxDuration time.Duration `validate:"min=1h30m,max=2h"` + ValidateFn Foo `validate:"validateFn=IsBar"` } var test Test @@ -823,6 +825,14 @@ func TestTranslations(t *testing.T) { ns: "Test.Image", expected: "Image must be a valid image", }, + { + ns: "Test.Audio", + expected: "Audio must be a valid audio file", + }, + { + ns: "Test.MIMEType", + expected: "MIMEType must be a valid MIME type", + }, { ns: "Test.CveString", expected: "CveString must be a valid cve identifier", diff --git a/translations/es/es.go b/translations/es/es.go index dbb6c9cf..61a78421 100644 --- a/translations/es/es.go +++ b/translations/es/es.go @@ -1299,6 +1299,16 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} debe ser una imagen válida", override: false, }, + { + tag: "audio", + translation: "{0} debe ser un archivo de audio válido", + override: false, + }, + { + tag: "mimetype", + translation: "{0} debe ser un tipo MIME válido", + override: false, + }, } for _, t := range translations { diff --git a/translations/es/es_test.go b/translations/es/es_test.go index cd4b0dfc..60eb6491 100644 --- a/translations/es/es_test.go +++ b/translations/es/es_test.go @@ -144,6 +144,8 @@ func TestTranslations(t *testing.T) { UniqueArray [3]string `validate:"unique"` UniqueMap map[string]string `validate:"unique"` Image string `validate:"image"` + Audio string `validate:"audio"` + MIMEType string `validate:"mimetype=image/png"` } var test Test @@ -647,6 +649,14 @@ func TestTranslations(t *testing.T) { ns: "Test.Image", expected: "Image debe ser una imagen válida", }, + { + ns: "Test.Audio", + expected: "Audio debe ser un archivo de audio válido", + }, + { + ns: "Test.MIMEType", + expected: "MIMEType debe ser un tipo MIME válido", + }, } for _, tt := range tests { diff --git a/translations/fa/fa.go b/translations/fa/fa.go index 91171dda..4f4df5a6 100644 --- a/translations/fa/fa.go +++ b/translations/fa/fa.go @@ -1351,6 +1351,16 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} باید یک تصویر معتبر باشد", override: false, }, + { + tag: "audio", + translation: "{0} باید یک فایل صوتی معتبر باشد", + override: false, + }, + { + tag: "mimetype", + translation: "{0} باید یک نوع MIME معتبر باشد", + override: false, + }, } for _, t := range translations { diff --git a/translations/fa/fa_test.go b/translations/fa/fa_test.go index 8d1f563e..7b80807e 100644 --- a/translations/fa/fa_test.go +++ b/translations/fa/fa_test.go @@ -150,6 +150,8 @@ func TestTranslations(t *testing.T) { PostCodeCountry string PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"` Image string `validate:"image"` + Audio string `validate:"audio"` + MIMEType string `validate:"mimetype=image/png"` } var test Test @@ -681,6 +683,14 @@ func TestTranslations(t *testing.T) { ns: "Test.Image", expected: "Image باید یک تصویر معتبر باشد", }, + { + ns: "Test.Audio", + expected: "Audio باید یک فایل صوتی معتبر باشد", + }, + { + ns: "Test.MIMEType", + expected: "MIMEType باید یک نوع MIME معتبر باشد", + }, } for _, tt := range tests { diff --git a/translations/fr/fr.go b/translations/fr/fr.go index 8b7b3ee6..b3a8dc37 100644 --- a/translations/fr/fr.go +++ b/translations/fr/fr.go @@ -1284,6 +1284,16 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} doit être une image valide", override: false, }, + { + tag: "audio", + translation: "{0} doit être un fichier audio valide", + override: false, + }, + { + tag: "mimetype", + translation: "{0} doit être un type MIME valide", + override: false, + }, } for _, t := range translations { diff --git a/translations/fr/fr_test.go b/translations/fr/fr_test.go index bcb48720..4b0c787f 100644 --- a/translations/fr/fr_test.go +++ b/translations/fr/fr_test.go @@ -140,6 +140,8 @@ func TestTranslations(t *testing.T) { OneOfString string `validate:"oneof=red green"` OneOfInt int `validate:"oneof=5 63"` Image string `validate:"image"` + Audio string `validate:"audio"` + MIMEType string `validate:"mimetype=image/png"` } var test Test @@ -628,6 +630,14 @@ func TestTranslations(t *testing.T) { ns: "Test.Image", expected: "Image doit être une image valide", }, + { + ns: "Test.Audio", + expected: "Audio doit être un fichier audio valide", + }, + { + ns: "Test.MIMEType", + expected: "MIMEType doit être un type MIME valide", + }, } for _, tt := range tests { diff --git a/translations/id/id.go b/translations/id/id.go index 2e924f0d..a3008653 100644 --- a/translations/id/id.go +++ b/translations/id/id.go @@ -1187,6 +1187,16 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} harus berupa gambar yang valid", override: false, }, + { + tag: "audio", + translation: "{0} harus berupa berkas audio yang valid", + override: false, + }, + { + tag: "mimetype", + translation: "{0} harus berupa tipe MIME yang valid", + override: false, + }, { tag: "isdefault", translation: "{0} harus berupa nilai default", diff --git a/translations/id/id_test.go b/translations/id/id_test.go index 0f56ba13..bdfabbea 100644 --- a/translations/id/id_test.go +++ b/translations/id/id_test.go @@ -1149,6 +1149,8 @@ func TestOtherTagsTranslations(t *testing.T) { File string `validate:"file"` FilePath string `validate:"filepath"` Image string `validate:"image"` + Audio string `validate:"audio"` + MIMEType string `validate:"mimetype=image/png"` LenString string `validate:"len=5"` LenSlice []string `validate:"len=3"` LenNumber int `validate:"len=10"` @@ -1240,6 +1242,14 @@ func TestOtherTagsTranslations(t *testing.T) { ns: "TestOtherTags.Image", expected: "Image harus berupa gambar yang valid", }, + { + ns: "TestOtherTags.Audio", + expected: "Audio harus berupa berkas audio yang valid", + }, + { + ns: "TestOtherTags.MIMEType", + expected: "MIMEType harus berupa tipe MIME yang valid", + }, { ns: "TestOtherTags.LenString", expected: "panjang LenString harus 5 karakter", diff --git a/translations/it/it.go b/translations/it/it.go index 419f1104..1a93ae6d 100644 --- a/translations/it/it.go +++ b/translations/it/it.go @@ -1218,6 +1218,16 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} deve essere uno specificatore di lingua BCP47 valido", override: false, }, + { + tag: "audio", + translation: "{0} deve essere un file audio valido", + override: false, + }, + { + tag: "mimetype", + translation: "{0} deve essere un tipo MIME valido", + override: false, + }, } for _, t := range translations { diff --git a/translations/it/it_test.go b/translations/it/it_test.go index 4e39c52e..70727be6 100644 --- a/translations/it/it_test.go +++ b/translations/it/it_test.go @@ -156,6 +156,8 @@ func TestTranslations(t *testing.T) { PostCodeCountry string PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"` Image string `validate:"image"` + Audio string `validate:"audio"` + MIMEType string `validate:"mimetype=image/png"` } var test Test @@ -716,6 +718,14 @@ func TestTranslations(t *testing.T) { ns: "Test.Image", expected: "Image deve essere un'immagine valida", }, + { + ns: "Test.Audio", + expected: "Audio deve essere un file audio valido", + }, + { + ns: "Test.MIMEType", + expected: "MIMEType deve essere un tipo MIME valido", + }, } for _, tt := range tests { diff --git a/translations/ja/ja.go b/translations/ja/ja.go index 4efc1b93..f15eb08c 100644 --- a/translations/ja/ja.go +++ b/translations/ja/ja.go @@ -1349,6 +1349,16 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} は有効な画像でなければなりません", override: false, }, + { + tag: "audio", + translation: "{0} は有効な音声ファイルでなければなりません", + override: false, + }, + { + tag: "mimetype", + translation: "{0} は有効なMIMEタイプでなければなりません", + override: false, + }, { tag: "json", translation: "{0}は正しいJSON文字列でなければなりません", diff --git a/translations/ja/ja_test.go b/translations/ja/ja_test.go index 1e5d4e03..5b89906c 100644 --- a/translations/ja/ja_test.go +++ b/translations/ja/ja_test.go @@ -154,6 +154,8 @@ func TestTranslations(t *testing.T) { PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"` BooleanString string `validate:"boolean"` Image string `validate:"image"` + Audio string `validate:"audio"` + MIMEType string `validate:"mimetype=image/png"` } var test Test @@ -656,6 +658,14 @@ func TestTranslations(t *testing.T) { ns: "Test.Image", expected: "Image は有効な画像でなければなりません", }, + { + ns: "Test.Audio", + expected: "Audio は有効な音声ファイルでなければなりません", + }, + { + ns: "Test.MIMEType", + expected: "MIMEType は有効なMIMEタイプでなければなりません", + }, { ns: "Test.UniqueSlice", expected: "UniqueSliceは一意な値のみを含まなければなりません", diff --git a/translations/ko/ko.go b/translations/ko/ko.go index 288074a4..bd2cb889 100644 --- a/translations/ko/ko.go +++ b/translations/ko/ko.go @@ -1456,6 +1456,16 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0}은(는) 유효한 이미지여야 합니다.", override: false, }, + { + tag: "audio", + translation: "{0}은(는) 유효한 오디오 파일이어야 합니다.", + override: false, + }, + { + tag: "mimetype", + translation: "{0}은(는) 유효한 MIME 타입이어야 합니다.", + override: false, + }, { tag: "cve", translation: "{0}은(는) 유효한 CVE 식별자여야 합니다.", diff --git a/translations/ko/ko_test.go b/translations/ko/ko_test.go index ccb19383..8764e3f5 100644 --- a/translations/ko/ko_test.go +++ b/translations/ko/ko_test.go @@ -42,66 +42,66 @@ func TestTranslations(t *testing.T) { } type Test struct { - Inner Inner - RequiredString string `validate:"required"` - RequiredNumber int `validate:"required"` - RequiredMultiple []string `validate:"required"` - RequiredIf string `validate:"required_if=Inner.RequiredIf abcd"` - RequiredUnless string `validate:"required_unless=Inner.RequiredUnless abcd"` - RequiredWith string `validate:"required_with=Inner.RequiredWith"` - RequiredWithAll string `validate:"required_with_all=Inner.RequiredWith Inner.RequiredWithAll"` - RequiredWithout string `validate:"required_without=Inner.RequiredWithout"` - RequiredWithoutAll string `validate:"required_without_all=Inner.RequiredWithout Inner.RequiredWithoutAll"` - ExcludedIf string `validate:"excluded_if=Inner.ExcludedIf abcd"` - ExcludedUnless string `validate:"excluded_unless=Inner.ExcludedUnless abcd"` - ExcludedWith string `validate:"excluded_with=Inner.ExcludedWith"` - ExcludedWithout string `validate:"excluded_with_all=Inner.ExcludedWithAll"` - ExcludedWithAll string `validate:"excluded_without=Inner.ExcludedWithout"` - ExcludedWithoutAll string `validate:"excluded_without_all=Inner.ExcludedWithoutAll"` - IsDefault string `validate:"isdefault"` - LenString string `validate:"len=1"` - LenNumber float64 `validate:"len=1113.00"` - LenMultiple []string `validate:"len=7"` - MinString string `validate:"min=1"` - MinNumber float64 `validate:"min=1113.00"` - MinMultiple []string `validate:"min=7"` - MaxString string `validate:"max=3"` - MaxNumber float64 `validate:"max=1113.00"` - MaxMultiple []string `validate:"max=7"` - EqString string `validate:"eq=3"` - EqNumber float64 `validate:"eq=2.33"` - EqMultiple []string `validate:"eq=7"` - NeString string `validate:"ne="` - NeNumber float64 `validate:"ne=0.00"` - NeMultiple []string `validate:"ne=0"` - LtString string `validate:"lt=3"` - LtNumber float64 `validate:"lt=5.56"` - LtMultiple []string `validate:"lt=2"` - LtTime time.Time `validate:"lt"` - LteString string `validate:"lte=3"` - LteNumber float64 `validate:"lte=5.56"` - LteMultiple []string `validate:"lte=2"` - LteTime time.Time `validate:"lte"` - GtString string `validate:"gt=3"` - GtNumber float64 `validate:"gt=5.56"` - GtMultiple []string `validate:"gt=2"` - GtTime time.Time `validate:"gt"` - GteString string `validate:"gte=3"` - GteNumber float64 `validate:"gte=5.56"` - GteMultiple []string `validate:"gte=2"` - GteTime time.Time `validate:"gte"` - EqFieldString string `validate:"eqfield=MaxString"` - EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` - NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` - GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` - GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` - LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` - LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` - NeFieldString string `validate:"nefield=EqFieldString"` - GtFieldString string `validate:"gtfield=MaxString"` - GteFieldString string `validate:"gtefield=MaxString"` - LtFieldString string `validate:"ltfield=MaxString"` - LteFieldString string `validate:"ltefield=MaxString"` + Inner Inner + RequiredString string `validate:"required"` + RequiredNumber int `validate:"required"` + RequiredMultiple []string `validate:"required"` + RequiredIf string `validate:"required_if=Inner.RequiredIf abcd"` + RequiredUnless string `validate:"required_unless=Inner.RequiredUnless abcd"` + RequiredWith string `validate:"required_with=Inner.RequiredWith"` + RequiredWithAll string `validate:"required_with_all=Inner.RequiredWith Inner.RequiredWithAll"` + RequiredWithout string `validate:"required_without=Inner.RequiredWithout"` + RequiredWithoutAll string `validate:"required_without_all=Inner.RequiredWithout Inner.RequiredWithoutAll"` + ExcludedIf string `validate:"excluded_if=Inner.ExcludedIf abcd"` + ExcludedUnless string `validate:"excluded_unless=Inner.ExcludedUnless abcd"` + ExcludedWith string `validate:"excluded_with=Inner.ExcludedWith"` + ExcludedWithout string `validate:"excluded_with_all=Inner.ExcludedWithAll"` + ExcludedWithAll string `validate:"excluded_without=Inner.ExcludedWithout"` + ExcludedWithoutAll string `validate:"excluded_without_all=Inner.ExcludedWithoutAll"` + IsDefault string `validate:"isdefault"` + LenString string `validate:"len=1"` + LenNumber float64 `validate:"len=1113.00"` + LenMultiple []string `validate:"len=7"` + MinString string `validate:"min=1"` + MinNumber float64 `validate:"min=1113.00"` + MinMultiple []string `validate:"min=7"` + MaxString string `validate:"max=3"` + MaxNumber float64 `validate:"max=1113.00"` + MaxMultiple []string `validate:"max=7"` + EqString string `validate:"eq=3"` + EqNumber float64 `validate:"eq=2.33"` + EqMultiple []string `validate:"eq=7"` + NeString string `validate:"ne="` + NeNumber float64 `validate:"ne=0.00"` + NeMultiple []string `validate:"ne=0"` + LtString string `validate:"lt=3"` + LtNumber float64 `validate:"lt=5.56"` + LtMultiple []string `validate:"lt=2"` + LtTime time.Time `validate:"lt"` + LteString string `validate:"lte=3"` + LteNumber float64 `validate:"lte=5.56"` + LteMultiple []string `validate:"lte=2"` + LteTime time.Time `validate:"lte"` + GtString string `validate:"gt=3"` + GtNumber float64 `validate:"gt=5.56"` + GtMultiple []string `validate:"gt=2"` + GtTime time.Time `validate:"gt"` + GteString string `validate:"gte=3"` + GteNumber float64 `validate:"gte=5.56"` + GteMultiple []string `validate:"gte=2"` + GteTime time.Time `validate:"gte"` + EqFieldString string `validate:"eqfield=MaxString"` + EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` + NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` + GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` + GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` + LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` + LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` + NeFieldString string `validate:"nefield=EqFieldString"` + GtFieldString string `validate:"gtfield=MaxString"` + GteFieldString string `validate:"gtefield=MaxString"` + LtFieldString string `validate:"ltfield=MaxString"` + LteFieldString string `validate:"ltefield=MaxString"` AlphaString string `validate:"alpha"` AlphanumString string `validate:"alphanum"` AlphaSpaceString string `validate:"alphaspace"` @@ -109,80 +109,82 @@ func TestTranslations(t *testing.T) { AlphaUnicodeString string `validate:"alphaunicode"` AlphaNumUnicodeString string `validate:"alphanumunicode"` NumericString string `validate:"numeric"` - NumberString string `validate:"number"` - HexadecimalString string `validate:"hexadecimal"` - HexColorString string `validate:"hexcolor"` - RGBColorString string `validate:"rgb"` - RGBAColorString string `validate:"rgba"` - HSLColorString string `validate:"hsl"` - HSLAColorString string `validate:"hsla"` - Email string `validate:"email"` - URL string `validate:"url"` - URI string `validate:"uri"` - Base64 string `validate:"base64"` - Contains string `validate:"contains=purpose"` - ContainsAny string `validate:"containsany=!@#$"` - Excludes string `validate:"excludes=text"` - ExcludesAll string `validate:"excludesall=!@#$"` - ExcludesRune string `validate:"excludesrune=☻"` - ISBN string `validate:"isbn"` - ISBN10 string `validate:"isbn10"` - ISBN13 string `validate:"isbn13"` - ISSN string `validate:"issn"` - UUID string `validate:"uuid"` - UUID3 string `validate:"uuid3"` - UUID4 string `validate:"uuid4"` - UUID5 string `validate:"uuid5"` - ULID string `validate:"ulid"` - ASCII string `validate:"ascii"` - PrintableASCII string `validate:"printascii"` - MultiByte string `validate:"multibyte"` - DataURI string `validate:"datauri"` - Latitude string `validate:"latitude"` - Longitude string `validate:"longitude"` - SSN string `validate:"ssn"` - IP string `validate:"ip"` - IPv4 string `validate:"ipv4"` - IPv6 string `validate:"ipv6"` - CIDR string `validate:"cidr"` - CIDRv4 string `validate:"cidrv4"` - CIDRv6 string `validate:"cidrv6"` - TCPAddr string `validate:"tcp_addr"` - TCPAddrv4 string `validate:"tcp4_addr"` - TCPAddrv6 string `validate:"tcp6_addr"` - UDPAddr string `validate:"udp_addr"` - UDPAddrv4 string `validate:"udp4_addr"` - UDPAddrv6 string `validate:"udp6_addr"` - IPAddr string `validate:"ip_addr"` - IPAddrv4 string `validate:"ip4_addr"` - IPAddrv6 string `validate:"ip6_addr"` - UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future - MAC string `validate:"mac"` - FQDN string `validate:"fqdn"` - IsColor string `validate:"iscolor"` - StrPtrMinLen *string `validate:"min=10"` - StrPtrMaxLen *string `validate:"max=1"` - StrPtrLen *string `validate:"len=2"` - StrPtrLt *string `validate:"lt=1"` - StrPtrLte *string `validate:"lte=1"` - StrPtrGt *string `validate:"gt=10"` - StrPtrGte *string `validate:"gte=10"` - OneOfString string `validate:"oneof=red green"` - OneOfInt int `validate:"oneof=5 63"` - UniqueSlice []string `validate:"unique"` - UniqueArray [3]string `validate:"unique"` - UniqueMap map[string]string `validate:"unique"` - JSONString string `validate:"json"` - JWTString string `validate:"jwt"` - LowercaseString string `validate:"lowercase"` - UppercaseString string `validate:"uppercase"` - Datetime string `validate:"datetime=2006-01-02"` - PostCode string `validate:"postcode_iso3166_alpha2=SG"` - PostCodeCountry string - PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"` - BooleanString string `validate:"boolean"` - Image string `validate:"image"` - CveString string `validate:"cve"` + NumberString string `validate:"number"` + HexadecimalString string `validate:"hexadecimal"` + HexColorString string `validate:"hexcolor"` + RGBColorString string `validate:"rgb"` + RGBAColorString string `validate:"rgba"` + HSLColorString string `validate:"hsl"` + HSLAColorString string `validate:"hsla"` + Email string `validate:"email"` + URL string `validate:"url"` + URI string `validate:"uri"` + Base64 string `validate:"base64"` + Contains string `validate:"contains=purpose"` + ContainsAny string `validate:"containsany=!@#$"` + Excludes string `validate:"excludes=text"` + ExcludesAll string `validate:"excludesall=!@#$"` + ExcludesRune string `validate:"excludesrune=☻"` + ISBN string `validate:"isbn"` + ISBN10 string `validate:"isbn10"` + ISBN13 string `validate:"isbn13"` + ISSN string `validate:"issn"` + UUID string `validate:"uuid"` + UUID3 string `validate:"uuid3"` + UUID4 string `validate:"uuid4"` + UUID5 string `validate:"uuid5"` + ULID string `validate:"ulid"` + ASCII string `validate:"ascii"` + PrintableASCII string `validate:"printascii"` + MultiByte string `validate:"multibyte"` + DataURI string `validate:"datauri"` + Latitude string `validate:"latitude"` + Longitude string `validate:"longitude"` + SSN string `validate:"ssn"` + IP string `validate:"ip"` + IPv4 string `validate:"ipv4"` + IPv6 string `validate:"ipv6"` + CIDR string `validate:"cidr"` + CIDRv4 string `validate:"cidrv4"` + CIDRv6 string `validate:"cidrv6"` + TCPAddr string `validate:"tcp_addr"` + TCPAddrv4 string `validate:"tcp4_addr"` + TCPAddrv6 string `validate:"tcp6_addr"` + UDPAddr string `validate:"udp_addr"` + UDPAddrv4 string `validate:"udp4_addr"` + UDPAddrv6 string `validate:"udp6_addr"` + IPAddr string `validate:"ip_addr"` + IPAddrv4 string `validate:"ip4_addr"` + IPAddrv6 string `validate:"ip6_addr"` + UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future + MAC string `validate:"mac"` + FQDN string `validate:"fqdn"` + IsColor string `validate:"iscolor"` + StrPtrMinLen *string `validate:"min=10"` + StrPtrMaxLen *string `validate:"max=1"` + StrPtrLen *string `validate:"len=2"` + StrPtrLt *string `validate:"lt=1"` + StrPtrLte *string `validate:"lte=1"` + StrPtrGt *string `validate:"gt=10"` + StrPtrGte *string `validate:"gte=10"` + OneOfString string `validate:"oneof=red green"` + OneOfInt int `validate:"oneof=5 63"` + UniqueSlice []string `validate:"unique"` + UniqueArray [3]string `validate:"unique"` + UniqueMap map[string]string `validate:"unique"` + JSONString string `validate:"json"` + JWTString string `validate:"jwt"` + LowercaseString string `validate:"lowercase"` + UppercaseString string `validate:"uppercase"` + Datetime string `validate:"datetime=2006-01-02"` + PostCode string `validate:"postcode_iso3166_alpha2=SG"` + PostCodeCountry string + PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"` + BooleanString string `validate:"boolean"` + Image string `validate:"image"` + Audio string `validate:"audio"` + MIMEType string `validate:"mimetype=image/png"` + CveString string `validate:"cve"` } var test Test @@ -812,6 +814,14 @@ func TestTranslations(t *testing.T) { ns: "Test.Image", expected: "Image은(는) 유효한 이미지여야 합니다.", }, + { + ns: "Test.Audio", + expected: "Audio은(는) 유효한 오디오 파일이어야 합니다.", + }, + { + ns: "Test.MIMEType", + expected: "MIMEType은(는) 유효한 MIME 타입이어야 합니다.", + }, { ns: "Test.CveString", expected: "CveString은(는) 유효한 CVE 식별자여야 합니다.", diff --git a/translations/nl/nl.go b/translations/nl/nl.go index 33235740..62b0c758 100644 --- a/translations/nl/nl.go +++ b/translations/nl/nl.go @@ -1284,6 +1284,16 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} moet een geldige afbeelding zijn", override: false, }, + { + tag: "audio", + translation: "{0} moet een geldig audiobestand zijn", + override: false, + }, + { + tag: "mimetype", + translation: "{0} moet een geldig MIME-type zijn", + override: false, + }, } for _, t := range translations { diff --git a/translations/nl/nl_test.go b/translations/nl/nl_test.go index 49894d2f..5682daae 100644 --- a/translations/nl/nl_test.go +++ b/translations/nl/nl_test.go @@ -140,6 +140,8 @@ func TestTranslations(t *testing.T) { OneOfString string `validate:"oneof=red green"` OneOfInt int `validate:"oneof=5 63"` Image string `validate:"image"` + Audio string `validate:"audio"` + MIMEType string `validate:"mimetype=image/png"` } var test Test @@ -628,6 +630,14 @@ func TestTranslations(t *testing.T) { ns: "Test.Image", expected: "Image moet een geldige afbeelding zijn", }, + { + ns: "Test.Audio", + expected: "Audio moet een geldig audiobestand zijn", + }, + { + ns: "Test.MIMEType", + expected: "MIMEType moet een geldig MIME-type zijn", + }, } for _, tt := range tests { diff --git a/translations/pl/pl.go b/translations/pl/pl.go index a122667e..4654d1ad 100644 --- a/translations/pl/pl.go +++ b/translations/pl/pl.go @@ -1173,6 +1173,16 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} musi być obrazem", override: false, }, + { + tag: "audio", + translation: "{0} musi być prawidłowym plikiem audio", + override: false, + }, + { + tag: "mimetype", + translation: "{0} musi być poprawnym typem MIME", + override: false, + }, { tag: "cve", translation: "{0} musi być poprawnym identyfikatorem CVE", diff --git a/translations/pl/pl_test.go b/translations/pl/pl_test.go index 0b40eaef..411066cb 100644 --- a/translations/pl/pl_test.go +++ b/translations/pl/pl_test.go @@ -186,6 +186,8 @@ func TestTranslations(t *testing.T) { PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"` BooleanString string `validate:"boolean"` Image string `validate:"image"` + Audio string `validate:"audio"` + MIMEType string `validate:"mimetype=image/png"` CveString string `validate:"cve"` } @@ -816,6 +818,14 @@ func TestTranslations(t *testing.T) { ns: "Test.Image", expected: "Image musi być obrazem", }, + { + ns: "Test.Audio", + expected: "Audio musi być prawidłowym plikiem audio", + }, + { + ns: "Test.MIMEType", + expected: "MIMEType musi być poprawnym typem MIME", + }, { ns: "Test.CveString", expected: "CveString musi być poprawnym identyfikatorem CVE", diff --git a/translations/pt/pt.go b/translations/pt/pt.go index d7a225f3..a31e0a96 100644 --- a/translations/pt/pt.go +++ b/translations/pt/pt.go @@ -1320,6 +1320,16 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} deve ser uma imagem válida", override: false, }, + { + tag: "audio", + translation: "{0} deve ser um arquivo de áudio válido", + override: false, + }, + { + tag: "mimetype", + translation: "{0} deve ser um tipo MIME válido", + override: false, + }, } for _, t := range translations { diff --git a/translations/pt/pt_test.go b/translations/pt/pt_test.go index 7b074e18..3793c3fc 100644 --- a/translations/pt/pt_test.go +++ b/translations/pt/pt_test.go @@ -148,6 +148,8 @@ func TestTranslations(t *testing.T) { UppercaseString string `validate:"uppercase"` Datetime string `validate:"datetime=2006-01-02"` Image string `validate:"image"` + Audio string `validate:"audio"` + MIMEType string `validate:"mimetype=image/png"` } var test Test @@ -671,6 +673,14 @@ func TestTranslations(t *testing.T) { ns: "Test.Image", expected: "Image deve ser uma imagem válida", }, + { + ns: "Test.Audio", + expected: "Audio deve ser um arquivo de áudio válido", + }, + { + ns: "Test.MIMEType", + expected: "MIMEType deve ser um tipo MIME válido", + }, } for _, tt := range tests { diff --git a/translations/pt_BR/pt_BR.go b/translations/pt_BR/pt_BR.go index 27cb2a5e..0141d9dd 100644 --- a/translations/pt_BR/pt_BR.go +++ b/translations/pt_BR/pt_BR.go @@ -1287,6 +1287,16 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} deve ser uma imagen válido", override: false, }, + { + tag: "audio", + translation: "{0} deve ser um arquivo de áudio válido", + override: false, + }, + { + tag: "mimetype", + translation: "{0} deve ser um tipo MIME válido", + override: false, + }, { tag: "cve", translation: "{0} deve ser um identificador cve válido", diff --git a/translations/pt_BR/pt_BR_test.go b/translations/pt_BR/pt_BR_test.go index e5880d97..99b7b4da 100644 --- a/translations/pt_BR/pt_BR_test.go +++ b/translations/pt_BR/pt_BR_test.go @@ -145,6 +145,8 @@ func TestTranslations(t *testing.T) { OneOfInt int `validate:"oneof=5 63"` BooleanString string `validate:"boolean"` Image string `validate:"image"` + Audio string `validate:"audio"` + MIMEType string `validate:"mimetype=image/png"` CveString string `validate:"cve"` ValidateFn Foo `validate:"validateFn=IsBar"` } @@ -641,6 +643,14 @@ func TestTranslations(t *testing.T) { ns: "Test.Image", expected: "Image deve ser uma imagen válido", }, + { + ns: "Test.Audio", + expected: "Audio deve ser um arquivo de áudio válido", + }, + { + ns: "Test.MIMEType", + expected: "MIMEType deve ser um tipo MIME válido", + }, { ns: "Test.CveString", expected: "CveString deve ser um identificador cve válido", diff --git a/translations/ru/ru.go b/translations/ru/ru.go index 362e3e4e..54eeef6f 100644 --- a/translations/ru/ru.go +++ b/translations/ru/ru.go @@ -1407,6 +1407,16 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} должно быть допустимым изображением", override: false, }, + { + tag: "audio", + translation: "{0} должно быть допустимым аудиофайлом", + override: false, + }, + { + tag: "mimetype", + translation: "{0} должно быть допустимым MIME-типом", + override: false, + }, } for _, t := range translations { diff --git a/translations/ru/ru_test.go b/translations/ru/ru_test.go index 2885d36c..741075cc 100644 --- a/translations/ru/ru_test.go +++ b/translations/ru/ru_test.go @@ -165,6 +165,8 @@ func TestTranslations(t *testing.T) { UniqueArray [3]string `validate:"unique"` UniqueMap map[string]string `validate:"unique"` Image string `validate:"image"` + Audio string `validate:"audio"` + MIMEType string `validate:"mimetype=image/png"` } var test Test @@ -754,6 +756,14 @@ func TestTranslations(t *testing.T) { ns: "Test.Image", expected: "Image должно быть допустимым изображением", }, + { + ns: "Test.Audio", + expected: "Audio должно быть допустимым аудиофайлом", + }, + { + ns: "Test.MIMEType", + expected: "MIMEType должно быть допустимым MIME-типом", + }, } for _, tt := range tests { diff --git a/translations/th/th.go b/translations/th/th.go index 4bb7c485..8f2ff4fa 100644 --- a/translations/th/th.go +++ b/translations/th/th.go @@ -1324,6 +1324,16 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} ต้องเป็นรูปภาพ", override: false, }, + { + tag: "audio", + translation: "{0} ต้องเป็นไฟล์เสียงที่ถูกต้อง", + override: false, + }, + { + tag: "mimetype", + translation: "{0} ต้องเป็น MIME type ที่ถูกต้อง", + override: false, + }, { tag: "cve", translation: "{0} ต้องเป็นรูปแบบ cve", diff --git a/translations/th/th_test.go b/translations/th/th_test.go index a407513d..17a7c2a2 100644 --- a/translations/th/th_test.go +++ b/translations/th/th_test.go @@ -155,6 +155,8 @@ func TestTranslations(t *testing.T) { PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"` BooleanString string `validate:"boolean"` Image string `validate:"image"` + Audio string `validate:"audio"` + MIMEType string `validate:"mimetype=image/png"` CveString string `validate:"cve"` } @@ -647,6 +649,14 @@ func TestTranslations(t *testing.T) { ns: "Test.Image", expected: "Image ต้องเป็นรูปภาพ", }, + { + ns: "Test.Audio", + expected: "Audio ต้องเป็นไฟล์เสียงที่ถูกต้อง", + }, + { + ns: "Test.MIMEType", + expected: "MIMEType ต้องเป็น MIME type ที่ถูกต้อง", + }, { ns: "Test.CveString", expected: "CveString ต้องเป็นรูปแบบ cve", diff --git a/translations/tr/tr.go b/translations/tr/tr.go index 10ab566f..35a5ac30 100644 --- a/translations/tr/tr.go +++ b/translations/tr/tr.go @@ -1288,6 +1288,16 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} geçerli bir resim olmalıdır", override: false, }, + { + tag: "audio", + translation: "{0} geçerli bir ses dosyası olmalıdır", + override: false, + }, + { + tag: "mimetype", + translation: "{0} gecerli bir MIME turu olmalidir", + override: false, + }, } for _, t := range translations { diff --git a/translations/tr/tr_test.go b/translations/tr/tr_test.go index f443c63f..ec1cc021 100644 --- a/translations/tr/tr_test.go +++ b/translations/tr/tr_test.go @@ -143,6 +143,8 @@ func TestTranslations(t *testing.T) { UniqueArray [3]string `validate:"unique"` UniqueMap map[string]string `validate:"unique"` Image string `validate:"image"` + Audio string `validate:"audio"` + MIMEType string `validate:"mimetype=image/png"` } var test Test @@ -646,6 +648,14 @@ func TestTranslations(t *testing.T) { ns: "Test.Image", expected: "Image geçerli bir resim olmalıdır", }, + { + ns: "Test.Audio", + expected: "Audio geçerli bir ses dosyası olmalıdır", + }, + { + ns: "Test.MIMEType", + expected: "MIMEType gecerli bir MIME turu olmalidir", + }, } for _, tt := range tests { diff --git a/translations/uk/uk.go b/translations/uk/uk.go index e0eb3f05..fbddae09 100644 --- a/translations/uk/uk.go +++ b/translations/uk/uk.go @@ -1166,6 +1166,16 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} має бути допустимим зображенням", override: false, }, + { + tag: "audio", + translation: "{0} має бути допустимим аудіофайлом", + override: false, + }, + { + tag: "mimetype", + translation: "{0} має бути допустимим MIME-типом", + override: false, + }, { tag: "cve", translation: "{0} має бути cve ідентифікатором", diff --git a/translations/uk/uk_test.go b/translations/uk/uk_test.go index cc73561d..28609a4b 100644 --- a/translations/uk/uk_test.go +++ b/translations/uk/uk_test.go @@ -214,6 +214,8 @@ func TestTranslations(t *testing.T) { PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"` BooleanString string `validate:"boolean"` Image string `validate:"image"` + Audio string `validate:"audio"` + MIMEType string `validate:"mimetype=image/png"` CveString string `validate:"cve"` } @@ -956,6 +958,14 @@ func TestTranslations(t *testing.T) { ns: "Test.Image", expected: "Image має бути допустимим зображенням", }, + { + ns: "Test.Audio", + expected: "Audio має бути допустимим аудіофайлом", + }, + { + ns: "Test.MIMEType", + expected: "MIMEType має бути допустимим MIME-типом", + }, { ns: "Test.CveString", expected: "CveString має бути cve ідентифікатором", diff --git a/translations/vi/vi.go b/translations/vi/vi.go index 8d8000d6..fd37ade3 100644 --- a/translations/vi/vi.go +++ b/translations/vi/vi.go @@ -1351,6 +1351,16 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} phải là một hình ảnh hợp lệ", override: false, }, + { + tag: "audio", + translation: "{0} phải là một tệp âm thanh hợp lệ", + override: false, + }, + { + tag: "mimetype", + translation: "{0} phải là một loại MIME hợp lệ", + override: false, + }, } for _, t := range translations { diff --git a/translations/vi/vi_test.go b/translations/vi/vi_test.go index 089192ac..5d71bd44 100644 --- a/translations/vi/vi_test.go +++ b/translations/vi/vi_test.go @@ -150,6 +150,8 @@ func TestTranslations(t *testing.T) { PostCodeCountry string PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"` Image string `validate:"image"` + Audio string `validate:"audio"` + MIMEType string `validate:"mimetype=image/png"` } var test Test @@ -681,6 +683,14 @@ func TestTranslations(t *testing.T) { ns: "Test.Image", expected: "Image phải là một hình ảnh hợp lệ", }, + { + ns: "Test.Audio", + expected: "Audio phải là một tệp âm thanh hợp lệ", + }, + { + ns: "Test.MIMEType", + expected: "MIMEType phải là một loại MIME hợp lệ", + }, } for _, tt := range tests { diff --git a/translations/zh/zh.go b/translations/zh/zh.go index 646fb408..a561baa4 100644 --- a/translations/zh/zh.go +++ b/translations/zh/zh.go @@ -1426,6 +1426,16 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} 必须是有效图像", override: false, }, + { + tag: "audio", + translation: "{0} 必须是有效音频文件", + override: false, + }, + { + tag: "mimetype", + translation: "{0} 必须是有效MIME类型", + override: false, + }, } for _, t := range translations { diff --git a/translations/zh/zh_test.go b/translations/zh/zh_test.go index 60ba0cf9..c2f3816f 100644 --- a/translations/zh/zh_test.go +++ b/translations/zh/zh_test.go @@ -174,6 +174,8 @@ func TestTranslations(t *testing.T) { UppercaseString string `validate:"uppercase"` Datetime string `validate:"datetime=2006-01-02"` Image string `validate:"image"` + Audio string `validate:"audio"` + MIMEType string `validate:"mimetype=image/png"` } var test Test @@ -769,6 +771,14 @@ func TestTranslations(t *testing.T) { ns: "Test.Image", expected: "Image 必须是有效图像", }, + { + ns: "Test.Audio", + expected: "Audio 必须是有效音频文件", + }, + { + ns: "Test.MIMEType", + expected: "MIMEType 必须是有效MIME类型", + }, } for _, tt := range tests { diff --git a/translations/zh_tw/zh_tw.go b/translations/zh_tw/zh_tw.go index 8f1d3a99..7c888329 100644 --- a/translations/zh_tw/zh_tw.go +++ b/translations/zh_tw/zh_tw.go @@ -1357,6 +1357,16 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} 必須是有效圖像", override: false, }, + { + tag: "audio", + translation: "{0} 必須是有效音訊檔案", + override: false, + }, + { + tag: "mimetype", + translation: "{0} 必須是有效MIME類型", + override: false, + }, } for _, t := range translations { diff --git a/translations/zh_tw/zh_tw_test.go b/translations/zh_tw/zh_tw_test.go index 23094579..cb9d7187 100644 --- a/translations/zh_tw/zh_tw_test.go +++ b/translations/zh_tw/zh_tw_test.go @@ -166,6 +166,8 @@ func TestTranslations(t *testing.T) { OneOfInt int `validate:"oneof=5 63"` Datetime string `validate:"datetime=2006-01-02"` Image string `validate:"image"` + Audio string `validate:"audio"` + MIMEType string `validate:"mimetype=image/png"` } var test Test @@ -719,6 +721,14 @@ func TestTranslations(t *testing.T) { ns: "Test.Image", expected: "Image 必須是有效圖像", }, + { + ns: "Test.Audio", + expected: "Audio 必須是有效音訊檔案", + }, + { + ns: "Test.MIMEType", + expected: "MIMEType 必須是有效MIME類型", + }, } for _, tt := range tests { diff --git a/validator_test.go b/validator_test.go index 00eba594..97571b0f 100644 --- a/validator_test.go +++ b/validator_test.go @@ -6306,6 +6306,187 @@ func TestImageValidation(t *testing.T) { }, "Bad field type int") } +func TestMIMETypeValidation(t *testing.T) { + validate := New() + + tmpDir := t.TempDir() + + paths := map[string]string{ + "empty": "", + "directory": "testdata", + "missing": filepath.Join(tmpDir, "none.png"), + "png": filepath.Join(tmpDir, "image.png"), + "jpeg": filepath.Join(tmpDir, "image.jpg"), + "go": filepath.Join("testdata", "a.go"), + } + + tests := []struct { + title string + param string + tag string + expected bool + createFile func() + }{ + { + title: "empty path", + param: paths["empty"], + tag: "mimetype=image/png", + expected: false, + createFile: func() {}, + }, + { + title: "directory, not a file", + param: paths["directory"], + tag: "mimetype=image/png", + expected: false, + createFile: func() {}, + }, + { + title: "missing file", + param: paths["missing"], + tag: "mimetype=image/png", + expected: false, + createFile: func() {}, + }, + { + title: "exact png match", + param: paths["png"], + tag: "mimetype=image/png", + expected: true, + createFile: func() { + img := image.NewRGBA(image.Rectangle{image.Point{0, 0}, image.Point{10, 10}}) + f, err := os.Create(paths["png"]) + Equal(t, err, nil) + defer func() { + _ = f.Close() + }() + + err = png.Encode(f, img) + Equal(t, err, nil) + }, + }, + { + title: "type wildcard png match", + param: paths["png"], + tag: "mimetype=image/*", + expected: true, + createFile: func() { + img := image.NewRGBA(image.Rectangle{image.Point{0, 0}, image.Point{10, 10}}) + f, err := os.Create(paths["png"]) + Equal(t, err, nil) + defer func() { + _ = f.Close() + }() + + err = png.Encode(f, img) + Equal(t, err, nil) + }, + }, + { + title: "type wildcard jpeg match", + param: paths["jpeg"], + tag: "mimetype=image/*", + expected: true, + createFile: func() { + var opt jpeg.Options + img := image.NewGray(image.Rect(0, 0, 10, 10)) + f, err := os.Create(paths["jpeg"]) + Equal(t, err, nil) + defer func() { + _ = f.Close() + }() + + err = jpeg.Encode(f, img, &opt) + Equal(t, err, nil) + }, + }, + { + title: "type mismatch", + param: paths["go"], + tag: "mimetype=image/*", + expected: false, + createFile: func() {}, + }, + { + title: "subtype mismatch", + param: paths["png"], + tag: "mimetype=image/jpeg", + expected: false, + createFile: func() { + img := image.NewRGBA(image.Rectangle{image.Point{0, 0}, image.Point{10, 10}}) + f, err := os.Create(paths["png"]) + Equal(t, err, nil) + defer func() { + _ = f.Close() + }() + + err = png.Encode(f, img) + Equal(t, err, nil) + }, + }, + { + title: "invalid validator param missing subtype", + param: paths["go"], + tag: "mimetype=image", + expected: false, + createFile: func() {}, + }, + } + + for _, test := range tests { + test.createFile() + errs := validate.Var(test.param, test.tag) + + if test.expected { + if !IsEqual(errs, nil) { + t.Fatalf("Test: '%s' failed Error: %s", test.title, errs) + } + } else { + if IsEqual(errs, nil) { + t.Fatalf("Test: '%s' failed Error: %s", test.title, errs) + } + } + } + + PanicMatches(t, func() { + _ = validate.Var(6, "mimetype=image/png") + }, "Bad field type int") +} + +func TestAudioValidation(t *testing.T) { + validate := New() + + tests := []struct { + title string + param string + expected bool + }{ + {"empty path", "", false}, + {"directory, not a file", "testdata", false}, + {"missing file", filepath.Join("testdata", "none.mp3"), false}, + {"valid mp3", filepath.Join("testdata", "music.mp3"), true}, + {"regular file, not audio", filepath.Join("testdata", "a.go"), false}, + } + + for _, test := range tests { + errs := validate.Var(test.param, "audio") + + if test.expected { + if !IsEqual(errs, nil) { + t.Fatalf("Test: '%s' failed Error: %s", test.title, errs) + } + } else { + if IsEqual(errs, nil) { + t.Fatalf("Test: '%s' failed Error: %s", test.title, errs) + } + } + } + + PanicMatches(t, func() { + _ = validate.Var(6, "audio") + }, "Bad field type int") +} + func TestFilePathValidation(t *testing.T) { validate := New()