Skip to content

Commit cac80c4

Browse files
committed
Add support for backend validations
1 parent f273cfe commit cac80c4

File tree

8 files changed

+312
-2
lines changed

8 files changed

+312
-2
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@
5151
},
5252
"devDependencies": {
5353
"@fastify/pre-commit": "^2.2.0",
54+
"@uphold/countries": "^6.2.1",
55+
"@uphold/zip-codes": "^1.0.1",
5456
"@uphold/github-changelog-generator": "^4.0.2",
5557
"abavalidator": "^2.0.2",
5658
"bignumber.js": "^9.3.0",

src/asserts/not-po-box-assert.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
'use strict';
2+
3+
/**
4+
* Module dependencies.
5+
*/
6+
7+
const { Validator, Violation } = require('validator.js');
8+
const _ = require('lodash');
9+
const regexps = [
10+
/apartado\s+\d+/i,
11+
/bp\s+\d+/i,
12+
/postboks\s+\d+/i,
13+
/postbus\s+\d+/i,
14+
/postfach\s+\d+/i,
15+
/(\W|^)(p\.?\s*o\.?|(post|postal)\s+(office)?)\s*(box)?\s*(number|num|no)?\s*\d+/i
16+
];
17+
18+
/**
19+
* Export `NotPoBoxAssert`.
20+
*/
21+
22+
module.exports = function () {
23+
this.__class__ = 'NotPoBox';
24+
25+
this.validate = function (value) {
26+
if (!_.isString(value)) {
27+
throw new Violation(this, value, { value: Validator.errorCode.must_be_a_string });
28+
}
29+
30+
for (const regexp of regexps) {
31+
if (regexp.test(value)) {
32+
throw new Violation(this, value);
33+
}
34+
}
35+
36+
return true;
37+
};
38+
39+
return this;
40+
};

src/asserts/person-name-assert.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
'use strict';
2+
3+
/**
4+
* Module dependencies.
5+
*/
6+
7+
const { Validator, Violation } = require('validator.js');
8+
const _ = require('lodash');
9+
10+
/**
11+
* Export `PersonNameAssert`.
12+
*/
13+
14+
module.exports = function () {
15+
// Class name.
16+
this.__class__ = 'PersonName';
17+
18+
const regexp = /[\d!"#$£%{}@&()*+/:;<=>?[\\\]^_~]|[`-]$/g;
19+
20+
// Validation algorithm.
21+
this.validate = function (value) {
22+
if (!_.isString(value)) {
23+
throw new Violation(this, value, { value: Validator.errorCode.must_be_a_string });
24+
}
25+
26+
const matches = value.match(regexp);
27+
28+
if (matches) {
29+
throw new Violation(this, value, { matches: _.uniq(matches) });
30+
}
31+
32+
return true;
33+
};
34+
35+
return this;
36+
};

src/asserts/zip-code-assert.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
'use strict';
2+
3+
/**
4+
* Module dependencies.
5+
*/
6+
7+
const { Assert, Validator, Violation } = require('validator.js');
8+
const { CaZipCode, UsZipCode } = require('validator.js-asserts');
9+
const {
10+
common: { getCountriesAlpha2 }
11+
} = require('@uphold/countries');
12+
const _ = require('lodash');
13+
const zipCodes = require('@uphold/zip-codes');
14+
15+
/**
16+
* Constants.
17+
*/
18+
19+
const countriesAlpha2 = getCountriesAlpha2();
20+
21+
/**
22+
* Instances.
23+
*/
24+
25+
const is = Assert.extend({ CaZipCode, UsZipCode });
26+
27+
/**
28+
* Export `ZipCodeAssert`.
29+
*/
30+
31+
module.exports = function (data = {}) {
32+
this.__class__ = 'ZipCode';
33+
this.country = data && data.country;
34+
this.state = data && data.state;
35+
36+
this.validate = function (value) {
37+
if (value !== null && !_.isString(value)) {
38+
throw new Violation(this, value, { value: 'must_be_null_or_a_string' });
39+
}
40+
41+
if (!_.isString(this.country)) {
42+
throw new Violation(this, value, { country: Validator.errorCode.must_be_a_string });
43+
}
44+
45+
if (!countriesAlpha2.includes(this.country)) {
46+
throw new Violation(this, value, { reason: 'invalid-country' });
47+
}
48+
49+
if (this.country === 'US' && is.usZipCode().check(value) !== true) {
50+
throw new Violation(this, value, { reason: 'invalid-zip-code' });
51+
}
52+
53+
if (this.country === 'CA' && is.caZipCode().check(value) !== true) {
54+
throw new Violation(this, value, { reason: 'invalid-zip-code' });
55+
}
56+
57+
const state = this.state && this.state.split('-')[1];
58+
59+
if (
60+
this.country &&
61+
state &&
62+
_.has(zipCodes, `${this.country}.${state}`) &&
63+
!(zipCodes[this.country][state] || []).find(zip => value.toUpperCase().startsWith(zip.toUpperCase()))
64+
) {
65+
throw new Violation(this, value, { reason: 'invalid-state-zip-code' });
66+
}
67+
68+
return true;
69+
};
70+
71+
return this;
72+
};

src/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ const Ip = require('./asserts/ip-assert.js');
3232
const Iso3166Country = require('./asserts/iso-3166-country-assert.js');
3333
const Json = require('./asserts/json-assert.js');
3434
const NotEmpty = require('./asserts/not-empty-assert.js');
35+
const NotPoBox = require('./asserts/not-po-box-assert.js');
3536
const NullOr = require('./asserts/null-or-assert.js');
3637
const NullOrBoolean = require('./asserts/null-or-boolean-assert.js');
3738
const NullOrDate = require('./asserts/null-or-date-assert.js');
@@ -79,6 +80,7 @@ module.exports = {
7980
Iso3166Country,
8081
Json,
8182
NotEmpty,
83+
NotPoBox,
8284
NullOr,
8385
NullOrBoolean,
8486
NullOrDate,
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
'use strict';
2+
3+
/**
4+
* Module dependencies.
5+
*/
6+
7+
const { Assert: BaseAssert, Violation } = require('validator.js');
8+
const { describe, it } = require('node:test');
9+
const NotPoBoxAssert = require('../../src/asserts/not-po-box-assert.js');
10+
11+
/**
12+
* Extend `Assert` with `NotPoBox`.
13+
*/
14+
15+
const Assert = BaseAssert.extend({
16+
NotPoBox: NotPoBoxAssert
17+
});
18+
19+
/**
20+
* Instances.
21+
*/
22+
23+
const addresses = {
24+
allowed: [
25+
`123 Boxing Street`,
26+
`34 Box Handler Road`,
27+
`424 Po Dance drive`,
28+
`234 P.O.D. Wasn't Terrible Circle`,
29+
`345 Box St, Main St`,
30+
`345 Po St, Main St`,
31+
`POSTAL NOTHING 234 Main St`,
32+
`p.o.BOX ABC, Main St`,
33+
`Cuerpo 2`
34+
],
35+
disallowed: [
36+
`P.O.BOX 234 Main St`,
37+
`P.O. BOX 234 Main St`,
38+
`Main St, P.O.BOX 234`,
39+
`POST OFFICE BOX 234 Main St`,
40+
`PO BOX 234 Main St`,
41+
`po box 234 Main St`,
42+
`po Box 234, 453 Main St`,
43+
`Postal Office BOX 234, Main St`,
44+
`POST BOX 234, Main St`,
45+
`POST BOX NO 234, Main St`,
46+
`POSTAL BOX 234, Main St`,
47+
`PO 234, 345 Main St`,
48+
`Postfach 8 15`,
49+
`Postbus 90222`,
50+
`Postboks 447 Sentrum`,
51+
`BP 13210`,
52+
`Apartado 0832`
53+
]
54+
};
55+
56+
/**
57+
* Test `NotPoBoxAssert`.
58+
*/
59+
60+
describe('NotPoBoxAssert', () => {
61+
it('should throw an error if value is not provided', ({ assert }) => {
62+
try {
63+
Assert.notPoBox().validate();
64+
65+
assert.fail();
66+
} catch (e) {
67+
assert.ok(e instanceof Violation);
68+
assert.equal(e.show().assert, 'NotPoBox');
69+
assert.equal(e.show().violation.value, 'must_be_a_string');
70+
}
71+
});
72+
73+
addresses.disallowed.forEach(address => {
74+
it(`should throw an error for address \`${address}\``, ({ assert }) => {
75+
try {
76+
Assert.notPoBox().validate(address);
77+
assert.fail();
78+
} catch (e) {
79+
assert.ok(e instanceof Violation);
80+
assert.equal(e.show().assert, 'NotPoBox');
81+
assert.equal(e.show().value, address);
82+
}
83+
});
84+
});
85+
86+
addresses.allowed.forEach(address => {
87+
it(`should accept address \`${address}\``, ({ assert }) => {
88+
assert.doesNotThrow(() => {
89+
Assert.notPoBox().validate(address);
90+
});
91+
});
92+
});
93+
});

test/index.test.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ describe('validator.js-asserts', () => {
1515
it('should export all asserts', ({ assert }) => {
1616
const assertNames = Object.keys(asserts);
1717

18-
assert.equal(assertNames.length, 41);
18+
assert.equal(assertNames.length, 42);
1919
assert.deepEqual(assertNames, [
2020
'AbaRoutingNumber',
2121
'BankIdentifierCode',
@@ -45,6 +45,7 @@ describe('validator.js-asserts', () => {
4545
'Iso3166Country',
4646
'Json',
4747
'NotEmpty',
48+
'NotPoBox',
4849
'NullOr',
4950
'NullOrBoolean',
5051
'NullOrDate',

0 commit comments

Comments
 (0)