| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140 |
1x
1x
21x
17x
17x
1x
63x
16x
1x
15x
15x
15x
15x
15x
1x
22x
17x
60x
60x
60x
15x
15x
2x
40x
40x
6x
42x
42x
8x
| /**
* @module server/api/validators/geojson
*/
const _ = require('lodash');
/**
* Returns a ValDSL validator that checks whether a value is a well-formatted bounding box string.
*
* A bounding box string is composed of 4 comma-separated numbers:
*
* * The first 2 numbers are the coordinates (longitude & latitude) of the bounding box's south-west corner.
* * The last 2 numbers are the coordinates (longitude & latitude) of the bounding box's north-east corner.
*
* @returns {function} A validator function.
*/
exports.bboxString = function() {
return async function(ctx) {
// Make sure the value is a string.
const bbox = ctx.get('value');
if (!_.isString(bbox)) {
return ctx.addError({
validator: 'bboxString',
cause: 'wrongType',
message: 'must be a string'
})
}
// Make sure it has 4 values.
const coordinates = bbox.split(',').map(value => parseFloat(value));
if (coordinates.length != 4) {
return ctx.addError({
validator: 'bboxString',
cause: 'wrongLength',
actualLength: coordinates.length,
message: `must have 4 comma-separated coordinates; got ${coordinates.length}`
});
}
// Make sure the 4 values are valid longitudes and latitudes.
await Promise.all([
validateBboxStringCoordinate(ctx, coordinates, 0, coordinateCtx => validateLongitude(coordinateCtx)),
validateBboxStringCoordinate(ctx, coordinates, 1, coordinateCtx => validateLatitude(coordinateCtx)),
validateBboxStringCoordinate(ctx, coordinates, 2, coordinateCtx => validateLongitude(coordinateCtx)),
validateBboxStringCoordinate(ctx, coordinates, 3, coordinateCtx => validateLatitude(coordinateCtx))
]);
};
};
/**
* Returns a ValDSL validator that checks whether a value is a GeoJSON object of type Point.
*
* const { point: validateGeoJsonPoint } = require('../validators/geojson');
*
* this.validate(
* this.json('geometry'),
* validateGeoJsonPoint()
* )
*
* @returns {function} A validator function.
*/
exports.point = function() {
return function(ctx) {
return ctx.series(
ctx.type('object'),
ctx.properties('type', 'coordinates'),
ctx.parallel(
ctx.validate(
ctx.json('/type'),
ctx.required(),
ctx.type('string'),
ctx.equals('Point')
),
ctx.validate(
ctx.json('/coordinates'),
ctx.required(),
ctx.type('array'),
validateCoordinates,
ctx.parallel(
ctx.validate(
ctx.json('/0'),
ctx.type('number'),
validateLongitude
),
ctx.validate(
ctx.json('/1'),
ctx.type('number'),
validateLatitude
)
)
)
)
);
};
}
function validateBboxStringCoordinate(ctx, coordinates, i, callback) {
return ctx.validate(coordinateCtx => {
// Make the error indicate the index of the invalid coordinate
// within the bbox string, e.g. "bbox[1]".
coordinateCtx.set({
location: `${coordinateCtx.get('location')}[${i}]`,
value: coordinates[i]
});
return callback(coordinateCtx);
});
}
function validateCoordinates(ctx) {
const coordinates = ctx.get('value');
if (!_.isArray(coordinates) || coordinates.length != 2) {
ctx.addError({
validator: 'coordinates',
message: 'must be an array of 2 numbers (longitude & latitude)'
});
}
}
function validateLongitude(ctx) {
const longitude = ctx.get('value');
if (!_.isFinite(longitude) || longitude < -180 || longitude > 180) {
ctx.addError({
validator: 'longitude',
message: 'must be a number between -180 and 180'
});
}
}
function validateLatitude(ctx) {
const latitude = ctx.get('value');
if (!_.isFinite(latitude) || latitude < -90 || latitude > 90) {
ctx.addError({
validator: 'latitude',
message: 'must be a number between -90 and 90'
});
}
}
|