kuzzle 2.19.2 → 2.19.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api/controllers/adminController.js +94 -80
- package/lib/api/controllers/authController.js +239 -212
- package/lib/api/controllers/baseController.js +89 -51
- package/lib/api/controllers/bulkController.js +62 -49
- package/lib/api/controllers/clusterController.js +6 -8
- package/lib/api/controllers/collectionController.js +140 -129
- package/lib/api/controllers/debugController.d.ts +2 -2
- package/lib/api/controllers/debugController.js +33 -31
- package/lib/api/controllers/documentController.js +365 -274
- package/lib/api/controllers/index.js +13 -13
- package/lib/api/controllers/indexController.js +46 -50
- package/lib/api/controllers/memoryStorageController.js +410 -360
- package/lib/api/controllers/realtimeController.js +37 -36
- package/lib/api/controllers/securityController.js +553 -412
- package/lib/api/controllers/serverController.js +111 -104
- package/lib/api/documentExtractor.js +75 -68
- package/lib/api/funnel.js +411 -312
- package/lib/api/httpRoutes.js +1493 -324
- package/lib/api/openapi/OpenApiManager.d.ts +1 -1
- package/lib/api/openapi/OpenApiManager.js +22 -22
- package/lib/api/openapi/components/document/count.yaml +1 -1
- package/lib/api/openapi/components/document/create.yaml +2 -2
- package/lib/api/openapi/components/document/delete.yaml +1 -1
- package/lib/api/openapi/components/document/deleteByQuery.yaml +1 -1
- package/lib/api/openapi/components/document/exists.yaml +1 -1
- package/lib/api/openapi/components/document/get.yaml +2 -2
- package/lib/api/openapi/components/document/index.js +12 -12
- package/lib/api/openapi/components/document/replace.yaml +1 -1
- package/lib/api/openapi/components/document/scroll.yaml +1 -1
- package/lib/api/openapi/components/document/validate.yaml +1 -1
- package/lib/api/openapi/components/index.d.ts +2 -2
- package/lib/api/openapi/components/index.js +1 -1
- package/lib/api/openapi/components/security/index.js +1 -1
- package/lib/api/openapi/components/security/upsertUser.yaml +2 -3
- package/lib/api/openapi/index.d.ts +1 -1
- package/lib/api/openapi/openApiGenerator.d.ts +1 -1
- package/lib/api/openapi/openApiGenerator.js +7 -7
- package/lib/api/rateLimiter.js +12 -13
- package/lib/api/request/index.d.ts +4 -4
- package/lib/api/request/kuzzleRequest.d.ts +9 -9
- package/lib/api/request/kuzzleRequest.js +89 -87
- package/lib/api/request/requestContext.d.ts +2 -2
- package/lib/api/request/requestContext.js +17 -17
- package/lib/api/request/requestInput.d.ts +1 -1
- package/lib/api/request/requestInput.js +19 -19
- package/lib/api/request/requestResponse.d.ts +4 -4
- package/lib/api/request/requestResponse.js +31 -33
- package/lib/cluster/command.js +48 -44
- package/lib/cluster/idCardHandler.d.ts +1 -1
- package/lib/cluster/idCardHandler.js +15 -15
- package/lib/cluster/index.js +2 -2
- package/lib/cluster/node.js +301 -269
- package/lib/cluster/publisher.js +45 -46
- package/lib/cluster/state.d.ts +5 -5
- package/lib/cluster/state.js +8 -8
- package/lib/cluster/subscriber.js +163 -113
- package/lib/cluster/workers/IDCardRenewer.js +33 -32
- package/lib/config/default.config.d.ts +1 -1
- package/lib/config/default.config.js +212 -171
- package/lib/config/documentEventAliases.js +6 -6
- package/lib/config/index.js +161 -98
- package/lib/config/sdkCompatibility.json +8 -8
- package/lib/core/auth/formatProcessing.js +7 -7
- package/lib/core/auth/passportResponse.js +7 -7
- package/lib/core/auth/passportWrapper.js +34 -30
- package/lib/core/auth/tokenManager.d.ts +2 -2
- package/lib/core/auth/tokenManager.js +11 -10
- package/lib/core/backend/applicationManager.d.ts +1 -1
- package/lib/core/backend/applicationManager.js +2 -2
- package/lib/core/backend/backend.d.ts +3 -3
- package/lib/core/backend/backend.js +34 -31
- package/lib/core/backend/backendCluster.d.ts +2 -2
- package/lib/core/backend/backendCluster.js +5 -5
- package/lib/core/backend/backendConfig.d.ts +2 -2
- package/lib/core/backend/backendConfig.js +3 -3
- package/lib/core/backend/backendController.d.ts +2 -2
- package/lib/core/backend/backendController.js +9 -10
- package/lib/core/backend/backendErrors.d.ts +3 -3
- package/lib/core/backend/backendErrors.js +2 -1
- package/lib/core/backend/backendHook.d.ts +2 -2
- package/lib/core/backend/backendHook.js +5 -5
- package/lib/core/backend/backendImport.d.ts +3 -3
- package/lib/core/backend/backendImport.js +23 -23
- package/lib/core/backend/backendOpenApi.d.ts +2 -2
- package/lib/core/backend/backendOpenApi.js +16 -16
- package/lib/core/backend/backendPipe.d.ts +2 -2
- package/lib/core/backend/backendPipe.js +6 -6
- package/lib/core/backend/backendPlugin.d.ts +4 -4
- package/lib/core/backend/backendPlugin.js +14 -14
- package/lib/core/backend/backendStorage.d.ts +2 -2
- package/lib/core/backend/backendStorage.js +1 -2
- package/lib/core/backend/backendVault.d.ts +2 -2
- package/lib/core/backend/backendVault.js +3 -3
- package/lib/core/backend/index.d.ts +14 -14
- package/lib/core/backend/internalLogger.d.ts +1 -1
- package/lib/core/backend/internalLogger.js +5 -5
- package/lib/core/cache/cacheDbEnum.js +4 -4
- package/lib/core/cache/cacheEngine.js +79 -85
- package/lib/core/network/accessLogger.js +126 -120
- package/lib/core/network/clientConnection.js +5 -5
- package/lib/core/network/context.js +8 -8
- package/lib/core/network/entryPoint.js +100 -85
- package/lib/core/network/httpRouter/index.js +63 -60
- package/lib/core/network/httpRouter/routeHandler.js +18 -19
- package/lib/core/network/httpRouter/routePart.js +23 -19
- package/lib/core/network/protocolManifest.js +3 -3
- package/lib/core/network/protocols/httpMessage.js +8 -10
- package/lib/core/network/protocols/httpwsProtocol.js +305 -250
- package/lib/core/network/protocols/internalProtocol.js +27 -24
- package/lib/core/network/protocols/mqttProtocol.js +106 -96
- package/lib/core/network/protocols/protocol.js +20 -17
- package/lib/core/network/router.js +56 -46
- package/lib/core/plugin/plugin.js +151 -120
- package/lib/core/plugin/pluginContext.d.ts +7 -7
- package/lib/core/plugin/pluginContext.js +48 -44
- package/lib/core/plugin/pluginManifest.js +13 -12
- package/lib/core/plugin/pluginRepository.js +26 -27
- package/lib/core/plugin/pluginsManager.js +425 -304
- package/lib/core/plugin/privilegedContext.js +3 -3
- package/lib/core/realtime/actionEnum.js +1 -1
- package/lib/core/realtime/channel.d.ts +1 -1
- package/lib/core/realtime/channel.js +22 -22
- package/lib/core/realtime/connectionRooms.d.ts +1 -1
- package/lib/core/realtime/hotelClerk.d.ts +2 -2
- package/lib/core/realtime/hotelClerk.js +53 -50
- package/lib/core/realtime/index.js +5 -5
- package/lib/core/realtime/notification/document.js +25 -25
- package/lib/core/realtime/notification/index.js +4 -4
- package/lib/core/realtime/notification/server.js +3 -3
- package/lib/core/realtime/notification/user.js +4 -4
- package/lib/core/realtime/notifier.js +113 -75
- package/lib/core/realtime/room.d.ts +1 -1
- package/lib/core/realtime/subscription.d.ts +1 -1
- package/lib/core/realtime/subscription.js +1 -1
- package/lib/core/security/index.js +8 -8
- package/lib/core/security/profileRepository.d.ts +6 -6
- package/lib/core/security/profileRepository.js +48 -45
- package/lib/core/security/roleRepository.js +127 -115
- package/lib/core/security/securityLoader.js +70 -63
- package/lib/core/security/tokenRepository.js +132 -118
- package/lib/core/security/userRepository.js +104 -88
- package/lib/core/shared/KoncordeWrapper.d.ts +1 -1
- package/lib/core/shared/KoncordeWrapper.js +3 -1
- package/lib/core/shared/abstractManifest.js +22 -23
- package/lib/core/shared/repository.js +69 -67
- package/lib/core/shared/sdk/embeddedSdk.d.ts +2 -2
- package/lib/core/shared/sdk/embeddedSdk.js +36 -32
- package/lib/core/shared/sdk/funnelProtocol.d.ts +1 -1
- package/lib/core/shared/sdk/funnelProtocol.js +11 -11
- package/lib/core/shared/sdk/impersonatedSdk.js +19 -18
- package/lib/core/shared/store.js +127 -32
- package/lib/core/statistics/index.js +2 -2
- package/lib/core/statistics/statistics.js +99 -85
- package/lib/core/storage/clientAdapter.js +219 -136
- package/lib/core/storage/indexCache.js +3 -3
- package/lib/core/storage/storageEngine.js +10 -13
- package/lib/core/storage/storeScopeEnum.js +3 -3
- package/lib/core/validation/baseType.js +12 -10
- package/lib/core/validation/index.js +2 -2
- package/lib/core/validation/types/anything.js +4 -4
- package/lib/core/validation/types/boolean.js +7 -7
- package/lib/core/validation/types/date.js +165 -131
- package/lib/core/validation/types/email.js +18 -21
- package/lib/core/validation/types/enum.js +34 -21
- package/lib/core/validation/types/geoPoint.js +7 -7
- package/lib/core/validation/types/geoShape.js +148 -125
- package/lib/core/validation/types/integer.js +9 -9
- package/lib/core/validation/types/ipAddress.js +17 -19
- package/lib/core/validation/types/numeric.js +36 -29
- package/lib/core/validation/types/object.js +19 -19
- package/lib/core/validation/types/string.js +36 -29
- package/lib/core/validation/types/url.js +17 -19
- package/lib/core/validation/validation.js +422 -378
- package/lib/kerror/codes/1-services.json +7 -1
- package/lib/kerror/codes/4-plugin.json +2 -2
- package/lib/kerror/codes/index.js +85 -63
- package/lib/kerror/errors/badRequestError.d.ts +1 -1
- package/lib/kerror/errors/externalServiceError.d.ts +1 -1
- package/lib/kerror/errors/forbiddenError.d.ts +1 -1
- package/lib/kerror/errors/gatewayTimeoutError.d.ts +1 -1
- package/lib/kerror/errors/index.d.ts +15 -15
- package/lib/kerror/errors/internalError.d.ts +1 -1
- package/lib/kerror/errors/kuzzleError.d.ts +1 -1
- package/lib/kerror/errors/multipleErrorsError.d.ts +1 -1
- package/lib/kerror/errors/multipleErrorsError.js +1 -1
- package/lib/kerror/errors/notFoundError.d.ts +1 -1
- package/lib/kerror/errors/partialError.d.ts +1 -1
- package/lib/kerror/errors/partialError.js +1 -1
- package/lib/kerror/errors/pluginImplementationError.d.ts +1 -1
- package/lib/kerror/errors/pluginImplementationError.js +2 -1
- package/lib/kerror/errors/preconditionError.d.ts +1 -1
- package/lib/kerror/errors/serviceUnavailableError.d.ts +1 -1
- package/lib/kerror/errors/sizeLimitError.d.ts +1 -1
- package/lib/kerror/errors/tooManyRequestsError.d.ts +1 -1
- package/lib/kerror/errors/unauthorizedError.d.ts +1 -1
- package/lib/kerror/index.d.ts +3 -3
- package/lib/kerror/index.js +17 -16
- package/lib/kuzzle/dumpGenerator.js +130 -114
- package/lib/kuzzle/event/kuzzleEventEmitter.js +96 -70
- package/lib/kuzzle/event/pipeRunner.js +25 -24
- package/lib/kuzzle/event/waterfall.js +13 -15
- package/lib/kuzzle/index.js +2 -2
- package/lib/kuzzle/internalIndexHandler.js +80 -59
- package/lib/kuzzle/kuzzle.js +99 -99
- package/lib/kuzzle/kuzzleStateEnum.js +1 -1
- package/lib/kuzzle/log.js +23 -18
- package/lib/kuzzle/vault.js +34 -19
- package/lib/model/security/profile.d.ts +3 -3
- package/lib/model/security/profile.js +38 -37
- package/lib/model/security/rights.js +5 -5
- package/lib/model/security/role.d.ts +3 -3
- package/lib/model/security/role.js +25 -26
- package/lib/model/security/token.d.ts +1 -1
- package/lib/model/security/token.js +4 -4
- package/lib/model/security/user.d.ts +2 -2
- package/lib/model/security/user.js +9 -9
- package/lib/model/storage/apiKey.js +43 -33
- package/lib/model/storage/baseModel.js +49 -45
- package/lib/service/cache/redis.js +60 -55
- package/lib/service/service.js +17 -17
- package/lib/service/storage/elasticsearch.js +839 -755
- package/lib/service/storage/esWrapper.js +103 -86
- package/lib/service/storage/queryTranslator.js +52 -59
- package/lib/types/Controller.d.ts +3 -3
- package/lib/types/ControllerDefinition.d.ts +3 -3
- package/lib/types/DebugModule.d.ts +2 -2
- package/lib/types/DebugModule.js +1 -1
- package/lib/types/Global.d.ts +1 -1
- package/lib/types/HttpStream.d.ts +2 -1
- package/lib/types/HttpStream.js +7 -5
- package/lib/types/Kuzzle.d.ts +1 -1
- package/lib/types/KuzzleDocument.d.ts +1 -1
- package/lib/types/OpenApiDefinition.d.ts +1 -1
- package/lib/types/PasswordPolicy.d.ts +1 -1
- package/lib/types/Plugin.d.ts +6 -6
- package/lib/types/Plugin.js +2 -2
- package/lib/types/Policy.d.ts +1 -1
- package/lib/types/RequestPayload.d.ts +1 -1
- package/lib/types/ResponsePayload.d.ts +1 -1
- package/lib/types/Token.d.ts +1 -1
- package/lib/types/User.d.ts +1 -1
- package/lib/types/config/DumpConfiguration.d.ts +8 -8
- package/lib/types/config/HttpConfiguration.d.ts +1 -1
- package/lib/types/config/KuzzleConfiguration.d.ts +1 -1
- package/lib/types/config/LimitsConfiguration.d.ts +8 -8
- package/lib/types/config/PluginsConfiguration.d.ts +4 -4
- package/lib/types/config/SecurityConfiguration.d.ts +62 -62
- package/lib/types/config/ServerConfiguration.d.ts +55 -55
- package/lib/types/config/ServicesConfiguration.d.ts +2 -2
- package/lib/types/config/internalCache/InternalCacheRedisConfiguration.d.ts +10 -10
- package/lib/types/config/publicCache/PublicCacheRedisConfiguration.d.ts +3 -3
- package/lib/types/config/storageEngine/StorageEngineElasticsearchConfiguration.d.ts +194 -110
- package/lib/types/errors/ErrorDefinition.d.ts +1 -1
- package/lib/types/errors/ErrorDomains.d.ts +1 -1
- package/lib/types/index.d.ts +38 -38
- package/lib/types/realtime/RealtimeScope.d.ts +1 -1
- package/lib/types/realtime/RealtimeUsers.d.ts +1 -1
- package/lib/util/assertType.js +13 -11
- package/lib/util/async.d.ts +1 -0
- package/lib/util/async.js +61 -0
- package/lib/util/asyncStore.js +19 -21
- package/lib/util/bufferedPassThrough.d.ts +2 -2
- package/lib/util/bufferedPassThrough.js +4 -4
- package/lib/util/bytes.js +9 -13
- package/lib/util/crypto.js +1 -1
- package/lib/util/debug.js +5 -5
- package/lib/util/deprecate.js +24 -21
- package/lib/util/didYouMean.js +7 -7
- package/lib/util/dump-collection.d.ts +2 -2
- package/lib/util/dump-collection.js +26 -26
- package/lib/util/esRequest.d.ts +1 -0
- package/lib/util/esRequest.js +62 -0
- package/lib/util/extractFields.js +24 -25
- package/lib/util/inflector.js +5 -5
- package/lib/util/koncordeCompat.d.ts +2 -2
- package/lib/util/koncordeCompat.js +5 -5
- package/lib/util/memoize.js +3 -5
- package/lib/util/mutex.d.ts +19 -1
- package/lib/util/mutex.js +39 -12
- package/lib/util/name-generator.js +1331 -1331
- package/lib/util/promback.js +8 -10
- package/lib/util/readYamlFile.d.ts +1 -1
- package/lib/util/readYamlFile.js +1 -1
- package/lib/util/requestAssertions.js +34 -34
- package/lib/util/safeObject.js +5 -5
- package/lib/util/stackTrace.js +20 -22
- package/lib/util/wildcard.js +15 -15
- package/package.json +6 -6
- package/npm-shrinkwrap.json +0 -19422
|
@@ -19,24 +19,24 @@
|
|
|
19
19
|
* limitations under the License.
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
"use strict";
|
|
23
23
|
|
|
24
|
-
const Bluebird = require(
|
|
25
|
-
const _ = require(
|
|
26
|
-
const { Koncorde } = require(
|
|
24
|
+
const Bluebird = require("bluebird");
|
|
25
|
+
const _ = require("lodash");
|
|
26
|
+
const { Koncorde } = require("koncorde");
|
|
27
27
|
|
|
28
|
-
const debug = require(
|
|
29
|
-
const kerror = require(
|
|
30
|
-
const { KuzzleError } = require(
|
|
31
|
-
const { has, isPlainObject, get } = require(
|
|
32
|
-
const { koncordeTest, toKoncordeIndex } = require(
|
|
28
|
+
const debug = require("../../util/debug")("core:validation");
|
|
29
|
+
const kerror = require("../../kerror");
|
|
30
|
+
const { KuzzleError } = require("../../kerror/errors");
|
|
31
|
+
const { has, isPlainObject, get } = require("../../util/safeObject");
|
|
32
|
+
const { koncordeTest, toKoncordeIndex } = require("../../util/koncordeCompat");
|
|
33
33
|
|
|
34
|
-
const assertionError = kerror.wrap(
|
|
34
|
+
const assertionError = kerror.wrap("validation", "assert");
|
|
35
35
|
/**
|
|
36
36
|
* @class Validation
|
|
37
37
|
*/
|
|
38
38
|
class Validation {
|
|
39
|
-
constructor
|
|
39
|
+
constructor() {
|
|
40
40
|
/** @type {...ValidationType} */
|
|
41
41
|
this.types = {};
|
|
42
42
|
|
|
@@ -55,22 +55,22 @@ class Validation {
|
|
|
55
55
|
/**
|
|
56
56
|
* Walks through all types in "defaultTypesFiles" initializes all types
|
|
57
57
|
*/
|
|
58
|
-
init
|
|
58
|
+
init() {
|
|
59
59
|
[
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
].forEach(typeFile => {
|
|
60
|
+
"anything",
|
|
61
|
+
"boolean",
|
|
62
|
+
"date",
|
|
63
|
+
"email",
|
|
64
|
+
"enum",
|
|
65
|
+
"geoPoint",
|
|
66
|
+
"geoShape",
|
|
67
|
+
"integer",
|
|
68
|
+
"ipAddress",
|
|
69
|
+
"numeric",
|
|
70
|
+
"object",
|
|
71
|
+
"string",
|
|
72
|
+
"url",
|
|
73
|
+
].forEach((typeFile) => {
|
|
74
74
|
const TypeConstructor = require(`./types/${typeFile}`);
|
|
75
75
|
this.addType(new TypeConstructor());
|
|
76
76
|
});
|
|
@@ -83,28 +83,29 @@ class Validation {
|
|
|
83
83
|
* @param {boolean} [verbose]
|
|
84
84
|
* @returns {Promise.<{documentBody: *, errorMessages:string[], valid: boolean}|KuzzleRequest>}
|
|
85
85
|
*/
|
|
86
|
-
async validate
|
|
87
|
-
const
|
|
88
|
-
{ _id, index, collection } = request.input.resource,
|
|
86
|
+
async validate(request, verbose = false) {
|
|
87
|
+
const { _id, index, collection } = request.input.resource,
|
|
89
88
|
collectionSpec =
|
|
90
|
-
isPlainObject(this.specification) &&
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
(isPlainObject(this.specification) &&
|
|
90
|
+
has(this.specification, index) &&
|
|
91
|
+
get(this.specification[index], collection)) ||
|
|
92
|
+
{};
|
|
93
93
|
|
|
94
|
-
let
|
|
95
|
-
isUpdate = false,
|
|
94
|
+
let isUpdate = false,
|
|
96
95
|
body = request.input.body;
|
|
97
96
|
|
|
98
|
-
if (
|
|
99
|
-
|
|
97
|
+
if (
|
|
98
|
+
request.input.controller === "document" &&
|
|
99
|
+
request.input.action === "update"
|
|
100
100
|
) {
|
|
101
101
|
isUpdate = true;
|
|
102
102
|
|
|
103
103
|
const document = await global.kuzzle.ask(
|
|
104
|
-
|
|
104
|
+
"core:storage:public:document:get",
|
|
105
105
|
index,
|
|
106
106
|
collection,
|
|
107
|
-
_id
|
|
107
|
+
_id
|
|
108
|
+
);
|
|
108
109
|
|
|
109
110
|
// Avoid side effects on the request during the update validation
|
|
110
111
|
body = _.cloneDeep(request.input.body);
|
|
@@ -122,45 +123,54 @@ class Validation {
|
|
|
122
123
|
collectionSpec.fields.children,
|
|
123
124
|
collectionSpec.strict,
|
|
124
125
|
errorMessages,
|
|
125
|
-
verbose
|
|
126
|
-
|
|
127
|
-
catch (error) {
|
|
126
|
+
verbose
|
|
127
|
+
);
|
|
128
|
+
} catch (error) {
|
|
128
129
|
// The strictness message can be received here only if it happens at
|
|
129
130
|
// the validation of the document's root
|
|
130
|
-
if (error.message !==
|
|
131
|
+
if (error.message !== "strictness") {
|
|
131
132
|
throw error;
|
|
132
133
|
}
|
|
133
134
|
|
|
134
135
|
isValid = false;
|
|
135
136
|
manageErrorMessage(
|
|
136
|
-
|
|
137
|
+
"document",
|
|
137
138
|
errorMessages,
|
|
138
139
|
`The document validation is strict. Cannot add unspecified sub-field "${error.details.field}"`,
|
|
139
|
-
verbose
|
|
140
|
+
verbose
|
|
141
|
+
);
|
|
140
142
|
}
|
|
141
143
|
}
|
|
142
144
|
|
|
143
145
|
if (collectionSpec.validators) {
|
|
144
|
-
const filters = koncordeTest(
|
|
146
|
+
const filters = koncordeTest(
|
|
147
|
+
this.koncorde,
|
|
148
|
+
index,
|
|
149
|
+
collection,
|
|
150
|
+
body,
|
|
151
|
+
_id
|
|
152
|
+
);
|
|
145
153
|
|
|
146
|
-
if (
|
|
154
|
+
if (filters.length === 0 || filters[0] !== collectionSpec.validators) {
|
|
147
155
|
isValid = false;
|
|
148
156
|
manageErrorMessage(
|
|
149
|
-
|
|
157
|
+
"document",
|
|
150
158
|
errorMessages,
|
|
151
|
-
|
|
152
|
-
verbose
|
|
159
|
+
"The document does not match validation filters.",
|
|
160
|
+
verbose
|
|
161
|
+
);
|
|
153
162
|
}
|
|
154
163
|
}
|
|
155
164
|
}
|
|
156
165
|
|
|
157
|
-
if (!
|
|
166
|
+
if (!verbose) {
|
|
158
167
|
// We only modify the request if the validation succeeds
|
|
159
168
|
if (collectionSpec.fields && collectionSpec.fields.children) {
|
|
160
169
|
request.input.body = this.recurseApplyDefault(
|
|
161
170
|
isUpdate,
|
|
162
171
|
request.input.body,
|
|
163
|
-
collectionSpec.fields.children
|
|
172
|
+
collectionSpec.fields.children
|
|
173
|
+
);
|
|
164
174
|
}
|
|
165
175
|
|
|
166
176
|
return request;
|
|
@@ -174,32 +184,34 @@ class Validation {
|
|
|
174
184
|
* @param {*} documentSubset
|
|
175
185
|
* @param {...StructuredFieldSpecification} collectionSpecSubset
|
|
176
186
|
*/
|
|
177
|
-
recurseApplyDefault
|
|
178
|
-
Object.keys(collectionSpecSubset).forEach(fieldName => {
|
|
179
|
-
const
|
|
180
|
-
specSubset = collectionSpecSubset[fieldName],
|
|
187
|
+
recurseApplyDefault(isUpdate, documentSubset, collectionSpecSubset) {
|
|
188
|
+
Object.keys(collectionSpecSubset).forEach((fieldName) => {
|
|
189
|
+
const specSubset = collectionSpecSubset[fieldName],
|
|
181
190
|
field = documentSubset[fieldName];
|
|
182
191
|
|
|
183
|
-
if (
|
|
184
|
-
|
|
192
|
+
if (
|
|
193
|
+
has(documentSubset, fieldName) &&
|
|
194
|
+
this.types[specSubset.type].allowChildren &&
|
|
195
|
+
specSubset.children
|
|
185
196
|
) {
|
|
186
197
|
if (Array.isArray(field)) {
|
|
187
198
|
for (let i = 0; i < field.length; i++) {
|
|
188
199
|
field[i] = this.recurseApplyDefault(
|
|
189
200
|
isUpdate,
|
|
190
201
|
field[i],
|
|
191
|
-
specSubset.children
|
|
202
|
+
specSubset.children
|
|
203
|
+
);
|
|
192
204
|
}
|
|
193
|
-
}
|
|
194
|
-
else {
|
|
205
|
+
} else {
|
|
195
206
|
documentSubset[fieldName] = this.recurseApplyDefault(
|
|
196
207
|
isUpdate,
|
|
197
208
|
field,
|
|
198
|
-
specSubset.children
|
|
209
|
+
specSubset.children
|
|
210
|
+
);
|
|
199
211
|
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
|
|
212
|
+
} else if (
|
|
213
|
+
specSubset.defaultValue &&
|
|
214
|
+
(field === null || (!isUpdate && !has(documentSubset, fieldName)))
|
|
203
215
|
) {
|
|
204
216
|
documentSubset[fieldName] = specSubset.defaultValue;
|
|
205
217
|
}
|
|
@@ -215,7 +227,7 @@ class Validation {
|
|
|
215
227
|
* @param {string[]} errorMessages
|
|
216
228
|
* @param {boolean} verbose
|
|
217
229
|
*/
|
|
218
|
-
recurseFieldValidation
|
|
230
|
+
recurseFieldValidation(
|
|
219
231
|
documentSubset,
|
|
220
232
|
collectionSpecSubset,
|
|
221
233
|
strictness,
|
|
@@ -224,36 +236,41 @@ class Validation {
|
|
|
224
236
|
) {
|
|
225
237
|
if (strictness) {
|
|
226
238
|
for (const field of Object.keys(documentSubset)) {
|
|
227
|
-
if (!
|
|
228
|
-
const error = new Error(
|
|
239
|
+
if (!collectionSpecSubset[field]) {
|
|
240
|
+
const error = new Error("strictness");
|
|
229
241
|
error.details = { field };
|
|
230
242
|
throw error;
|
|
231
243
|
}
|
|
232
244
|
}
|
|
233
245
|
}
|
|
234
246
|
|
|
235
|
-
if (!
|
|
247
|
+
if (!verbose) {
|
|
236
248
|
// We stop as soon as one field is not valid
|
|
237
|
-
return Object.keys(collectionSpecSubset).every(fieldName =>
|
|
249
|
+
return Object.keys(collectionSpecSubset).every((fieldName) =>
|
|
238
250
|
this.isValidField(
|
|
239
251
|
fieldName,
|
|
240
252
|
documentSubset,
|
|
241
253
|
collectionSpecSubset,
|
|
242
254
|
strictness,
|
|
243
255
|
errorMessages,
|
|
244
|
-
verbose
|
|
256
|
+
verbose
|
|
257
|
+
)
|
|
258
|
+
);
|
|
245
259
|
}
|
|
246
260
|
|
|
247
261
|
// We try to validate every field in order to get all error messages if any
|
|
248
262
|
return Object.keys(collectionSpecSubset).reduce(
|
|
249
|
-
(reductionResult, fieldName) =>
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
263
|
+
(reductionResult, fieldName) =>
|
|
264
|
+
this.isValidField(
|
|
265
|
+
fieldName,
|
|
266
|
+
documentSubset,
|
|
267
|
+
collectionSpecSubset,
|
|
268
|
+
strictness,
|
|
269
|
+
errorMessages,
|
|
270
|
+
verbose
|
|
271
|
+
) && reductionResult,
|
|
272
|
+
true
|
|
273
|
+
);
|
|
257
274
|
}
|
|
258
275
|
|
|
259
276
|
/**
|
|
@@ -265,7 +282,7 @@ class Validation {
|
|
|
265
282
|
* @param {boolean} verbose
|
|
266
283
|
* @returns {boolean}
|
|
267
284
|
*/
|
|
268
|
-
isValidField
|
|
285
|
+
isValidField(
|
|
269
286
|
fieldName,
|
|
270
287
|
documentSubset,
|
|
271
288
|
collectionSpecSubset,
|
|
@@ -277,64 +294,70 @@ class Validation {
|
|
|
277
294
|
const field = collectionSpecSubset[fieldName];
|
|
278
295
|
let result = true;
|
|
279
296
|
|
|
280
|
-
if (
|
|
281
|
-
|
|
282
|
-
|
|
297
|
+
if (
|
|
298
|
+
field.mandatory &&
|
|
299
|
+
!has(field, "defaultValue") &&
|
|
300
|
+
_.isNil(documentSubset[fieldName])
|
|
283
301
|
) {
|
|
284
302
|
manageErrorMessage(
|
|
285
303
|
field.path,
|
|
286
304
|
errorMessages,
|
|
287
|
-
|
|
288
|
-
verbose
|
|
305
|
+
"The field is mandatory.",
|
|
306
|
+
verbose
|
|
307
|
+
);
|
|
289
308
|
return false;
|
|
290
309
|
}
|
|
291
310
|
|
|
292
|
-
if (!
|
|
293
|
-
let
|
|
294
|
-
nestedStrictness = false,
|
|
311
|
+
if (!_.isNil(documentSubset[fieldName])) {
|
|
312
|
+
let nestedStrictness = false,
|
|
295
313
|
fieldValues;
|
|
296
314
|
|
|
297
315
|
if (field.multivalued.value) {
|
|
298
|
-
if (!
|
|
316
|
+
if (!Array.isArray(documentSubset[fieldName])) {
|
|
299
317
|
manageErrorMessage(
|
|
300
318
|
field.path,
|
|
301
319
|
errorMessages,
|
|
302
|
-
|
|
303
|
-
verbose
|
|
320
|
+
"The field must be multivalued, unary value provided.",
|
|
321
|
+
verbose
|
|
322
|
+
);
|
|
304
323
|
return false;
|
|
305
324
|
}
|
|
306
325
|
|
|
307
|
-
if (
|
|
308
|
-
|
|
326
|
+
if (
|
|
327
|
+
has(field.multivalued, "minCount") &&
|
|
328
|
+
documentSubset[fieldName].length < field.multivalued.minCount
|
|
309
329
|
) {
|
|
310
330
|
manageErrorMessage(
|
|
311
331
|
field.path,
|
|
312
332
|
errorMessages,
|
|
313
333
|
`Not enough elements. Minimum count is set to ${field.multivalued.minCount}.`,
|
|
314
|
-
verbose
|
|
334
|
+
verbose
|
|
335
|
+
);
|
|
315
336
|
return false;
|
|
316
337
|
}
|
|
317
338
|
|
|
318
|
-
if (
|
|
319
|
-
|
|
339
|
+
if (
|
|
340
|
+
has(field.multivalued, "maxCount") &&
|
|
341
|
+
documentSubset[fieldName].length > field.multivalued.maxCount
|
|
320
342
|
) {
|
|
321
343
|
manageErrorMessage(
|
|
322
344
|
field.path,
|
|
323
345
|
errorMessages,
|
|
324
346
|
`Too many elements. Maximum count is set to ${field.multivalued.maxCount}.`,
|
|
325
|
-
verbose
|
|
347
|
+
verbose
|
|
348
|
+
);
|
|
326
349
|
return false;
|
|
327
350
|
}
|
|
328
351
|
|
|
329
352
|
fieldValues = documentSubset[fieldName];
|
|
330
|
-
}
|
|
331
|
-
else {
|
|
353
|
+
} else {
|
|
332
354
|
if (Array.isArray(documentSubset[fieldName])) {
|
|
333
355
|
manageErrorMessage(
|
|
334
356
|
field.path,
|
|
335
357
|
errorMessages,
|
|
336
|
-
|
|
337
|
-
verbose
|
|
358
|
+
"The field is not a multivalued field; Multiple values provided.",
|
|
359
|
+
verbose
|
|
360
|
+
);
|
|
338
361
|
return false;
|
|
339
362
|
}
|
|
340
363
|
|
|
@@ -344,64 +367,61 @@ class Validation {
|
|
|
344
367
|
if (this.types[field.type].allowChildren) {
|
|
345
368
|
nestedStrictness = this.types[field.type].getStrictness(
|
|
346
369
|
field.typeOptions,
|
|
347
|
-
strictness
|
|
370
|
+
strictness
|
|
371
|
+
);
|
|
348
372
|
}
|
|
349
373
|
|
|
350
374
|
for (const val of fieldValues) {
|
|
351
375
|
const fieldErrors = [];
|
|
352
376
|
|
|
353
|
-
if (
|
|
354
|
-
field.typeOptions,
|
|
355
|
-
val,
|
|
356
|
-
fieldErrors)
|
|
377
|
+
if (
|
|
378
|
+
!this.types[field.type].validate(field.typeOptions, val, fieldErrors)
|
|
357
379
|
) {
|
|
358
380
|
if (fieldErrors.length === 0) {
|
|
359
381
|
// We still want to trigger an error, even if no message is provided
|
|
360
382
|
manageErrorMessage(
|
|
361
383
|
field.path,
|
|
362
384
|
errorMessages,
|
|
363
|
-
|
|
364
|
-
verbose
|
|
365
|
-
|
|
366
|
-
else {
|
|
367
|
-
fieldErrors.forEach(
|
|
368
|
-
message
|
|
369
|
-
|
|
370
|
-
errorMessages,
|
|
371
|
-
message,
|
|
372
|
-
verbose));
|
|
385
|
+
"An error has occurred during validation.",
|
|
386
|
+
verbose
|
|
387
|
+
);
|
|
388
|
+
} else {
|
|
389
|
+
fieldErrors.forEach((message) =>
|
|
390
|
+
manageErrorMessage(field.path, errorMessages, message, verbose)
|
|
391
|
+
);
|
|
373
392
|
}
|
|
374
393
|
return false;
|
|
375
394
|
}
|
|
376
395
|
|
|
377
396
|
if (this.types[field.type].allowChildren && field.children) {
|
|
378
397
|
try {
|
|
379
|
-
if (
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
398
|
+
if (
|
|
399
|
+
!this.recurseFieldValidation(
|
|
400
|
+
val,
|
|
401
|
+
field.children,
|
|
402
|
+
nestedStrictness,
|
|
403
|
+
errorMessages,
|
|
404
|
+
verbose
|
|
405
|
+
)
|
|
406
|
+
) {
|
|
386
407
|
result = false;
|
|
387
408
|
}
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
if (error.message === 'strictness') {
|
|
409
|
+
} catch (error) {
|
|
410
|
+
if (error.message === "strictness") {
|
|
391
411
|
manageErrorMessage(
|
|
392
412
|
field.path,
|
|
393
413
|
errorMessages,
|
|
394
414
|
`The field is set to "strict"; cannot add unspecified sub-field "${error.details.field}".`,
|
|
395
|
-
verbose
|
|
396
|
-
|
|
397
|
-
else if (verbose) {
|
|
415
|
+
verbose
|
|
416
|
+
);
|
|
417
|
+
} else if (verbose) {
|
|
398
418
|
manageErrorMessage(
|
|
399
419
|
field.path,
|
|
400
420
|
errorMessages,
|
|
401
421
|
error.message,
|
|
402
|
-
verbose
|
|
403
|
-
|
|
404
|
-
else {
|
|
422
|
+
verbose
|
|
423
|
+
);
|
|
424
|
+
} else {
|
|
405
425
|
throw error;
|
|
406
426
|
}
|
|
407
427
|
|
|
@@ -416,51 +436,47 @@ class Validation {
|
|
|
416
436
|
/**
|
|
417
437
|
* @returns {Promise.<T>}
|
|
418
438
|
*/
|
|
419
|
-
curateSpecification
|
|
420
|
-
const
|
|
421
|
-
promises = [],
|
|
439
|
+
curateSpecification() {
|
|
440
|
+
const promises = [],
|
|
422
441
|
specification = {};
|
|
423
442
|
|
|
424
|
-
return getValidationConfiguration()
|
|
425
|
-
.
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
for (const
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
)
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
promises.push(promise);
|
|
455
|
-
}
|
|
443
|
+
return getValidationConfiguration().then((validation) => {
|
|
444
|
+
this.rawConfiguration = validation;
|
|
445
|
+
|
|
446
|
+
for (const indexName of Object.keys(this.rawConfiguration)) {
|
|
447
|
+
for (const collectionName of Object.keys(
|
|
448
|
+
this.rawConfiguration[indexName]
|
|
449
|
+
)) {
|
|
450
|
+
const promise = this.curateCollectionSpecification(
|
|
451
|
+
indexName,
|
|
452
|
+
collectionName,
|
|
453
|
+
this.rawConfiguration[indexName][collectionName]
|
|
454
|
+
)
|
|
455
|
+
.then((curatedSpec) => {
|
|
456
|
+
if (!has(specification, indexName)) {
|
|
457
|
+
specification[indexName] = {};
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
specification[indexName][collectionName] = curatedSpec;
|
|
461
|
+
|
|
462
|
+
return null;
|
|
463
|
+
})
|
|
464
|
+
.catch((error) => {
|
|
465
|
+
global.kuzzle.log.error(
|
|
466
|
+
`Specification for the collection ${collectionName} triggered an error`
|
|
467
|
+
);
|
|
468
|
+
global.kuzzle.log.error(`Error: ${error.message}`);
|
|
469
|
+
|
|
470
|
+
return null;
|
|
471
|
+
});
|
|
472
|
+
promises.push(promise);
|
|
456
473
|
}
|
|
474
|
+
}
|
|
457
475
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
.then(() => {
|
|
461
|
-
this.specification = specification;
|
|
462
|
-
});
|
|
476
|
+
return Bluebird.all(promises).then(() => {
|
|
477
|
+
this.specification = specification;
|
|
463
478
|
});
|
|
479
|
+
});
|
|
464
480
|
}
|
|
465
481
|
|
|
466
482
|
/**
|
|
@@ -470,7 +486,7 @@ class Validation {
|
|
|
470
486
|
* @param {boolean} [verboseErrors]
|
|
471
487
|
* @returns {Promise<object>}
|
|
472
488
|
*/
|
|
473
|
-
validateFormat
|
|
489
|
+
validateFormat(
|
|
474
490
|
indexName,
|
|
475
491
|
collectionName,
|
|
476
492
|
collectionSpec,
|
|
@@ -479,21 +495,24 @@ class Validation {
|
|
|
479
495
|
// We make a deep clone to avoid side effects
|
|
480
496
|
const specification = _.cloneDeep(collectionSpec);
|
|
481
497
|
|
|
482
|
-
return
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
498
|
+
return (
|
|
499
|
+
this.curateCollectionSpecification(
|
|
500
|
+
indexName,
|
|
501
|
+
collectionName,
|
|
502
|
+
specification,
|
|
503
|
+
true,
|
|
504
|
+
verboseErrors
|
|
505
|
+
)
|
|
506
|
+
.then((result) => {
|
|
507
|
+
if (verboseErrors && result.isValid === false) {
|
|
508
|
+
return result;
|
|
509
|
+
}
|
|
510
|
+
return { isValid: true };
|
|
511
|
+
})
|
|
512
|
+
// we do not want to reject since this method goal is
|
|
513
|
+
// to know what is going wrong with the given spec
|
|
514
|
+
.catch((error) => ({ errors: [error], isValid: false }))
|
|
515
|
+
);
|
|
497
516
|
}
|
|
498
517
|
|
|
499
518
|
/**
|
|
@@ -505,26 +524,27 @@ class Validation {
|
|
|
505
524
|
* @returns {Promise<CollectionSpecification>}
|
|
506
525
|
* @rejects PreconditionError
|
|
507
526
|
*/
|
|
508
|
-
async curateCollectionSpecification
|
|
527
|
+
async curateCollectionSpecification(
|
|
509
528
|
index,
|
|
510
529
|
collection,
|
|
511
530
|
spec,
|
|
512
531
|
dryRun = false,
|
|
513
532
|
verbose = false
|
|
514
533
|
) {
|
|
515
|
-
let error =
|
|
534
|
+
let error = "";
|
|
516
535
|
const processed = {
|
|
517
536
|
fields: {},
|
|
518
537
|
strict: spec.strict || false,
|
|
519
|
-
validators: null
|
|
538
|
+
validators: null,
|
|
520
539
|
};
|
|
521
|
-
const allowed = [
|
|
540
|
+
const allowed = ["strict", "fields", "validators"];
|
|
522
541
|
|
|
523
|
-
if (!
|
|
542
|
+
if (!checkAllowedProperties(spec, allowed)) {
|
|
524
543
|
error = assertionError.get(
|
|
525
|
-
|
|
544
|
+
"unexpected_properties",
|
|
526
545
|
`${index}.${collection}`,
|
|
527
|
-
allowed.join(
|
|
546
|
+
allowed.join(", ")
|
|
547
|
+
);
|
|
528
548
|
|
|
529
549
|
if (verbose) {
|
|
530
550
|
return { errors: [error.message], isValid: false };
|
|
@@ -538,7 +558,8 @@ class Validation {
|
|
|
538
558
|
spec,
|
|
539
559
|
index,
|
|
540
560
|
collection,
|
|
541
|
-
verbose
|
|
561
|
+
verbose
|
|
562
|
+
);
|
|
542
563
|
|
|
543
564
|
if (result.isValid === false) {
|
|
544
565
|
if (verbose) {
|
|
@@ -546,7 +567,10 @@ class Validation {
|
|
|
546
567
|
return result;
|
|
547
568
|
}
|
|
548
569
|
|
|
549
|
-
throw assertionError.get(
|
|
570
|
+
throw assertionError.get(
|
|
571
|
+
"invalid_specifications",
|
|
572
|
+
result.errors.join("\n\t- ")
|
|
573
|
+
);
|
|
550
574
|
}
|
|
551
575
|
processed.fields = result;
|
|
552
576
|
}
|
|
@@ -557,33 +581,31 @@ class Validation {
|
|
|
557
581
|
index,
|
|
558
582
|
collection,
|
|
559
583
|
spec.validators,
|
|
560
|
-
dryRun
|
|
584
|
+
dryRun
|
|
585
|
+
);
|
|
561
586
|
|
|
562
587
|
processed.validators = filterId;
|
|
563
|
-
}
|
|
564
|
-
catch (e) {
|
|
588
|
+
} catch (e) {
|
|
565
589
|
global.kuzzle.log.error(e);
|
|
566
|
-
throw assertionError.getFrom(e,
|
|
590
|
+
throw assertionError.getFrom(e, "invalid_filters", e.message);
|
|
567
591
|
}
|
|
568
592
|
}
|
|
569
593
|
|
|
570
594
|
return processed;
|
|
571
595
|
}
|
|
572
596
|
|
|
573
|
-
structureCollectionValidation
|
|
597
|
+
structureCollectionValidation(
|
|
574
598
|
collectionSpec,
|
|
575
599
|
indexName,
|
|
576
600
|
collectionName,
|
|
577
601
|
verboseErrors = false
|
|
578
602
|
) {
|
|
579
603
|
const fields = {};
|
|
580
|
-
let
|
|
581
|
-
errors = [],
|
|
604
|
+
let errors = [],
|
|
582
605
|
maxDepth = 0;
|
|
583
606
|
|
|
584
607
|
for (const fieldName of Object.keys(collectionSpec.fields)) {
|
|
585
|
-
const
|
|
586
|
-
// We deep clone the field because we will modify it
|
|
608
|
+
const // We deep clone the field because we will modify it
|
|
587
609
|
fieldSpecClone = _.cloneDeep(collectionSpec.fields[fieldName]);
|
|
588
610
|
|
|
589
611
|
try {
|
|
@@ -592,30 +614,29 @@ class Validation {
|
|
|
592
614
|
indexName,
|
|
593
615
|
collectionName,
|
|
594
616
|
fieldName,
|
|
595
|
-
verboseErrors
|
|
617
|
+
verboseErrors
|
|
618
|
+
);
|
|
596
619
|
|
|
597
620
|
if (result.isValid === false) {
|
|
598
621
|
errors = _.concat(errors, result.errors);
|
|
599
|
-
global.kuzzle.log.error(result.errors.join(
|
|
600
|
-
}
|
|
601
|
-
else {
|
|
622
|
+
global.kuzzle.log.error(result.errors.join("\n"));
|
|
623
|
+
} else {
|
|
602
624
|
const field = result.fieldSpec;
|
|
603
625
|
|
|
604
|
-
field.path = fieldName.split(
|
|
626
|
+
field.path = fieldName.split("/");
|
|
605
627
|
field.depth = field.path.length;
|
|
606
628
|
|
|
607
629
|
if (field.depth > maxDepth) {
|
|
608
630
|
maxDepth = field.depth;
|
|
609
631
|
}
|
|
610
632
|
|
|
611
|
-
if (!
|
|
633
|
+
if (!fields[field.depth]) {
|
|
612
634
|
fields[field.depth] = [];
|
|
613
635
|
}
|
|
614
636
|
|
|
615
637
|
fields[field.depth].push(field);
|
|
616
638
|
}
|
|
617
|
-
}
|
|
618
|
-
catch (error) {
|
|
639
|
+
} catch (error) {
|
|
619
640
|
global.kuzzle.log.error(error);
|
|
620
641
|
throwOrStoreError(error, verboseErrors, errors);
|
|
621
642
|
}
|
|
@@ -640,7 +661,7 @@ class Validation {
|
|
|
640
661
|
* @returns {object}
|
|
641
662
|
* @throws PreconditionError
|
|
642
663
|
*/
|
|
643
|
-
curateFieldSpecification
|
|
664
|
+
curateFieldSpecification(
|
|
644
665
|
fieldSpec,
|
|
645
666
|
indexName,
|
|
646
667
|
collectionName,
|
|
@@ -662,43 +683,46 @@ class Validation {
|
|
|
662
683
|
}
|
|
663
684
|
|
|
664
685
|
_.defaultsDeep(fieldSpec, {
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
value: false
|
|
668
|
-
}
|
|
686
|
+
mandatory: false,
|
|
687
|
+
multivalued: {
|
|
688
|
+
value: false,
|
|
689
|
+
},
|
|
669
690
|
});
|
|
670
691
|
|
|
671
|
-
if (!
|
|
692
|
+
if (!has(fieldSpec, "typeOptions")) {
|
|
672
693
|
fieldSpec.typeOptions = {};
|
|
673
694
|
}
|
|
674
695
|
|
|
675
696
|
const allowed = this.types[fieldSpec.type].allowedTypeOptions || [];
|
|
676
697
|
|
|
677
|
-
if (!
|
|
698
|
+
if (!checkAllowedProperties(fieldSpec.typeOptions, allowed)) {
|
|
678
699
|
throwOrStoreError(
|
|
679
700
|
assertionError.get(
|
|
680
|
-
|
|
701
|
+
"unexpected_properties",
|
|
681
702
|
`${indexName}.${collectionName}.${fieldName}`,
|
|
682
|
-
allowed.join(
|
|
703
|
+
allowed.join(", ")
|
|
704
|
+
),
|
|
683
705
|
verboseErrors,
|
|
684
|
-
errors
|
|
706
|
+
errors
|
|
707
|
+
);
|
|
685
708
|
}
|
|
686
709
|
|
|
687
710
|
try {
|
|
688
|
-
fieldSpec.typeOptions = this.types[
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
catch (e) {
|
|
692
|
-
if (!
|
|
711
|
+
fieldSpec.typeOptions = this.types[
|
|
712
|
+
fieldSpec.type
|
|
713
|
+
].validateFieldSpecification(fieldSpec.typeOptions);
|
|
714
|
+
} catch (e) {
|
|
715
|
+
if (!verboseErrors) {
|
|
693
716
|
if (e instanceof KuzzleError) {
|
|
694
717
|
throw e;
|
|
695
718
|
}
|
|
696
719
|
throw kerror.getFrom(
|
|
697
720
|
e,
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
e.message
|
|
721
|
+
"plugin",
|
|
722
|
+
"runtime",
|
|
723
|
+
"unexpected_error",
|
|
724
|
+
e.message
|
|
725
|
+
);
|
|
702
726
|
}
|
|
703
727
|
|
|
704
728
|
errors.push(e.message);
|
|
@@ -709,11 +733,12 @@ class Validation {
|
|
|
709
733
|
}
|
|
710
734
|
|
|
711
735
|
debug(
|
|
712
|
-
|
|
736
|
+
"Loaded field validator: %s/%s/%s: %o",
|
|
713
737
|
indexName,
|
|
714
738
|
collectionName,
|
|
715
739
|
fieldName,
|
|
716
|
-
fieldSpec
|
|
740
|
+
fieldSpec
|
|
741
|
+
);
|
|
717
742
|
|
|
718
743
|
return { fieldSpec, isValid: true };
|
|
719
744
|
}
|
|
@@ -727,7 +752,7 @@ class Validation {
|
|
|
727
752
|
* @returns {object}
|
|
728
753
|
* @throws PreconditionError
|
|
729
754
|
*/
|
|
730
|
-
curateFieldSpecificationFormat
|
|
755
|
+
curateFieldSpecificationFormat(
|
|
731
756
|
fieldSpec,
|
|
732
757
|
indexName,
|
|
733
758
|
collectionName,
|
|
@@ -737,100 +762,118 @@ class Validation {
|
|
|
737
762
|
const errors = [];
|
|
738
763
|
|
|
739
764
|
const props = [
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
765
|
+
"mandatory",
|
|
766
|
+
"type",
|
|
767
|
+
"defaultValue",
|
|
768
|
+
"description",
|
|
769
|
+
"multivalued",
|
|
770
|
+
"typeOptions",
|
|
746
771
|
];
|
|
747
772
|
|
|
748
|
-
if (!
|
|
773
|
+
if (!checkAllowedProperties(fieldSpec, props)) {
|
|
749
774
|
throwOrStoreError(
|
|
750
775
|
assertionError.get(
|
|
751
|
-
|
|
776
|
+
"unexpected_properties",
|
|
752
777
|
`${indexName}.${collectionName}.${fieldName}`,
|
|
753
|
-
props.join(
|
|
778
|
+
props.join(", ")
|
|
779
|
+
),
|
|
754
780
|
verboseErrors,
|
|
755
|
-
errors
|
|
781
|
+
errors
|
|
782
|
+
);
|
|
756
783
|
}
|
|
757
784
|
|
|
758
|
-
if (!
|
|
785
|
+
if (!has(fieldSpec, "type")) {
|
|
759
786
|
throwOrStoreError(
|
|
760
787
|
assertionError.get(
|
|
761
|
-
|
|
762
|
-
`${indexName}.${collectionName}.${fieldName}`
|
|
788
|
+
"missing_type",
|
|
789
|
+
`${indexName}.${collectionName}.${fieldName}`
|
|
790
|
+
),
|
|
763
791
|
verboseErrors,
|
|
764
|
-
errors
|
|
792
|
+
errors
|
|
793
|
+
);
|
|
765
794
|
}
|
|
766
795
|
|
|
767
|
-
if (!
|
|
796
|
+
if (!has(this.types, fieldSpec.type)) {
|
|
768
797
|
throwOrStoreError(
|
|
769
798
|
assertionError.get(
|
|
770
|
-
|
|
799
|
+
"unknown_type",
|
|
771
800
|
`${indexName}.${collectionName}.${fieldName}`,
|
|
772
|
-
fieldSpec.type
|
|
801
|
+
fieldSpec.type
|
|
802
|
+
),
|
|
773
803
|
verboseErrors,
|
|
774
|
-
errors
|
|
804
|
+
errors
|
|
805
|
+
);
|
|
775
806
|
}
|
|
776
807
|
|
|
777
|
-
if (has(fieldSpec,
|
|
778
|
-
const multivaluedProps = [
|
|
779
|
-
if (!
|
|
808
|
+
if (has(fieldSpec, "multivalued")) {
|
|
809
|
+
const multivaluedProps = ["value", "minCount", "maxCount"];
|
|
810
|
+
if (!checkAllowedProperties(fieldSpec.multivalued, multivaluedProps)) {
|
|
780
811
|
throwOrStoreError(
|
|
781
812
|
assertionError.get(
|
|
782
|
-
|
|
813
|
+
"unexpected_properties",
|
|
783
814
|
`${indexName}.${collectionName}.${fieldName}.multivalued`,
|
|
784
|
-
multivaluedProps.join(
|
|
815
|
+
multivaluedProps.join(", ")
|
|
816
|
+
),
|
|
785
817
|
verboseErrors,
|
|
786
|
-
errors
|
|
818
|
+
errors
|
|
819
|
+
);
|
|
787
820
|
}
|
|
788
821
|
|
|
789
|
-
if (!
|
|
822
|
+
if (!has(fieldSpec.multivalued, "value")) {
|
|
790
823
|
throwOrStoreError(
|
|
791
824
|
assertionError.get(
|
|
792
|
-
|
|
793
|
-
`${indexName}.${collectionName}.${fieldName}.multivalued`
|
|
825
|
+
"missing_value",
|
|
826
|
+
`${indexName}.${collectionName}.${fieldName}.multivalued`
|
|
827
|
+
),
|
|
794
828
|
verboseErrors,
|
|
795
|
-
errors
|
|
829
|
+
errors
|
|
830
|
+
);
|
|
796
831
|
}
|
|
797
832
|
|
|
798
|
-
if (typeof fieldSpec.multivalued.value !==
|
|
833
|
+
if (typeof fieldSpec.multivalued.value !== "boolean") {
|
|
799
834
|
throwOrStoreError(
|
|
800
835
|
assertionError.get(
|
|
801
|
-
|
|
836
|
+
"invalid_type",
|
|
802
837
|
`${indexName}.${collectionName}.${fieldName}.multivalued.value`,
|
|
803
|
-
|
|
838
|
+
"boolean"
|
|
839
|
+
),
|
|
804
840
|
verboseErrors,
|
|
805
|
-
errors
|
|
841
|
+
errors
|
|
842
|
+
);
|
|
806
843
|
}
|
|
807
844
|
|
|
808
|
-
for (const unexpected of [
|
|
809
|
-
if (
|
|
810
|
-
|
|
845
|
+
for (const unexpected of ["minCount", "maxCount"]) {
|
|
846
|
+
if (
|
|
847
|
+
!fieldSpec.multivalued.value &&
|
|
848
|
+
has(fieldSpec.multivalued, unexpected)
|
|
811
849
|
) {
|
|
812
850
|
throwOrStoreError(
|
|
813
851
|
assertionError.get(
|
|
814
|
-
|
|
852
|
+
"not_multivalued",
|
|
815
853
|
`${indexName}.${collectionName}.${fieldName}`,
|
|
816
|
-
unexpected
|
|
854
|
+
unexpected
|
|
855
|
+
),
|
|
817
856
|
verboseErrors,
|
|
818
|
-
errors
|
|
857
|
+
errors
|
|
858
|
+
);
|
|
819
859
|
}
|
|
820
860
|
}
|
|
821
861
|
|
|
822
|
-
if (
|
|
823
|
-
|
|
824
|
-
|
|
862
|
+
if (
|
|
863
|
+
has(fieldSpec.multivalued, "minCount") &&
|
|
864
|
+
has(fieldSpec.multivalued, "maxCount") &&
|
|
865
|
+
fieldSpec.multivalued.minCount > fieldSpec.multivalued.maxCount
|
|
825
866
|
) {
|
|
826
867
|
throwOrStoreError(
|
|
827
868
|
assertionError.get(
|
|
828
|
-
|
|
869
|
+
"invalid_range",
|
|
829
870
|
`${indexName}.${collectionName}.${fieldName}`,
|
|
830
|
-
|
|
831
|
-
|
|
871
|
+
"minCount",
|
|
872
|
+
"maxCount"
|
|
873
|
+
),
|
|
832
874
|
verboseErrors,
|
|
833
|
-
errors
|
|
875
|
+
errors
|
|
876
|
+
);
|
|
834
877
|
}
|
|
835
878
|
}
|
|
836
879
|
|
|
@@ -848,25 +891,27 @@ class Validation {
|
|
|
848
891
|
* @param {boolean} dryRun
|
|
849
892
|
* @returns {string}
|
|
850
893
|
*/
|
|
851
|
-
curateValidatorFilter
|
|
894
|
+
curateValidatorFilter(indexName, collectionName, validatorFilter, dryRun) {
|
|
852
895
|
const query = {
|
|
853
896
|
bool: {
|
|
854
|
-
must: validatorFilter
|
|
855
|
-
}
|
|
897
|
+
must: validatorFilter,
|
|
898
|
+
},
|
|
856
899
|
};
|
|
857
900
|
|
|
858
901
|
this.koncorde.validate(query);
|
|
859
902
|
|
|
860
|
-
if (!
|
|
903
|
+
if (!dryRun) {
|
|
861
904
|
debug(
|
|
862
|
-
|
|
905
|
+
"Registering filter validator %s/%s: %O",
|
|
863
906
|
indexName,
|
|
864
907
|
collectionName,
|
|
865
|
-
query
|
|
908
|
+
query
|
|
909
|
+
);
|
|
866
910
|
|
|
867
911
|
return this.koncorde.register(
|
|
868
912
|
query,
|
|
869
|
-
toKoncordeIndex(indexName, collectionName)
|
|
913
|
+
toKoncordeIndex(indexName, collectionName)
|
|
914
|
+
);
|
|
870
915
|
}
|
|
871
916
|
|
|
872
917
|
return null;
|
|
@@ -876,45 +921,49 @@ class Validation {
|
|
|
876
921
|
* @param {ValidationType} validationType
|
|
877
922
|
* @throws {PluginImplementationError}
|
|
878
923
|
*/
|
|
879
|
-
addType
|
|
880
|
-
if (!
|
|
881
|
-
throw kerror.get(
|
|
924
|
+
addType(validationType) {
|
|
925
|
+
if (!validationType.typeName) {
|
|
926
|
+
throw kerror.get("validation", "types", "missing_type_name");
|
|
882
927
|
}
|
|
883
928
|
|
|
884
|
-
if (
|
|
885
|
-
|
|
929
|
+
if (
|
|
930
|
+
!validationType.validate ||
|
|
931
|
+
typeof validationType.validate !== "function"
|
|
886
932
|
) {
|
|
887
933
|
throw kerror.get(
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
934
|
+
"validation",
|
|
935
|
+
"types",
|
|
936
|
+
"missing_function",
|
|
891
937
|
validationType.typeName,
|
|
892
|
-
|
|
938
|
+
"validate"
|
|
939
|
+
);
|
|
893
940
|
}
|
|
894
941
|
|
|
895
|
-
if (
|
|
896
|
-
|
|
942
|
+
if (
|
|
943
|
+
!validationType.validateFieldSpecification ||
|
|
944
|
+
typeof validationType.validateFieldSpecification !== "function"
|
|
897
945
|
) {
|
|
898
946
|
throw kerror.get(
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
947
|
+
"validation",
|
|
948
|
+
"types",
|
|
949
|
+
"missing_function",
|
|
902
950
|
validationType.typeName,
|
|
903
|
-
|
|
951
|
+
"validateFieldSpecification"
|
|
952
|
+
);
|
|
904
953
|
}
|
|
905
954
|
|
|
906
|
-
if (has(validationType,
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|| typeof validationType.getStrictness !== 'function'
|
|
955
|
+
if (has(validationType, "allowChildren") && validationType.allowChildren) {
|
|
956
|
+
if (
|
|
957
|
+
!validationType.getStrictness ||
|
|
958
|
+
typeof validationType.getStrictness !== "function"
|
|
911
959
|
) {
|
|
912
960
|
throw kerror.get(
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
961
|
+
"validation",
|
|
962
|
+
"types",
|
|
963
|
+
"missing_function",
|
|
916
964
|
validationType.typeName,
|
|
917
|
-
|
|
965
|
+
"getStrictness"
|
|
966
|
+
);
|
|
918
967
|
}
|
|
919
968
|
|
|
920
969
|
this.typeAllowsChildren.push(validationType.typeName);
|
|
@@ -922,15 +971,15 @@ class Validation {
|
|
|
922
971
|
|
|
923
972
|
if (this.types[validationType.typeName]) {
|
|
924
973
|
throw kerror.get(
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
validationType.typeName
|
|
974
|
+
"validation",
|
|
975
|
+
"types",
|
|
976
|
+
"already_exists",
|
|
977
|
+
validationType.typeName
|
|
978
|
+
);
|
|
929
979
|
}
|
|
930
980
|
|
|
931
981
|
this.types[validationType.typeName] = validationType;
|
|
932
982
|
}
|
|
933
|
-
|
|
934
983
|
}
|
|
935
984
|
|
|
936
985
|
/**
|
|
@@ -938,13 +987,14 @@ class Validation {
|
|
|
938
987
|
* @param {string[]} allowedProperties
|
|
939
988
|
* @returns {boolean}
|
|
940
989
|
*/
|
|
941
|
-
function checkAllowedProperties
|
|
942
|
-
if (!
|
|
990
|
+
function checkAllowedProperties(object, allowedProperties) {
|
|
991
|
+
if (!isPlainObject(object)) {
|
|
943
992
|
return false;
|
|
944
993
|
}
|
|
945
994
|
|
|
946
|
-
return !
|
|
947
|
-
propertyName => !
|
|
995
|
+
return !Object.keys(object).some(
|
|
996
|
+
(propertyName) => !allowedProperties.includes(propertyName)
|
|
997
|
+
);
|
|
948
998
|
}
|
|
949
999
|
|
|
950
1000
|
/**
|
|
@@ -953,29 +1003,27 @@ function checkAllowedProperties (object, allowedProperties) {
|
|
|
953
1003
|
* @param {number} maxDepth : depth of the fields; counting starts at 1
|
|
954
1004
|
* @throws PreconditionError
|
|
955
1005
|
*/
|
|
956
|
-
function curateStructuredFields
|
|
957
|
-
const
|
|
958
|
-
/** @type StructuredFieldSpecification */
|
|
1006
|
+
function curateStructuredFields(typeAllowsChildren, fields, maxDepth) {
|
|
1007
|
+
const /** @type StructuredFieldSpecification */
|
|
959
1008
|
structuredFields = {
|
|
960
1009
|
children: {},
|
|
961
|
-
root: true
|
|
1010
|
+
root: true,
|
|
962
1011
|
};
|
|
963
1012
|
|
|
964
1013
|
for (let i = 1; i <= maxDepth; i++) {
|
|
965
|
-
if (!
|
|
966
|
-
throw assertionError.get(
|
|
1014
|
+
if (!has(fields, i)) {
|
|
1015
|
+
throw assertionError.get("missing_nested_spec");
|
|
967
1016
|
}
|
|
968
1017
|
|
|
969
|
-
fields[i].forEach(field => {
|
|
970
|
-
const
|
|
971
|
-
parent = getParent(structuredFields, field.path),
|
|
1018
|
+
fields[i].forEach((field) => {
|
|
1019
|
+
const parent = getParent(structuredFields, field.path),
|
|
972
1020
|
childKey = field.path[field.path.length - 1];
|
|
973
1021
|
|
|
974
|
-
if (!
|
|
975
|
-
throw assertionError.get(
|
|
1022
|
+
if (!parent.root && typeAllowsChildren.indexOf(parent.type) === -1) {
|
|
1023
|
+
throw assertionError.get("unexpected_children", parent.type);
|
|
976
1024
|
}
|
|
977
1025
|
|
|
978
|
-
if (!
|
|
1026
|
+
if (!has(parent, "children")) {
|
|
979
1027
|
parent.children = {};
|
|
980
1028
|
}
|
|
981
1029
|
|
|
@@ -991,7 +1039,7 @@ function curateStructuredFields (typeAllowsChildren, fields, maxDepth) {
|
|
|
991
1039
|
* @param {string[]}fieldPath
|
|
992
1040
|
* @returns {StructuredFieldSpecification}
|
|
993
1041
|
*/
|
|
994
|
-
function getParent
|
|
1042
|
+
function getParent(structuredFields, fieldPath) {
|
|
995
1043
|
if (fieldPath.length === 1) {
|
|
996
1044
|
return structuredFields;
|
|
997
1045
|
}
|
|
@@ -999,8 +1047,8 @@ function getParent (structuredFields, fieldPath) {
|
|
|
999
1047
|
let pointer = structuredFields;
|
|
1000
1048
|
|
|
1001
1049
|
for (let i = 0; i < fieldPath.length - 1; i++) {
|
|
1002
|
-
if (!
|
|
1003
|
-
throw assertionError.get(
|
|
1050
|
+
if (!has(pointer.children, fieldPath[i])) {
|
|
1051
|
+
throw assertionError.get("missing_parent", fieldPath.join("."));
|
|
1004
1052
|
}
|
|
1005
1053
|
|
|
1006
1054
|
pointer = pointer.children[fieldPath[i]];
|
|
@@ -1014,8 +1062,8 @@ function getParent (structuredFields, fieldPath) {
|
|
|
1014
1062
|
* @param {boolean} doNotThrow
|
|
1015
1063
|
* @param {string[]} errors
|
|
1016
1064
|
*/
|
|
1017
|
-
function throwOrStoreError
|
|
1018
|
-
if (!
|
|
1065
|
+
function throwOrStoreError(error, doNotThrow, errorMessages) {
|
|
1066
|
+
if (!doNotThrow) {
|
|
1019
1067
|
throw error;
|
|
1020
1068
|
}
|
|
1021
1069
|
|
|
@@ -1028,50 +1076,48 @@ function throwOrStoreError (error, doNotThrow, errorMessages) {
|
|
|
1028
1076
|
* @param {string} message
|
|
1029
1077
|
* @param {boolean} structured
|
|
1030
1078
|
*/
|
|
1031
|
-
function manageErrorMessage
|
|
1079
|
+
function manageErrorMessage(errorContext, errorHolder, message, structured) {
|
|
1032
1080
|
if (structured) {
|
|
1033
|
-
if (errorContext ===
|
|
1034
|
-
if (!
|
|
1081
|
+
if (errorContext === "document") {
|
|
1082
|
+
if (!errorHolder.documentScope) {
|
|
1035
1083
|
errorHolder.documentScope = [];
|
|
1036
1084
|
}
|
|
1037
1085
|
|
|
1038
1086
|
errorHolder.documentScope.push(message);
|
|
1039
|
-
}
|
|
1040
|
-
|
|
1041
|
-
if (! errorHolder.fieldScope) {
|
|
1087
|
+
} else {
|
|
1088
|
+
if (!errorHolder.fieldScope) {
|
|
1042
1089
|
errorHolder.fieldScope = {};
|
|
1043
1090
|
}
|
|
1044
1091
|
|
|
1045
1092
|
let pointer = errorHolder.fieldScope;
|
|
1046
1093
|
|
|
1047
1094
|
for (let i = 0; i < errorContext.length; i++) {
|
|
1048
|
-
if (!
|
|
1095
|
+
if (!pointer.children) {
|
|
1049
1096
|
pointer.children = {};
|
|
1050
1097
|
}
|
|
1051
1098
|
|
|
1052
|
-
if (!
|
|
1099
|
+
if (!has(pointer.children, errorContext[i])) {
|
|
1053
1100
|
pointer.children[errorContext[i]] = {};
|
|
1054
1101
|
}
|
|
1055
1102
|
pointer = pointer.children[errorContext[i]];
|
|
1056
1103
|
}
|
|
1057
1104
|
|
|
1058
|
-
if (!
|
|
1105
|
+
if (!has(pointer, "messages")) {
|
|
1059
1106
|
pointer.messages = [];
|
|
1060
1107
|
}
|
|
1061
1108
|
|
|
1062
1109
|
pointer.messages.push(message);
|
|
1063
1110
|
}
|
|
1064
|
-
}
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
}
|
|
1068
|
-
else {
|
|
1111
|
+
} else if (errorContext === "document") {
|
|
1112
|
+
throw kerror.get("validation", "check", "failed_document", message);
|
|
1113
|
+
} else {
|
|
1069
1114
|
throw kerror.get(
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
errorContext.join(
|
|
1074
|
-
message
|
|
1115
|
+
"validation",
|
|
1116
|
+
"check",
|
|
1117
|
+
"failed_field",
|
|
1118
|
+
errorContext.join("."),
|
|
1119
|
+
message
|
|
1120
|
+
);
|
|
1075
1121
|
}
|
|
1076
1122
|
}
|
|
1077
1123
|
|
|
@@ -1081,49 +1127,47 @@ function manageErrorMessage (errorContext, errorHolder, message, structured) {
|
|
|
1081
1127
|
*
|
|
1082
1128
|
* @returns {Promise}
|
|
1083
1129
|
*/
|
|
1084
|
-
function getValidationConfiguration
|
|
1130
|
+
function getValidationConfiguration() {
|
|
1085
1131
|
return global.kuzzle.internalIndex
|
|
1086
|
-
.search(
|
|
1087
|
-
.then(result => {
|
|
1132
|
+
.search("validations", {}, { from: 0, size: 1000 })
|
|
1133
|
+
.then((result) => {
|
|
1088
1134
|
let validation = {};
|
|
1089
1135
|
|
|
1090
|
-
if ( result
|
|
1091
|
-
&& Array.isArray(result.hits)
|
|
1092
|
-
&& result.hits.length > 0
|
|
1093
|
-
) {
|
|
1136
|
+
if (result && Array.isArray(result.hits) && result.hits.length > 0) {
|
|
1094
1137
|
for (const { _source, _id } of result.hits) {
|
|
1095
|
-
const collectionName = `${_id.split(
|
|
1138
|
+
const collectionName = `${_id.split("#")[0]}/${_id.split("#")[1]}`;
|
|
1096
1139
|
|
|
1097
|
-
if (!
|
|
1140
|
+
if (!get(_source, "index")) {
|
|
1098
1141
|
throw assertionError.get(
|
|
1099
|
-
|
|
1142
|
+
"incorrect_validation_format",
|
|
1100
1143
|
collectionName,
|
|
1101
|
-
|
|
1144
|
+
"index"
|
|
1145
|
+
);
|
|
1102
1146
|
}
|
|
1103
1147
|
|
|
1104
|
-
if (!
|
|
1148
|
+
if (!get(_source, "collection")) {
|
|
1105
1149
|
throw assertionError.get(
|
|
1106
|
-
|
|
1150
|
+
"incorrect_validation_format",
|
|
1107
1151
|
collectionName,
|
|
1108
|
-
|
|
1152
|
+
"collection"
|
|
1153
|
+
);
|
|
1109
1154
|
}
|
|
1110
1155
|
|
|
1111
|
-
if (!
|
|
1156
|
+
if (!get(_source, "validation")) {
|
|
1112
1157
|
throw assertionError.get(
|
|
1113
|
-
|
|
1158
|
+
"incorrect_validation_format",
|
|
1114
1159
|
collectionName,
|
|
1115
|
-
|
|
1160
|
+
"validation"
|
|
1161
|
+
);
|
|
1116
1162
|
}
|
|
1117
1163
|
|
|
1118
|
-
if (!
|
|
1164
|
+
if (!has(validation, _source.index)) {
|
|
1119
1165
|
validation[_source.index] = {};
|
|
1120
1166
|
}
|
|
1121
1167
|
|
|
1122
|
-
validation[_source.index][_source.collection] =
|
|
1123
|
-
_source.validation;
|
|
1168
|
+
validation[_source.index][_source.collection] = _source.validation;
|
|
1124
1169
|
}
|
|
1125
|
-
}
|
|
1126
|
-
else if (global.kuzzle.config.validation) {
|
|
1170
|
+
} else if (global.kuzzle.config.validation) {
|
|
1127
1171
|
// We can't wait prepareDb as it runs outside of the rest of the start
|
|
1128
1172
|
validation = global.kuzzle.config.validation;
|
|
1129
1173
|
}
|