kuzzle-device-manager 3.0.0-3-dev.20 → 3.0.0-3-dev.21
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/dist/lib/modules/asset/AssetService.d.ts +6 -0
- package/dist/lib/modules/asset/AssetService.js +46 -46
- package/dist/lib/modules/asset/AssetService.js.map +1 -1
- package/dist/lib/modules/asset/roles/RoleAssetsAdmin.d.ts +1 -0
- package/dist/lib/modules/asset/roles/RoleAssetsAdmin.js +2 -0
- package/dist/lib/modules/asset/roles/RoleAssetsAdmin.js.map +1 -1
- package/dist/lib/modules/asset/roles/RoleAssetsReader.d.ts +1 -0
- package/dist/lib/modules/asset/roles/RoleAssetsReader.js +2 -0
- package/dist/lib/modules/asset/roles/RoleAssetsReader.js.map +1 -1
- package/dist/lib/modules/device/DeviceService.js +23 -23
- package/dist/lib/modules/device/DeviceService.js.map +1 -1
- package/dist/lib/modules/device/roles/RoleDevicesAdmin.d.ts +1 -0
- package/dist/lib/modules/device/roles/RoleDevicesAdmin.js +2 -0
- package/dist/lib/modules/device/roles/RoleDevicesAdmin.js.map +1 -1
- package/dist/lib/modules/device/roles/RoleDevicesReader.d.ts +1 -0
- package/dist/lib/modules/device/roles/RoleDevicesReader.js +2 -0
- package/dist/lib/modules/device/roles/RoleDevicesReader.js.map +1 -1
- package/dist/lib/modules/group/GroupsService.d.ts +5 -0
- package/dist/lib/modules/group/GroupsService.js +39 -0
- package/dist/lib/modules/group/GroupsService.js.map +1 -1
- package/dist/lib/modules/group/index.d.ts +1 -0
- package/dist/lib/modules/group/index.js +1 -0
- package/dist/lib/modules/group/index.js.map +1 -1
- package/dist/lib/modules/group/roles/RoleGroupsAdmin.d.ts +1 -0
- package/dist/lib/modules/group/roles/RoleGroupsAdmin.js +2 -0
- package/dist/lib/modules/group/roles/RoleGroupsAdmin.js.map +1 -1
- package/dist/lib/modules/group/roles/RoleGroupsReader.d.ts +1 -0
- package/dist/lib/modules/group/roles/RoleGroupsReader.js +2 -0
- package/dist/lib/modules/group/roles/RoleGroupsReader.js.map +1 -1
- package/dist/lib/modules/group/types/GroupEvents.d.ts +8 -0
- package/dist/lib/modules/group/types/GroupEvents.js +3 -0
- package/dist/lib/modules/group/types/GroupEvents.js.map +1 -0
- package/dist/lib/modules/model/MetadataReferential.d.ts +119 -0
- package/dist/lib/modules/model/MetadataReferential.js +342 -0
- package/dist/lib/modules/model/MetadataReferential.js.map +1 -0
- package/dist/lib/modules/model/ModelService.d.ts +103 -1
- package/dist/lib/modules/model/ModelService.js +486 -185
- package/dist/lib/modules/model/ModelService.js.map +1 -1
- package/dist/lib/modules/model/ModelsConflicts.d.ts +23 -0
- package/dist/lib/modules/model/ModelsConflicts.js +54 -4
- package/dist/lib/modules/model/ModelsConflicts.js.map +1 -1
- package/dist/lib/modules/model/ModelsController.d.ts +11 -2
- package/dist/lib/modules/model/ModelsController.js +109 -11
- package/dist/lib/modules/model/ModelsController.js.map +1 -1
- package/dist/lib/modules/model/ModelsRegister.d.ts +33 -1
- package/dist/lib/modules/model/ModelsRegister.js +101 -3
- package/dist/lib/modules/model/ModelsRegister.js.map +1 -1
- package/dist/lib/modules/model/collections/modelsMappings.js +7 -0
- package/dist/lib/modules/model/collections/modelsMappings.js.map +1 -1
- package/dist/lib/modules/model/types/ModelApi.d.ts +93 -2
- package/dist/lib/modules/model/types/ModelContent.d.ts +67 -1
- package/dist/lib/modules/model/types/ModelContent.js.map +1 -1
- package/dist/lib/modules/model/types/ModelDefinition.d.ts +6 -3
- package/dist/lib/modules/model/types/ModelEvents.d.ts +6 -1
- package/dist/lib/modules/plugin/DeviceManagerEngine.d.ts +33 -0
- package/dist/lib/modules/plugin/DeviceManagerEngine.js +106 -10
- package/dist/lib/modules/plugin/DeviceManagerEngine.js.map +1 -1
- package/dist/lib/modules/plugin/DeviceManagerPlugin.d.ts +36 -1
- package/dist/lib/modules/plugin/DeviceManagerPlugin.js +42 -0
- package/dist/lib/modules/plugin/DeviceManagerPlugin.js.map +1 -1
- package/dist/lib/modules/plugin/types/DeviceManagerConfiguration.d.ts +11 -0
- package/dist/lib/modules/shared/utils/lock.d.ts +7 -1
- package/dist/lib/modules/shared/utils/lock.js +2 -2
- package/dist/lib/modules/shared/utils/lock.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.ModelService = void 0;
|
|
4
7
|
const kuzzle_1 = require("kuzzle");
|
|
@@ -11,6 +14,8 @@ const AJValidator_1 = require("../shared/utils/AJValidator");
|
|
|
11
14
|
const SchemaValidationError_1 = require("../shared/errors/SchemaValidationError");
|
|
12
15
|
const MeasuresDuplicates_1 = require("./MeasuresDuplicates");
|
|
13
16
|
const MeasuresNamesDuplicatesError_1 = require("./MeasuresNamesDuplicatesError");
|
|
17
|
+
const lodash_1 = __importDefault(require("lodash"));
|
|
18
|
+
const MetadataReferential_1 = require("./MetadataReferential");
|
|
14
19
|
class ModelService extends shared_1.BaseService {
|
|
15
20
|
constructor(plugin, logger) {
|
|
16
21
|
super(plugin);
|
|
@@ -30,6 +35,7 @@ class ModelService extends shared_1.BaseService {
|
|
|
30
35
|
const groupModel = await this.getGroup(model);
|
|
31
36
|
return groupModel._source;
|
|
32
37
|
});
|
|
38
|
+
(0, kuzzle_plugin_commons_1.onAsk)("ask:device-manager:model:metadata-referential:get", async () => this.getMetadataReferential());
|
|
33
39
|
(0, kuzzle_plugin_commons_1.onAsk)("ask:device-manager:model:measure:get", async ({ type, index }) => {
|
|
34
40
|
const measureModel = await this.getMeasure(type, index);
|
|
35
41
|
return measureModel._source;
|
|
@@ -156,157 +162,177 @@ class ModelService extends shared_1.BaseService {
|
|
|
156
162
|
return { models, strict, type };
|
|
157
163
|
}
|
|
158
164
|
async writeAsset(tenantClasses, model, metadataMappings, defaultMetadata, metadataDetails, metadataGroups, measures, tooltipModels, locales, indexes, icon) {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
if (indexes?.length && tenantClasses?.length) {
|
|
163
|
-
throw new kuzzle_1.BadRequestError(`"indexes" and "tenantClasses" are mutually exclusive on an asset model.`);
|
|
164
|
-
}
|
|
165
|
-
const duplicates = (0, MeasuresDuplicates_1.getNamedMeasuresDuplicates)(measures);
|
|
166
|
-
if (duplicates.length > 0) {
|
|
167
|
-
throw new MeasuresNamesDuplicatesError_1.MeasuresNamesDuplicatesError("Asset model measures contain one or multiple duplicate measure name", duplicates);
|
|
168
|
-
}
|
|
169
|
-
const normalizedTenantClasses = tenantClasses.includes("commons")
|
|
170
|
-
? ["commons"]
|
|
171
|
-
: tenantClasses;
|
|
172
|
-
// Anti-shadowing: reject if a model with the same name exists at a different scope level
|
|
173
|
-
const isGlobal = normalizedTenantClasses.includes("commons") &&
|
|
174
|
-
(!indexes || indexes.length === 0);
|
|
175
|
-
const isTenantScoped = indexes && indexes.length > 0;
|
|
176
|
-
const isGroupScoped = !isGlobal && !isTenantScoped;
|
|
177
|
-
await this.sdk.collection.refresh(this.config.platformIndex, plugin_1.InternalCollection.MODELS);
|
|
178
|
-
const existing = await this.sdk.document.search(this.config.platformIndex, plugin_1.InternalCollection.MODELS, {
|
|
179
|
-
query: {
|
|
180
|
-
bool: {
|
|
181
|
-
must: [
|
|
182
|
-
{ term: { type: "asset" } },
|
|
183
|
-
{ term: { "asset.model": model } },
|
|
184
|
-
],
|
|
185
|
-
},
|
|
186
|
-
},
|
|
187
|
-
}, { size: 10 });
|
|
188
|
-
for (const hit of existing.hits) {
|
|
189
|
-
const doc = hit._source;
|
|
190
|
-
const docIsGlobal = doc.tenantClasses?.includes("commons") &&
|
|
191
|
-
(!doc.indexes || doc.indexes.length === 0);
|
|
192
|
-
const docIsTenantScoped = doc.indexes && doc.indexes.length > 0;
|
|
193
|
-
const docIsGroupScoped = !docIsGlobal && !docIsTenantScoped;
|
|
194
|
-
// Same scope level: allow overwrite
|
|
195
|
-
if (isGlobal && docIsGlobal) {
|
|
196
|
-
continue;
|
|
197
|
-
}
|
|
198
|
-
if (isTenantScoped && docIsTenantScoped) {
|
|
199
|
-
continue;
|
|
200
|
-
}
|
|
201
|
-
if (isGroupScoped && docIsGroupScoped) {
|
|
202
|
-
continue;
|
|
165
|
+
return (0, MetadataReferential_1.withMetadataReferentialLock)(async () => {
|
|
166
|
+
if (kuzzle_1.Inflector.pascalCase(model) !== model) {
|
|
167
|
+
throw new kuzzle_1.BadRequestError(`Asset model "${model}" must be PascalCase.`);
|
|
203
168
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
throw new kuzzle_1.BadRequestError(`Asset model "${model}" already exists as a global (commons) model. A model cannot exist at multiple scopes.`);
|
|
169
|
+
if (indexes?.length && tenantClasses?.length) {
|
|
170
|
+
throw new kuzzle_1.BadRequestError(`"indexes" and "tenantClasses" are mutually exclusive on an asset model.`);
|
|
207
171
|
}
|
|
208
|
-
|
|
209
|
-
|
|
172
|
+
const duplicates = (0, MeasuresDuplicates_1.getNamedMeasuresDuplicates)(measures);
|
|
173
|
+
if (duplicates.length > 0) {
|
|
174
|
+
throw new MeasuresNamesDuplicatesError_1.MeasuresNamesDuplicatesError("Asset model measures contain one or multiple duplicate measure name", duplicates);
|
|
210
175
|
}
|
|
211
|
-
|
|
212
|
-
|
|
176
|
+
const normalizedTenantClasses = tenantClasses.includes("commons")
|
|
177
|
+
? ["commons"]
|
|
178
|
+
: tenantClasses;
|
|
179
|
+
// Anti-shadowing: reject if a model with the same name exists at a different scope level
|
|
180
|
+
const isGlobal = normalizedTenantClasses.includes("commons") &&
|
|
181
|
+
(!indexes || indexes.length === 0);
|
|
182
|
+
const isTenantScoped = indexes && indexes.length > 0;
|
|
183
|
+
const isGroupScoped = !isGlobal && !isTenantScoped;
|
|
184
|
+
await this.sdk.collection.refresh(this.config.platformIndex, plugin_1.InternalCollection.MODELS);
|
|
185
|
+
const existing = await this.sdk.document.search(this.config.platformIndex, plugin_1.InternalCollection.MODELS, {
|
|
186
|
+
query: {
|
|
187
|
+
bool: {
|
|
188
|
+
must: [
|
|
189
|
+
{ term: { type: "asset" } },
|
|
190
|
+
{ term: { "asset.model": model } },
|
|
191
|
+
],
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
}, { size: 10 });
|
|
195
|
+
for (const hit of existing.hits) {
|
|
196
|
+
const doc = hit._source;
|
|
197
|
+
const docIsGlobal = doc.tenantClasses?.includes("commons") &&
|
|
198
|
+
(!doc.indexes || doc.indexes.length === 0);
|
|
199
|
+
const docIsTenantScoped = doc.indexes && doc.indexes.length > 0;
|
|
200
|
+
const docIsGroupScoped = !docIsGlobal && !docIsTenantScoped;
|
|
201
|
+
// Same scope level: allow overwrite
|
|
202
|
+
if (isGlobal && docIsGlobal) {
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
if (isTenantScoped && docIsTenantScoped) {
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
if (isGroupScoped && docIsGroupScoped) {
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
// Different scope levels: reject
|
|
212
|
+
if (docIsGlobal) {
|
|
213
|
+
throw new kuzzle_1.BadRequestError(`Asset model "${model}" already exists as a global (commons) model. A model cannot exist at multiple scopes.`);
|
|
214
|
+
}
|
|
215
|
+
if (isGlobal) {
|
|
216
|
+
throw new kuzzle_1.BadRequestError(`Asset model "${model}" already exists at a non-global scope. A model cannot exist at multiple scopes.`);
|
|
217
|
+
}
|
|
218
|
+
if (isTenantScoped && docIsGroupScoped) {
|
|
219
|
+
throw new kuzzle_1.BadRequestError(`Asset model "${model}" already exists at group scope. A model cannot be both group-scoped and tenant-scoped.`);
|
|
220
|
+
}
|
|
221
|
+
if (isGroupScoped && docIsTenantScoped) {
|
|
222
|
+
throw new kuzzle_1.BadRequestError(`Asset model "${model}" already exists at tenant scope. A model cannot be both group-scoped and tenant-scoped.`);
|
|
223
|
+
}
|
|
213
224
|
}
|
|
214
|
-
|
|
215
|
-
|
|
225
|
+
const { fields: metadata, resolvedMappings } = await this.resolveMetadata("asset", model, { defaultMetadata, metadataDetails, metadataMappings });
|
|
226
|
+
const modelContent = {
|
|
227
|
+
asset: {
|
|
228
|
+
...metadata,
|
|
229
|
+
icon,
|
|
230
|
+
locales,
|
|
231
|
+
measures,
|
|
232
|
+
metadataGroups,
|
|
233
|
+
model,
|
|
234
|
+
tooltipModels,
|
|
235
|
+
},
|
|
236
|
+
...(indexes?.length
|
|
237
|
+
? { indexes }
|
|
238
|
+
: { tenantClasses: normalizedTenantClasses }),
|
|
239
|
+
type: "asset",
|
|
240
|
+
};
|
|
241
|
+
const modelId = ModelSerializer_1.ModelSerializer.id("asset", modelContent);
|
|
242
|
+
const stored = await this.getStoredModel(modelId);
|
|
243
|
+
this.checkReferentialOnly("asset", model, metadataMappings, stored);
|
|
244
|
+
this.checkDefaultValues(resolvedMappings, metadata.defaultMetadata);
|
|
245
|
+
const conflicts = await (0, kuzzle_plugin_commons_1.ask)("ask:device-manager:engine:doesUpdateConflict", { twin: { models: [modelContent], type: "asset" } });
|
|
246
|
+
if (conflicts.length > 0) {
|
|
247
|
+
throw new MappingsConflictsError_1.MappingsConflictsError(`New assets mappings are causing conflicts`, conflicts);
|
|
216
248
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
metadataDetails,
|
|
225
|
-
metadataGroups,
|
|
226
|
-
metadataMappings,
|
|
227
|
-
model,
|
|
228
|
-
tooltipModels,
|
|
229
|
-
},
|
|
230
|
-
...(indexes?.length
|
|
231
|
-
? { indexes }
|
|
232
|
-
: { tenantClasses: normalizedTenantClasses }),
|
|
233
|
-
type: "asset",
|
|
234
|
-
};
|
|
235
|
-
this.checkDefaultValues(metadataMappings, defaultMetadata);
|
|
236
|
-
const conflicts = await (0, kuzzle_plugin_commons_1.ask)("ask:device-manager:engine:doesUpdateConflict", { twin: { models: [modelContent], type: "asset" } });
|
|
237
|
-
if (conflicts.length > 0) {
|
|
238
|
-
throw new MappingsConflictsError_1.MappingsConflictsError(`New assets mappings are causing conflicts`, conflicts);
|
|
239
|
-
}
|
|
240
|
-
const assetModel = await this.sdk.document.createOrReplace(this.config.platformIndex, plugin_1.InternalCollection.MODELS, ModelSerializer_1.ModelSerializer.id("asset", modelContent), modelContent);
|
|
241
|
-
await this.sdk.collection.refresh(this.config.platformIndex, plugin_1.InternalCollection.MODELS);
|
|
242
|
-
await (0, kuzzle_plugin_commons_1.ask)("ask:device-manager:engine:updateAll");
|
|
243
|
-
await (0, kuzzle_plugin_commons_1.ask)("ask:device-manager:asset:refresh-model", {
|
|
244
|
-
assetModel: assetModel._source,
|
|
249
|
+
const assetModel = await this.sdk.document.createOrReplace(this.config.platformIndex, plugin_1.InternalCollection.MODELS, ModelSerializer_1.ModelSerializer.id("asset", modelContent), modelContent);
|
|
250
|
+
await this.sdk.collection.refresh(this.config.platformIndex, plugin_1.InternalCollection.MODELS);
|
|
251
|
+
await this.updateEnginesOrRestore(modelId, stored);
|
|
252
|
+
await (0, kuzzle_plugin_commons_1.ask)("ask:device-manager:asset:refresh-model", {
|
|
253
|
+
assetModel: assetModel._source,
|
|
254
|
+
});
|
|
255
|
+
return assetModel;
|
|
245
256
|
});
|
|
246
|
-
return assetModel;
|
|
247
257
|
}
|
|
248
258
|
async writeDevice(model, metadataMappings, defaultMetadata, metadataDetails, metadataGroups, measures, icon) {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
259
|
+
return (0, MetadataReferential_1.withMetadataReferentialLock)(async () => {
|
|
260
|
+
if (kuzzle_1.Inflector.pascalCase(model) !== model) {
|
|
261
|
+
throw new kuzzle_1.BadRequestError(`Device model "${model}" must be PascalCase.`);
|
|
262
|
+
}
|
|
263
|
+
const duplicates = (0, MeasuresDuplicates_1.getNamedMeasuresDuplicates)(measures);
|
|
264
|
+
if (duplicates.length > 0) {
|
|
265
|
+
throw new MeasuresNamesDuplicatesError_1.MeasuresNamesDuplicatesError("Device model measures contain one or multiple duplicate measure name", duplicates);
|
|
266
|
+
}
|
|
267
|
+
const { fields: metadata } = await this.resolveMetadata("device", model, {
|
|
258
268
|
defaultMetadata,
|
|
259
|
-
icon,
|
|
260
|
-
measures,
|
|
261
269
|
metadataDetails,
|
|
262
|
-
metadataGroups,
|
|
263
270
|
metadataMappings,
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
271
|
+
});
|
|
272
|
+
const modelContent = {
|
|
273
|
+
device: {
|
|
274
|
+
...metadata,
|
|
275
|
+
icon,
|
|
276
|
+
measures,
|
|
277
|
+
metadataGroups,
|
|
278
|
+
model,
|
|
279
|
+
},
|
|
280
|
+
type: "device",
|
|
281
|
+
};
|
|
282
|
+
const modelId = ModelSerializer_1.ModelSerializer.id("device", modelContent);
|
|
283
|
+
const stored = await this.getStoredModel(modelId);
|
|
284
|
+
this.checkReferentialOnly("device", model, metadataMappings, stored);
|
|
285
|
+
const conflicts = await (0, kuzzle_plugin_commons_1.ask)("ask:device-manager:engine:doesUpdateConflict", { twin: { models: [modelContent], type: "device" } });
|
|
286
|
+
if (conflicts.length > 0) {
|
|
287
|
+
throw new MappingsConflictsError_1.MappingsConflictsError(`New devices mappings are causing conflicts`, conflicts);
|
|
288
|
+
}
|
|
289
|
+
const deviceModel = await this.sdk.document.createOrReplace(this.config.platformIndex, plugin_1.InternalCollection.MODELS, ModelSerializer_1.ModelSerializer.id("device", modelContent), modelContent);
|
|
290
|
+
await this.sdk.collection.refresh(this.config.platformIndex, plugin_1.InternalCollection.MODELS);
|
|
291
|
+
await this.updateEnginesOrRestore(modelId, stored);
|
|
292
|
+
await (0, kuzzle_plugin_commons_1.ask)("ask:device-manager:device:refresh-model", {
|
|
293
|
+
deviceModel: modelContent,
|
|
294
|
+
});
|
|
295
|
+
return deviceModel;
|
|
277
296
|
});
|
|
278
|
-
return deviceModel;
|
|
279
297
|
}
|
|
280
298
|
async writeGroup(tenantClasses, model, affinity, metadataMappings, defaultMetadata, metadataDetails, metadataGroups, icon, locales) {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
tenantClasses
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
group: {
|
|
291
|
-
affinity: groupAffinity,
|
|
299
|
+
return (0, MetadataReferential_1.withMetadataReferentialLock)(async () => {
|
|
300
|
+
if (kuzzle_1.Inflector.pascalCase(model) !== model) {
|
|
301
|
+
throw new kuzzle_1.BadRequestError(`Group model "${model}" must be PascalCase.`);
|
|
302
|
+
}
|
|
303
|
+
if (tenantClasses.includes("commons")) {
|
|
304
|
+
tenantClasses = ["commons"];
|
|
305
|
+
}
|
|
306
|
+
const groupAffinity = this.checkGroupAffinity(affinity);
|
|
307
|
+
const { fields: metadata } = await this.resolveMetadata("group", model, {
|
|
292
308
|
defaultMetadata,
|
|
293
|
-
icon,
|
|
294
|
-
locales,
|
|
295
309
|
metadataDetails,
|
|
296
|
-
metadataGroups,
|
|
297
310
|
metadataMappings,
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
311
|
+
});
|
|
312
|
+
const modelContent = {
|
|
313
|
+
tenantClasses,
|
|
314
|
+
group: {
|
|
315
|
+
...metadata,
|
|
316
|
+
affinity: groupAffinity,
|
|
317
|
+
icon,
|
|
318
|
+
locales,
|
|
319
|
+
metadataGroups,
|
|
320
|
+
model,
|
|
321
|
+
},
|
|
322
|
+
type: "group",
|
|
323
|
+
};
|
|
324
|
+
const modelId = ModelSerializer_1.ModelSerializer.id("group", modelContent);
|
|
325
|
+
const stored = await this.getStoredModel(modelId);
|
|
326
|
+
this.checkReferentialOnly("group", model, metadataMappings, stored);
|
|
327
|
+
const conflicts = await (0, kuzzle_plugin_commons_1.ask)("ask:device-manager:engine:doesUpdateConflict", { groupModels: [modelContent] });
|
|
328
|
+
if (conflicts.length > 0) {
|
|
329
|
+
throw new MappingsConflictsError_1.MappingsConflictsError(`New group mappings are causing conflicts`, conflicts);
|
|
330
|
+
}
|
|
331
|
+
const groupModel = await this.sdk.document.createOrReplace(this.config.platformIndex, plugin_1.InternalCollection.MODELS, ModelSerializer_1.ModelSerializer.id("group", modelContent), modelContent);
|
|
332
|
+
await this.sdk.collection.refresh(this.config.platformIndex, plugin_1.InternalCollection.MODELS);
|
|
333
|
+
await this.updateEnginesOrRestore(modelId, stored);
|
|
334
|
+
return groupModel;
|
|
335
|
+
});
|
|
310
336
|
}
|
|
311
337
|
async writeMeasure(type, valuesMappings, validationSchema, valuesDetails, locales, indexes, icon) {
|
|
312
338
|
const modelContent = {
|
|
@@ -337,9 +363,11 @@ class ModelService extends shared_1.BaseService {
|
|
|
337
363
|
if (conflicts.length > 0) {
|
|
338
364
|
throw new MappingsConflictsError_1.MappingsConflictsError(`New assets mappings are causing conflicts`, conflicts);
|
|
339
365
|
}
|
|
340
|
-
const
|
|
366
|
+
const modelId = ModelSerializer_1.ModelSerializer.id("measure", modelContent);
|
|
367
|
+
const stored = await this.getStoredModel(modelId);
|
|
368
|
+
const measureModel = await this.sdk.document.createOrReplace(this.config.platformIndex, plugin_1.InternalCollection.MODELS, modelId, modelContent);
|
|
341
369
|
await this.sdk.collection.refresh(this.config.platformIndex, plugin_1.InternalCollection.MODELS);
|
|
342
|
-
await (
|
|
370
|
+
await this.updateEnginesOrRestore(modelId, stored);
|
|
343
371
|
return measureModel;
|
|
344
372
|
}
|
|
345
373
|
async deleteAsset(_id) {
|
|
@@ -737,60 +765,333 @@ class ModelService extends shared_1.BaseService {
|
|
|
737
765
|
* Update an asset model
|
|
738
766
|
*/
|
|
739
767
|
async updateAsset(tenantClasses, index, model, metadataMappings, defaultMetadata, metadataDetails, metadataGroups, measures, tooltipModels, locales, icon, request) {
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
768
|
+
return (0, MetadataReferential_1.withMetadataReferentialLock)(async () => {
|
|
769
|
+
if (kuzzle_1.Inflector.pascalCase(model) !== model) {
|
|
770
|
+
throw new kuzzle_1.BadRequestError(`Asset model "${model}" must be PascalCase.`);
|
|
771
|
+
}
|
|
772
|
+
const existingAsset = await this.getAsset(tenantClasses, index, model);
|
|
773
|
+
this.checkReferentialOnly("asset", model, metadataMappings, existingAsset._source);
|
|
774
|
+
const { fields: metadata, resolvedMappings } = await this.resolveMetadata("asset", model, { defaultMetadata, metadataDetails, metadataMappings });
|
|
775
|
+
this.checkDefaultValues(resolvedMappings, metadata.defaultMetadata);
|
|
776
|
+
const measuresUpdated = measures.length === 0 ? existingAsset._source.asset.measures : measures;
|
|
777
|
+
// Preserve the existing scope: scope (tenantClasses / indexes) is decided
|
|
778
|
+
// at write time and must not be silently rewritten by an update payload.
|
|
779
|
+
// This also enforces tenantClasses / indexes mutual exclusivity (KZLPRD-1192).
|
|
780
|
+
const assetModelContent = {
|
|
781
|
+
asset: {
|
|
782
|
+
...metadata,
|
|
783
|
+
icon: icon ?? existingAsset._source.asset.icon,
|
|
784
|
+
locales,
|
|
785
|
+
measures: measuresUpdated,
|
|
786
|
+
metadataGroups,
|
|
787
|
+
model,
|
|
788
|
+
tooltipModels,
|
|
789
|
+
},
|
|
790
|
+
tenantClasses: existingAsset._source.tenantClasses,
|
|
791
|
+
indexes: existingAsset._source.indexes,
|
|
792
|
+
type: "asset",
|
|
793
|
+
};
|
|
794
|
+
const assetModel = {
|
|
795
|
+
_id: existingAsset._id,
|
|
796
|
+
_source: assetModelContent,
|
|
797
|
+
};
|
|
798
|
+
const conflicts = await (0, kuzzle_plugin_commons_1.ask)("ask:device-manager:engine:doesUpdateConflict", { twin: { models: [assetModelContent], type: "asset" } });
|
|
799
|
+
if (conflicts.length > 0) {
|
|
800
|
+
throw new MappingsConflictsError_1.MappingsConflictsError(`Assets mappings are causing conflicts`, conflicts);
|
|
801
|
+
}
|
|
802
|
+
// The field must be deleted if an element of the table is to be deleted.
|
|
803
|
+
// ? Only after the conflicts check, so a rejected update leaves the model untouched
|
|
804
|
+
await this.sdk.document.deleteFields(this.config.platformIndex, plugin_1.InternalCollection.MODELS, existingAsset._id, [
|
|
805
|
+
"asset.tooltipModels",
|
|
806
|
+
"asset.metadataMappings",
|
|
807
|
+
"asset.defaultMetadata",
|
|
808
|
+
"asset.metadataDetails",
|
|
809
|
+
"asset.metadataGroups",
|
|
810
|
+
], { source: true });
|
|
811
|
+
const endDocument = await this.updateDocument(request, assetModel, {
|
|
812
|
+
collection: plugin_1.InternalCollection.MODELS,
|
|
813
|
+
index: this.config.platformIndex,
|
|
814
|
+
}, { source: true });
|
|
815
|
+
// ? Only update indexes and refresh asset models when necessary
|
|
816
|
+
if (Object.keys(metadata.metadataMappings).length > 0 ||
|
|
817
|
+
measures.length > 0) {
|
|
818
|
+
await this.sdk.collection.refresh(this.config.platformIndex, plugin_1.InternalCollection.MODELS);
|
|
819
|
+
await this.updateEnginesOrRestore(existingAsset._id, existingAsset._source);
|
|
820
|
+
await (0, kuzzle_plugin_commons_1.ask)("ask:device-manager:asset:refresh-model", {
|
|
821
|
+
assetModel: endDocument._source,
|
|
822
|
+
});
|
|
823
|
+
}
|
|
824
|
+
return endDocument;
|
|
825
|
+
});
|
|
826
|
+
}
|
|
827
|
+
/**
|
|
828
|
+
* Adds metadata of the metadata referential to a device model.
|
|
829
|
+
*
|
|
830
|
+
* Device models are additive only from the API: every existing metadata must be kept unchanged,
|
|
831
|
+
* new metadata must come from the referential. Metadata details and default values can change.
|
|
832
|
+
* The engines mappings are updated and the devices get the new metadata with their default value.
|
|
833
|
+
*
|
|
834
|
+
* @throws BadRequestError if an existing metadata is missing or changed, or a new one is inline
|
|
835
|
+
* @throws MappingsConflictsError if the new metadata conflict with the existing mappings
|
|
836
|
+
*/
|
|
837
|
+
async updateDevice(model, { defaultMetadata, metadataDetails, metadataMappings }) {
|
|
838
|
+
return (0, MetadataReferential_1.withMetadataReferentialLock)(async () => {
|
|
839
|
+
const existingDevice = await this.getDevice(model);
|
|
840
|
+
const existing = existingDevice._source.device;
|
|
841
|
+
const existingMappings = existing.metadataMappings ?? {};
|
|
842
|
+
const removed = Object.keys(existingMappings).filter((name) => !lodash_1.default.isEqual(existingMappings[name], metadataMappings[name]));
|
|
843
|
+
if (removed.length > 0) {
|
|
844
|
+
throw new kuzzle_1.BadRequestError(`Device model "${model}" metadata cannot be removed or modified: ${removed.join(", ")}`);
|
|
845
|
+
}
|
|
846
|
+
const inline = Object.keys(metadataMappings).filter((name) => !(name in existingMappings) &&
|
|
847
|
+
!(0, MetadataReferential_1.isReferentialMapping)(metadataMappings[name]));
|
|
848
|
+
if (inline.length > 0) {
|
|
849
|
+
throw new kuzzle_1.BadRequestError(`New metadata of device model "${model}" must come from the metadata referential, inline metadata: ${inline.join(", ")}`);
|
|
850
|
+
}
|
|
851
|
+
const { fields: metadata } = await this.resolveMetadata("device", model, {
|
|
852
|
+
defaultMetadata: defaultMetadata ?? existing.defaultMetadata,
|
|
853
|
+
metadataDetails: metadataDetails ?? existing.metadataDetails,
|
|
765
854
|
metadataMappings,
|
|
766
|
-
|
|
767
|
-
|
|
855
|
+
});
|
|
856
|
+
const deviceModelContent = {
|
|
857
|
+
...existingDevice._source,
|
|
858
|
+
device: { ...existing, ...metadata },
|
|
859
|
+
};
|
|
860
|
+
const conflicts = await (0, kuzzle_plugin_commons_1.ask)("ask:device-manager:engine:doesUpdateConflict", { twin: { models: [deviceModelContent], type: "device" } });
|
|
861
|
+
if (conflicts.length > 0) {
|
|
862
|
+
throw new MappingsConflictsError_1.MappingsConflictsError(`Devices mappings are causing conflicts`, conflicts);
|
|
863
|
+
}
|
|
864
|
+
const deviceModel = await this.sdk.document.createOrReplace(this.config.platformIndex, plugin_1.InternalCollection.MODELS, existingDevice._id, deviceModelContent);
|
|
865
|
+
await this.sdk.collection.refresh(this.config.platformIndex, plugin_1.InternalCollection.MODELS);
|
|
866
|
+
await this.updateEnginesOrRestore(existingDevice._id, existingDevice._source);
|
|
867
|
+
await (0, kuzzle_plugin_commons_1.ask)("ask:device-manager:device:refresh-model", { deviceModel: deviceModel._source });
|
|
868
|
+
return deviceModel;
|
|
869
|
+
});
|
|
870
|
+
}
|
|
871
|
+
/**
|
|
872
|
+
* Returns the group model available for the given tenant classes:
|
|
873
|
+
* a model of these classes first, then a commons model.
|
|
874
|
+
*
|
|
875
|
+
* @throws NotFoundError if no group model with this name is available
|
|
876
|
+
*/
|
|
877
|
+
async getScopedGroup(tenantClasses, model) {
|
|
878
|
+
const result = await this.sdk.document.search(this.config.platformIndex, plugin_1.InternalCollection.MODELS, {
|
|
879
|
+
query: {
|
|
880
|
+
and: [
|
|
881
|
+
{ equals: { type: "group" } },
|
|
882
|
+
{ equals: { "group.model": model } },
|
|
883
|
+
],
|
|
768
884
|
},
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
};
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
885
|
+
}, { lang: "koncorde", size: 100 });
|
|
886
|
+
const scoped = result.hits.find(({ _source }) => _source.tenantClasses.some((tenantClass) => tenantClass !== "commons" && tenantClasses.includes(tenantClass)));
|
|
887
|
+
const common = result.hits.find(({ _source }) => _source.tenantClasses.includes("commons"));
|
|
888
|
+
const groupModel = scoped ?? common;
|
|
889
|
+
if (!groupModel) {
|
|
890
|
+
throw new kuzzle_1.NotFoundError(`Unknown Group model "${model}" for tenant classes "${tenantClasses.join(", ")}".`);
|
|
891
|
+
}
|
|
892
|
+
return { _id: groupModel._id, _source: groupModel._source };
|
|
893
|
+
}
|
|
894
|
+
/**
|
|
895
|
+
* Updates a group model, keeping its scope.
|
|
896
|
+
* Affinity and icon are kept when omitted.
|
|
897
|
+
*
|
|
898
|
+
* The engines mappings are updated and the groups of the model are refreshed.
|
|
899
|
+
*
|
|
900
|
+
* @throws MappingsConflictsError if the new mappings conflict with the existing ones
|
|
901
|
+
*/
|
|
902
|
+
async updateGroup(tenantClasses, model, { affinity, defaultMetadata, icon, locales, metadataDetails, metadataGroups, metadataMappings, }) {
|
|
903
|
+
return (0, MetadataReferential_1.withMetadataReferentialLock)(async () => {
|
|
904
|
+
if (kuzzle_1.Inflector.pascalCase(model) !== model) {
|
|
905
|
+
throw new kuzzle_1.BadRequestError(`Group model "${model}" must be PascalCase.`);
|
|
906
|
+
}
|
|
907
|
+
const existingGroup = await this.getScopedGroup(tenantClasses, model);
|
|
908
|
+
const existing = existingGroup._source.group;
|
|
909
|
+
this.checkReferentialOnly("group", model, metadataMappings, existingGroup._source);
|
|
910
|
+
const { fields: metadata, resolvedMappings } = await this.resolveMetadata("group", model, { defaultMetadata, metadataDetails, metadataMappings });
|
|
911
|
+
this.checkDefaultValues(resolvedMappings, metadata.defaultMetadata);
|
|
912
|
+
const groupModelContent = {
|
|
913
|
+
tenantClasses: existingGroup._source.tenantClasses,
|
|
914
|
+
group: {
|
|
915
|
+
...metadata,
|
|
916
|
+
affinity: affinity === undefined
|
|
917
|
+
? existing.affinity
|
|
918
|
+
: this.checkGroupAffinity(affinity),
|
|
919
|
+
icon: icon ?? existing.icon,
|
|
920
|
+
locales,
|
|
921
|
+
metadataGroups,
|
|
922
|
+
model,
|
|
923
|
+
},
|
|
924
|
+
type: "group",
|
|
925
|
+
};
|
|
926
|
+
const conflicts = await (0, kuzzle_plugin_commons_1.ask)("ask:device-manager:engine:doesUpdateConflict", { groupModels: [groupModelContent] });
|
|
927
|
+
if (conflicts.length > 0) {
|
|
928
|
+
throw new MappingsConflictsError_1.MappingsConflictsError(`Group mappings are causing conflicts`, conflicts);
|
|
929
|
+
}
|
|
930
|
+
const groupModel = await this.sdk.document.createOrReplace(this.config.platformIndex, plugin_1.InternalCollection.MODELS, existingGroup._id, groupModelContent);
|
|
787
931
|
await this.sdk.collection.refresh(this.config.platformIndex, plugin_1.InternalCollection.MODELS);
|
|
788
|
-
await (
|
|
789
|
-
await (0, kuzzle_plugin_commons_1.ask)("ask:device-manager:
|
|
790
|
-
|
|
932
|
+
await this.updateEnginesOrRestore(existingGroup._id, existingGroup._source);
|
|
933
|
+
await (0, kuzzle_plugin_commons_1.ask)("ask:device-manager:group:refresh-model", {
|
|
934
|
+
groupModel: groupModel._source,
|
|
791
935
|
});
|
|
936
|
+
return groupModel;
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
/**
|
|
940
|
+
* Validates the metadata of a model written through the API against the metadata referential
|
|
941
|
+
* and enriches the details and default values of the metadata coming from it
|
|
942
|
+
*/
|
|
943
|
+
async resolveMetadata(modelType, model, fields) {
|
|
944
|
+
const enrichment = (0, MetadataReferential_1.enrichModelMetadata)(await this.getMetadataReferential(), fields, {
|
|
945
|
+
createError: (message) => new kuzzle_1.BadRequestError(message),
|
|
946
|
+
model,
|
|
947
|
+
modelType,
|
|
948
|
+
});
|
|
949
|
+
for (const warning of enrichment.warnings) {
|
|
950
|
+
this.logger.warn(warning);
|
|
951
|
+
}
|
|
952
|
+
return enrichment;
|
|
953
|
+
}
|
|
954
|
+
/**
|
|
955
|
+
* Resolves the referential metadata of stored models, to be returned by the API
|
|
956
|
+
*/
|
|
957
|
+
async resolveModels(documents) {
|
|
958
|
+
const referential = await this.getMetadataReferential();
|
|
959
|
+
return documents.map((document) => ({
|
|
960
|
+
...document,
|
|
961
|
+
_source: (0, MetadataReferential_1.resolveModelMetadata)(referential, document._source),
|
|
962
|
+
}));
|
|
963
|
+
}
|
|
964
|
+
async getMetadataReferential() {
|
|
965
|
+
return (0, MetadataReferential_1.fetchMetadataReferential)(this.sdk, this.config.platformIndex);
|
|
966
|
+
}
|
|
967
|
+
/**
|
|
968
|
+
* Creates a metadata of the metadata referential, or updates its details.
|
|
969
|
+
*
|
|
970
|
+
* The mappings of a new metadata are merged into the assets, devices and groups collections
|
|
971
|
+
* of every engine. They cannot be modified afterwards: only the locales, editor hint,
|
|
972
|
+
* default value and icon of an existing metadata can change. These are copied into the models
|
|
973
|
+
* using the metadata when they are written, the existing models are not modified.
|
|
974
|
+
*
|
|
975
|
+
* @throws BadRequestError if the mappings of an existing metadata are modified
|
|
976
|
+
* @throws MappingsConflictsError if the new metadata conflicts with an inline metadata of a model
|
|
977
|
+
* or with the actual mappings of an engine collection
|
|
978
|
+
*/
|
|
979
|
+
async writeMetadata(name, definition) {
|
|
980
|
+
(0, MetadataReferential_1.checkMetadataReferentialEntry)(name, definition, (message) => new kuzzle_1.BadRequestError(message));
|
|
981
|
+
return (0, MetadataReferential_1.withMetadataReferentialLock)(async () => {
|
|
982
|
+
const stored = await this.getMetadataReferential();
|
|
983
|
+
const entry = {
|
|
984
|
+
locales: {},
|
|
985
|
+
...lodash_1.default.omit(definition, "managed"),
|
|
986
|
+
};
|
|
987
|
+
this.checkUnmanagedMetadata(stored, name);
|
|
988
|
+
if (stored[name]) {
|
|
989
|
+
if (!lodash_1.default.isEqual(stored[name].mappings, entry.mappings)) {
|
|
990
|
+
throw new kuzzle_1.BadRequestError(`The mappings of metadata "${name}" cannot be modified, they are already merged into the engines collections`);
|
|
991
|
+
}
|
|
992
|
+
const referential = { ...stored, [name]: entry };
|
|
993
|
+
await (0, MetadataReferential_1.saveMetadataReferential)(this.sdk, this.config.platformIndex, referential);
|
|
994
|
+
return referential;
|
|
995
|
+
}
|
|
996
|
+
const models = await (0, MetadataReferential_1.fetchMetadataModels)(this.sdk, this.config.platformIndex);
|
|
997
|
+
const modelsConflicts = (0, MetadataReferential_1.getEntryModelsConflicts)(name, entry, models.map(({ _source }) => _source));
|
|
998
|
+
if (modelsConflicts.length > 0) {
|
|
999
|
+
throw new MappingsConflictsError_1.MappingsConflictsError(`Metadata "${name}" conflicts with the metadata of models`, modelsConflicts);
|
|
1000
|
+
}
|
|
1001
|
+
const esConflicts = await (0, kuzzle_plugin_commons_1.ask)("ask:device-manager:engine:doesMetadataConflict", { metadataMappings: { [name]: entry.mappings } });
|
|
1002
|
+
if (esConflicts.length > 0) {
|
|
1003
|
+
throw new MappingsConflictsError_1.MappingsConflictsError(`Metadata "${name}" conflicts with the engines collections mappings`, esConflicts);
|
|
1004
|
+
}
|
|
1005
|
+
const referential = { ...stored, [name]: entry };
|
|
1006
|
+
await (0, MetadataReferential_1.saveMetadataReferential)(this.sdk, this.config.platformIndex, referential);
|
|
1007
|
+
try {
|
|
1008
|
+
await (0, kuzzle_plugin_commons_1.ask)("ask:device-manager:engine:updateAll");
|
|
1009
|
+
}
|
|
1010
|
+
catch (error) {
|
|
1011
|
+
// ? A metadata rejected by Elasticsearch would make every next engines update fail
|
|
1012
|
+
await (0, MetadataReferential_1.saveMetadataReferential)(this.sdk, this.config.platformIndex, stored);
|
|
1013
|
+
throw error;
|
|
1014
|
+
}
|
|
1015
|
+
return referential;
|
|
1016
|
+
});
|
|
1017
|
+
}
|
|
1018
|
+
/**
|
|
1019
|
+
* Deletes a metadata of the metadata referential.
|
|
1020
|
+
* Its mappings stay in the engines collections, Elasticsearch cannot remove them.
|
|
1021
|
+
*
|
|
1022
|
+
* @throws BadRequestError if a model still uses the metadata
|
|
1023
|
+
*/
|
|
1024
|
+
async deleteMetadata(name) {
|
|
1025
|
+
return (0, MetadataReferential_1.withMetadataReferentialLock)(async () => {
|
|
1026
|
+
const referential = await this.getMetadataReferential();
|
|
1027
|
+
if (!referential[name]) {
|
|
1028
|
+
throw new kuzzle_1.NotFoundError(`Unknown metadata "${name}" in the metadata referential`);
|
|
1029
|
+
}
|
|
1030
|
+
this.checkUnmanagedMetadata(referential, name);
|
|
1031
|
+
const referencingModels = await (0, MetadataReferential_1.fetchReferencingModels)(this.sdk, this.config.platformIndex, name);
|
|
1032
|
+
if (referencingModels.length > 0) {
|
|
1033
|
+
throw new kuzzle_1.BadRequestError(`Metadata "${name}" is still used by the models: ${referencingModels
|
|
1034
|
+
.map(({ _id }) => _id)
|
|
1035
|
+
.join(", ")}`);
|
|
1036
|
+
}
|
|
1037
|
+
const updatedReferential = lodash_1.default.omit(referential, name);
|
|
1038
|
+
await (0, MetadataReferential_1.saveMetadataReferential)(this.sdk, this.config.platformIndex, updatedReferential);
|
|
1039
|
+
return updatedReferential;
|
|
1040
|
+
});
|
|
1041
|
+
}
|
|
1042
|
+
/**
|
|
1043
|
+
* With the referentialOnly option, rejects the inline metadata a model write adds.
|
|
1044
|
+
* The inline metadata already defined by the stored model are kept (legacy).
|
|
1045
|
+
*
|
|
1046
|
+
* @throws BadRequestError if new inline metadata are added
|
|
1047
|
+
*/
|
|
1048
|
+
checkReferentialOnly(modelType, model, metadataMappings, stored) {
|
|
1049
|
+
if (!this.config.models?.metadata?.referentialOnly) {
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
1052
|
+
const added = (0, MetadataReferential_1.getAddedInlineMetadata)(metadataMappings, stored);
|
|
1053
|
+
if (added.length > 0) {
|
|
1054
|
+
throw new kuzzle_1.BadRequestError(`New metadata of ${modelType} model "${model}" must come from the metadata referential, inline metadata: ${added.join(", ")}`);
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
/**
|
|
1058
|
+
* Updates the engines collections. If Elasticsearch rejects the new mappings, the model is
|
|
1059
|
+
* restored to its previous version (or deleted if it is new), otherwise every next engines
|
|
1060
|
+
* update would fail on it.
|
|
1061
|
+
*/
|
|
1062
|
+
async updateEnginesOrRestore(_id, previous) {
|
|
1063
|
+
try {
|
|
1064
|
+
await (0, kuzzle_plugin_commons_1.ask)("ask:device-manager:engine:updateAll");
|
|
1065
|
+
}
|
|
1066
|
+
catch (error) {
|
|
1067
|
+
if (previous) {
|
|
1068
|
+
await this.sdk.document.createOrReplace(this.config.platformIndex, plugin_1.InternalCollection.MODELS, _id, lodash_1.default.omit(previous, "_kuzzle_info"), { refresh: "wait_for" });
|
|
1069
|
+
}
|
|
1070
|
+
else {
|
|
1071
|
+
await this.sdk.document.delete(this.config.platformIndex, plugin_1.InternalCollection.MODELS, _id, { refresh: "wait_for" });
|
|
1072
|
+
}
|
|
1073
|
+
throw error;
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
async getStoredModel(_id) {
|
|
1077
|
+
try {
|
|
1078
|
+
const { _source } = await this.sdk.document.get(this.config.platformIndex, plugin_1.InternalCollection.MODELS, _id);
|
|
1079
|
+
return _source;
|
|
1080
|
+
}
|
|
1081
|
+
catch (error) {
|
|
1082
|
+
if (error.status === 404) {
|
|
1083
|
+
return null;
|
|
1084
|
+
}
|
|
1085
|
+
throw error;
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
/**
|
|
1089
|
+
* @throws BadRequestError if the metadata is registered from code
|
|
1090
|
+
*/
|
|
1091
|
+
checkUnmanagedMetadata(referential, name) {
|
|
1092
|
+
if (referential[name]?.managed) {
|
|
1093
|
+
throw new kuzzle_1.BadRequestError(`Metadata "${name}" is registered from code, it cannot be modified or deleted through the API`);
|
|
792
1094
|
}
|
|
793
|
-
return endDocument;
|
|
794
1095
|
}
|
|
795
1096
|
}
|
|
796
1097
|
exports.ModelService = ModelService;
|