Skip to content

Commit

Permalink
add ISSN validator + tests + documentation (#1166)
Browse files Browse the repository at this point in the history
## International Standard Serial Number (ISSN) validator

"_An ISSN is an 8-digit code used to identify newspapers, journals,
magazines and periodicals of all kinds and on all media–print and
electronic._" --
[issn.org](https://www.issn.org/understanding-the-issn/what-is-an-issn/)

This PR adds a new `issn` validator, along with updating all translation
files and tests. This validator is very similar to that of the ISBN so I
believe all translations will be okay. The _valid_ ISSNs used in the
tests are examples taken from issn.org.

**Make sure that you've checked the boxes below before you submit PR:**
- [X] Tests exist or have been written that cover this particular
change.

@go-playground/validator-maintainers
  • Loading branch information
mrcook authored Nov 4, 2023
1 parent c856961 commit 1246622
Show file tree
Hide file tree
Showing 38 changed files with 237 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ validate := validator.New(validator.WithRequiredStructEnabled())
| isbn | International Standard Book Number |
| isbn10 | International Standard Book Number 10 |
| isbn13 | International Standard Book Number 13 |
| issn | International Standard Serial Number |
| iso3166_1_alpha2 | Two-letter country code (ISO 3166-1 alpha-2) |
| iso3166_1_alpha3 | Three-letter country code (ISO 3166-1 alpha-3) |
| iso3166_1_alpha_numeric | Numeric country code (ISO 3166-1 numeric) |
Expand Down
27 changes: 27 additions & 0 deletions baked_in.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ var (
"isbn": isISBN,
"isbn10": isISBN10,
"isbn13": isISBN13,
"issn": isISSN,
"eth_addr": isEthereumAddress,
"eth_addr_checksum": isEthereumAddressChecksum,
"btc_addr": isBitcoinAddress,
Expand Down Expand Up @@ -651,6 +652,32 @@ func isISBN10(fl FieldLevel) bool {
return checksum%11 == 0
}

// isISSN is the validation function for validating if the field's value is a valid ISSN.
func isISSN(fl FieldLevel) bool {
s := fl.Field().String()

if !iSSNRegex.MatchString(s) {
return false
}
s = strings.ReplaceAll(s, "-", "")

pos := 8
checksum := 0

for i := 0; i < 7; i++ {
checksum += pos * int(s[i]-'0')
pos--
}

if s[7] == 'X' {
checksum += 10
} else {
checksum += int(s[7] - '0')
}

return checksum%11 == 0
}

// isEthereumAddress is the validation function for validating if the field's value is a valid Ethereum address.
func isEthereumAddress(fl FieldLevel) bool {
address := fl.Field().String()
Expand Down
2 changes: 2 additions & 0 deletions regexes.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const (
base64RawURLRegexString = "^(?:[A-Za-z0-9-_]{4})*(?:[A-Za-z0-9-_]{2,4})$"
iSBN10RegexString = "^(?:[0-9]{9}X|[0-9]{10})$"
iSBN13RegexString = "^(?:(?:97(?:8|9))[0-9]{10})$"
iSSNRegexString = "^(?:[0-9]{4}-[0-9]{3}[0-9X])$"
uUID3RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$"
uUID4RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
uUID5RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
Expand Down Expand Up @@ -93,6 +94,7 @@ var (
base64RawURLRegex = regexp.MustCompile(base64RawURLRegexString)
iSBN10Regex = regexp.MustCompile(iSBN10RegexString)
iSBN13Regex = regexp.MustCompile(iSBN13RegexString)
iSSNRegex = regexp.MustCompile(iSSNRegexString)
uUID3Regex = regexp.MustCompile(uUID3RegexString)
uUID4Regex = regexp.MustCompile(uUID4RegexString)
uUID5Regex = regexp.MustCompile(uUID5RegexString)
Expand Down
5 changes: 5 additions & 0 deletions translations/ar/ar.go
Original file line number Diff line number Diff line change
Expand Up @@ -1116,6 +1116,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "يجب أن يكون {0} رقم ISBN-13 صالح",
override: false,
},
{
tag: "issn",
translation: "يجب أن يكون {0} رقم ISSN صالح",
override: false,
},
{
tag: "uuid",
translation: "يجب أن يكون {0} UUID صالح",
Expand Down
5 changes: 5 additions & 0 deletions translations/ar/ar_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ func TestTranslations(t *testing.T) {
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"`
Expand Down Expand Up @@ -341,6 +342,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.ISBN13",
expected: "يجب أن يكون ISBN13 رقم ISBN-13 صالح",
},
{
ns: "Test.ISSN",
expected: "يجب أن يكون ISSN رقم ISSN صالح",
},
{
ns: "Test.Excludes",
expected: "لا يمكن أن يحتوي Excludes على النص 'text'",
Expand Down
6 changes: 6 additions & 0 deletions translations/en/en.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

"github.com/go-playground/locales"
ut "github.com/go-playground/universal-translator"

"github.com/go-playground/validator/v10"
)

Expand Down Expand Up @@ -1121,6 +1122,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} must be a valid ISBN-13 number",
override: false,
},
{
tag: "issn",
translation: "{0} must be a valid ISSN number",
override: false,
},
{
tag: "uuid",
translation: "{0} must be a valid UUID",
Expand Down
5 changes: 5 additions & 0 deletions translations/en/en_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ func TestTranslations(t *testing.T) {
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"`
Expand Down Expand Up @@ -354,6 +355,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.ISBN13",
expected: "ISBN13 must be a valid ISBN-13 number",
},
{
ns: "Test.ISSN",
expected: "ISSN must be a valid ISSN number",
},
{
ns: "Test.Excludes",
expected: "Excludes cannot contain the text 'text'",
Expand Down
5 changes: 5 additions & 0 deletions translations/es/es.go
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} debe ser un número ISBN-13 válido",
override: false,
},
{
tag: "issn",
translation: "{0} debe ser un número ISSN válido",
override: false,
},
{
tag: "uuid",
translation: "{0} debe ser un UUID válido",
Expand Down
5 changes: 5 additions & 0 deletions translations/es/es_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ func TestTranslations(t *testing.T) {
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"`
Expand Down Expand Up @@ -331,6 +332,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.ISBN13",
expected: "ISBN13 debe ser un número ISBN-13 válido",
},
{
ns: "Test.ISSN",
expected: "ISSN debe ser un número ISSN válido",
},
{
ns: "Test.Excludes",
expected: "Excludes no puede contener el texto 'text'",
Expand Down
5 changes: 5 additions & 0 deletions translations/fa/fa.go
Original file line number Diff line number Diff line change
Expand Up @@ -1116,6 +1116,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} باید یک شابک(ISBN-13) معتبر باشد",
override: false,
},
{
tag: "issn",
translation: "{0} باید یک شابک(ISSN) معتبر باشد",
override: false,
},
{
tag: "uuid",
translation: "{0} باید یک UUID معتبر باشد",
Expand Down
5 changes: 5 additions & 0 deletions translations/fa/fa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ func TestTranslations(t *testing.T) {
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"`
Expand Down Expand Up @@ -340,6 +341,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.ISBN13",
expected: "ISBN13 باید یک شابک(ISBN-13) معتبر باشد",
},
{
ns: "Test.ISSN",
expected: "ISSN باید یک شابک(ISSN) معتبر باشد",
},
{
ns: "Test.Excludes",
expected: "Excludes نمیتواند شامل 'text' باشد",
Expand Down
5 changes: 5 additions & 0 deletions translations/fr/fr.go
Original file line number Diff line number Diff line change
Expand Up @@ -1153,6 +1153,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} doit être un numéro ISBN-13 valid",
override: false,
},
{
tag: "issn",
translation: "{0} doit être un numéro ISSN valid",
override: false,
},
{
tag: "uuid",
translation: "{0} doit être un UUID valid",
Expand Down
5 changes: 5 additions & 0 deletions translations/fr/fr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ func TestTranslations(t *testing.T) {
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"`
Expand Down Expand Up @@ -324,6 +325,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.ISBN13",
expected: "ISBN13 doit être un numéro ISBN-13 valid",
},
{
ns: "Test.ISSN",
expected: "ISSN doit être un numéro ISSN valid",
},
{
ns: "Test.Excludes",
expected: "Excludes ne doit pas contenir le texte 'text'",
Expand Down
5 changes: 5 additions & 0 deletions translations/id/id.go
Original file line number Diff line number Diff line change
Expand Up @@ -1153,6 +1153,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} harus berupa nomor ISBN-13 yang valid",
override: false,
},
{
tag: "issn",
translation: "{0} harus berupa nomor ISSN yang valid",
override: false,
},
{
tag: "uuid",
translation: "{0} harus berupa UUID yang valid",
Expand Down
5 changes: 5 additions & 0 deletions translations/id/id_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ func TestTranslations(t *testing.T) {
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"`
Expand Down Expand Up @@ -324,6 +325,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.ISBN13",
expected: "ISBN13 harus berupa nomor ISBN-13 yang valid",
},
{
ns: "Test.ISSN",
expected: "ISSN harus berupa nomor ISSN yang valid",
},
{
ns: "Test.Excludes",
expected: "Excludes tidak boleh berisi teks 'text'",
Expand Down
5 changes: 5 additions & 0 deletions translations/it/it.go
Original file line number Diff line number Diff line change
Expand Up @@ -977,6 +977,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} deve essere un numero ISBN-13 valido",
override: false,
},
{
tag: "issn",
translation: "{0} deve essere un numero ISSN valido",
override: false,
},
{
tag: "uuid",
translation: "{0} deve essere un UUID valido",
Expand Down
5 changes: 5 additions & 0 deletions translations/it/it_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ func TestTranslations(t *testing.T) {
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"`
Expand Down Expand Up @@ -351,6 +352,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.ISBN13",
expected: "ISBN13 deve essere un numero ISBN-13 valido",
},
{
ns: "Test.ISSN",
expected: "ISSN deve essere un numero ISSN valido",
},
{
ns: "Test.Excludes",
expected: "Excludes non deve contenere il testo 'text'",
Expand Down
5 changes: 5 additions & 0 deletions translations/ja/ja.go
Original file line number Diff line number Diff line change
Expand Up @@ -1186,6 +1186,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0}は正しいISBN-13番号でなければなりません",
override: false,
},
{
tag: "issn",
translation: "{0}は正しいISSN番号でなければなりません",
override: false,
},
{
tag: "uuid",
translation: "{0}は正しいUUIDでなければなりません",
Expand Down
5 changes: 5 additions & 0 deletions translations/ja/ja_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ func TestTranslations(t *testing.T) {
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"`
Expand Down Expand Up @@ -347,6 +348,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.ISBN13",
expected: "ISBN13は正しいISBN-13番号でなければなりません",
},
{
ns: "Test.ISSN",
expected: "ISSNは正しいISSN番号でなければなりません",
},
{
ns: "Test.Excludes",
expected: "Excludesには'text'というテキストを含むことはできません",
Expand Down
5 changes: 5 additions & 0 deletions translations/lv/lv.go
Original file line number Diff line number Diff line change
Expand Up @@ -1121,6 +1121,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} jābūt derīgam ISBN-13 numuram",
override: false,
},
{
tag: "issn",
translation: "{0} jābūt derīgam ISSN numuram",
override: false,
},
{
tag: "uuid",
translation: "{0} jābūt derīgam UUID",
Expand Down
5 changes: 5 additions & 0 deletions translations/lv/lv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ func TestTranslations(t *testing.T) {
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"`
Expand Down Expand Up @@ -346,6 +347,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.ISBN13",
expected: "ISBN13 jābūt derīgam ISBN-13 numuram",
},
{
ns: "Test.ISSN",
expected: "ISSN jābūt derīgam ISSN numuram",
},
{
ns: "Test.Excludes",
expected: "Excludes nedrīkst saturēt tekstu 'text'",
Expand Down
5 changes: 5 additions & 0 deletions translations/nl/nl.go
Original file line number Diff line number Diff line change
Expand Up @@ -1153,6 +1153,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} moet een geldig ISBN-13 nummer zijn",
override: false,
},
{
tag: "issn",
translation: "{0} moet een geldig ISSN nummer zijn",
override: false,
},
{
tag: "uuid",
translation: "{0} moet een geldige UUID zijn",
Expand Down
5 changes: 5 additions & 0 deletions translations/nl/nl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ func TestTranslations(t *testing.T) {
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"`
Expand Down Expand Up @@ -324,6 +325,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.ISBN13",
expected: "ISBN13 moet een geldig ISBN-13 nummer zijn",
},
{
ns: "Test.ISSN",
expected: "ISSN moet een geldig ISSN nummer zijn",
},
{
ns: "Test.Excludes",
expected: "Excludes mag niet de tekst 'text' bevatten",
Expand Down
5 changes: 5 additions & 0 deletions translations/pt/pt.go
Original file line number Diff line number Diff line change
Expand Up @@ -1158,6 +1158,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} deve ser um número ISBN-13 válido",
override: false,
},
{
tag: "issn",
translation: "{0} deve ser um número ISSN válido",
override: false,
},
{
tag: "uuid",
translation: "{0} deve ser um UUID válido",
Expand Down
Loading

0 comments on commit 1246622

Please sign in to comment.