diff --git a/lib/modules/asset/AssetService.ts b/lib/modules/asset/AssetService.ts index ea2ec7bf..222915dd 100644 --- a/lib/modules/asset/AssetService.ts +++ b/lib/modules/asset/AssetService.ts @@ -1,4 +1,4 @@ -import { BadRequestError, User } from "kuzzle"; +import { BadRequestError, KuzzleRequest, User } from "kuzzle"; import { BaseRequest, DocumentSearchResult, @@ -30,6 +30,7 @@ import { lock, onAsk, BaseService, + SearchParams, } from "../shared"; import { AssetHistoryService } from "./AssetHistoryService"; @@ -69,41 +70,43 @@ export class AssetService extends BaseService { public async get( engineId: string, - assetId: string + assetId: string, + request: KuzzleRequest ): Promise> { - return this.sdk.document.get( + return this.getDocument(request, assetId, { + collection: InternalCollection.ASSETS, engineId, - InternalCollection.ASSETS, - assetId - ); + }); } /** * Updates an asset metadata */ public async update( - user: User, engineId: string, assetId: string, metadata: Metadata, - { refresh }: { refresh: any } + request: KuzzleRequest ): Promise> { return lock(`asset:${engineId}:${assetId}`, async () => { - const asset = await this.get(engineId, assetId); + const asset = await this.get(engineId, assetId, request); const updatedPayload = await this.app.trigger( "device-manager:asset:update:before", { asset, metadata } ); - const updatedAsset = await this.impersonatedSdk( - user - ).document.update( - engineId, - InternalCollection.ASSETS, - assetId, - { metadata: updatedPayload.metadata }, - { refresh, source: true } + const updatedAsset = await this.updateDocument( + request, + { + _id: assetId, + _source: { metadata: updatedPayload.metadata }, + }, + { + collection: InternalCollection.ASSETS, + engineId, + }, + { source: true } ); await this.assetHistoryService.add(engineId, [ @@ -133,12 +136,11 @@ export class AssetService extends BaseService { } public async create( - user: User, engineId: string, model: string, reference: string, metadata: JSONObject, - { refresh }: { refresh: any } + request: KuzzleRequest ): Promise> { const assetId = AssetSerializer.id(model, reference); @@ -167,20 +169,24 @@ export class AssetService extends BaseService { measures[name] = null; } - const asset = await this.impersonatedSdk( - user - ).document.create( - engineId, - InternalCollection.ASSETS, + const asset = await this.createDocument( + request, { - linkedDevices: [], - measures, - metadata: { ...assetMetadata, ...metadata }, - model, - reference, + _id: assetId, + _source: { + groups: [], + lastMeasuredAt: null, + linkedDevices: [], + measures, + metadata: { ...assetMetadata, ...metadata }, + model, + reference, + }, }, - assetId, - { refresh } + { + collection: InternalCollection.ASSETS, + engineId, + } ); await this.assetHistoryService.add(engineId, [ @@ -202,13 +208,15 @@ export class AssetService extends BaseService { } public async delete( - user: User, engineId: string, assetId: string, - { refresh, strict }: { refresh: any; strict: boolean } + request: KuzzleRequest ) { + const user = request.getUser(); + const strict = request.getBoolean("strict"); + return lock(`asset:${engineId}:${assetId}`, async () => { - const asset = await this.get(engineId, assetId); + const asset = await this.get(engineId, assetId, request); if (strict && asset._source.linkedDevices.length !== 0) { throw new BadRequestError( @@ -223,35 +231,22 @@ export class AssetService extends BaseService { ); } - await this.sdk.document.delete( + await this.deleteDocument(request, assetId, { + collection: InternalCollection.ASSETS, engineId, - InternalCollection.ASSETS, - assetId, - { - refresh, - } - ); + }); }); } public async search( engineId: string, - searchBody: JSONObject, - { - from, - size, - scroll, - lang, - }: { from?: number; size?: number; scroll?: string; lang?: string } + searchParams: SearchParams, + request: KuzzleRequest ): Promise>> { - const result = await this.sdk.document.search( + return await this.searchDocument(request, searchParams, { + collection: InternalCollection.ASSETS, engineId, - InternalCollection.ASSETS, - searchBody, - { from, lang, scroll, size } - ); - - return result; + }); } public async migrateTenant( diff --git a/lib/modules/asset/AssetsController.ts b/lib/modules/asset/AssetsController.ts index c8ab80c6..7801420e 100644 --- a/lib/modules/asset/AssetsController.ts +++ b/lib/modules/asset/AssetsController.ts @@ -124,7 +124,7 @@ export class AssetsController { const assetId = request.getId(); const engineId = request.getString("engineId"); - const asset = await this.assetService.get(engineId, assetId); + const asset = await this.assetService.get(engineId, assetId, request); return AssetSerializer.serialize(asset); } @@ -133,16 +133,12 @@ export class AssetsController { const assetId = request.getId(); const engineId = request.getString("engineId"); const metadata = request.getBodyObject("metadata"); - const refresh = request.getRefresh(); const updatedAsset = await this.assetService.update( - request.getUser(), engineId, assetId, metadata, - { - refresh, - } + request ); return AssetSerializer.serialize(updatedAsset); @@ -153,17 +149,13 @@ export class AssetsController { const model = request.getBodyString("model"); const reference = request.getBodyString("reference"); const metadata = request.getBodyObject("metadata", {}); - const refresh = request.getRefresh(); const asset = await this.assetService.create( - request.getUser(), engineId, model, reference, metadata, - { - refresh, - } + request ); return AssetSerializer.serialize(asset); @@ -172,33 +164,16 @@ export class AssetsController { async delete(request: KuzzleRequest): Promise { const engineId = request.getString("engineId"); const assetId = request.getId(); - const refresh = request.getRefresh(); - const strict = request.getBoolean("strict"); - await this.assetService.delete(request.getUser(), engineId, assetId, { - refresh, - strict, - }); + await this.assetService.delete(engineId, assetId, request); } async search(request: KuzzleRequest): Promise { - const engineId = request.getString("engineId"); - const { - searchBody, - from, - size, - scrollTTL: scroll, - } = request.getSearchParams(); - const lang = request.getLangParam(); - - const result = await this.assetService.search(engineId, searchBody, { - from, - lang, - scroll, - size, - }); - - return result; + return await this.assetService.search( + request.getString("engineId"), + request.getSearchParams(), + request + ); } async getMeasures( diff --git a/lib/modules/device/DeviceService.ts b/lib/modules/device/DeviceService.ts index 1b65a778..61070231 100644 --- a/lib/modules/device/DeviceService.ts +++ b/lib/modules/device/DeviceService.ts @@ -1,4 +1,4 @@ -import { BadRequestError, User } from "kuzzle"; +import { BadRequestError, KuzzleRequest } from "kuzzle"; import { JSONObject, KDocument, KHit, SearchResult } from "kuzzle-sdk"; import { @@ -8,7 +8,14 @@ import { AssetHistoryEventUnlink, } from "./../asset"; import { InternalCollection, DeviceManagerPlugin } from "../plugin"; -import { Metadata, lock, ask, onAsk, BaseService } from "../shared"; +import { + Metadata, + lock, + ask, + onAsk, + BaseService, + SearchParams, +} from "../shared"; import { AskModelAssetGet, AskModelDeviceGet, @@ -43,28 +50,39 @@ export class DeviceService extends BaseService { onAsk( "ask:device-manager:device:link-asset", async ({ deviceId, engineId, user, assetId, measureNames }) => { - await this.linkAsset(user, engineId, deviceId, assetId, measureNames); + const request = new KuzzleRequest({ refresh: "false" }, { user }); + await this.linkAsset( + engineId, + deviceId, + assetId, + measureNames, + false, + request + ); } ); onAsk( "ask:device-manager:device:unlink-asset", async ({ deviceId, user }) => { - await this.unlinkAsset(user, deviceId); + const request = new KuzzleRequest({ refresh: "false" }, { user }); + await this.unlinkAsset(deviceId, request); } ); onAsk( "ask:device-manager:device:detach-engine", async ({ deviceId, user }) => { - await this.detachEngine(user, deviceId); + const request = new KuzzleRequest({ refresh: "false" }, { user }); + await this.detachEngine(deviceId, request); } ); onAsk( "ask:device-manager:device:attach-engine", async ({ deviceId, engineId, user }) => { - await this.attachEngine(user, engineId, deviceId); + const request = new KuzzleRequest({ refresh: "false" }, { user }); + await this.attachEngine(engineId, deviceId, request); } ); } @@ -77,17 +95,10 @@ export class DeviceService extends BaseService { * required as an argument (in part to check the tenant rights) */ async create( - user: User, model: string, reference: string, metadata: JSONObject, - { - engineId, - refresh, - }: { - engineId?: string; - refresh?: any; - } = {} + request: KuzzleRequest ): Promise> { let device: KDocument = { _id: DeviceSerializer.id(model, reference), @@ -104,6 +115,7 @@ export class DeviceService extends BaseService { return lock(`device:create:${device._id}`, async () => { const deviceModel = await this.getDeviceModel(model); + const engineId = request.getString("engineId"); for (const metadataName of Object.keys( deviceModel.device.metadataMappings @@ -116,13 +128,13 @@ export class DeviceService extends BaseService { collection: string; }> = []; - const { _source } = await this.impersonatedSdk( - user - ).document.create( - this.config.adminIndex, - InternalCollection.DEVICES, - device._source, - device._id + const { _source } = await this.createDocument( + request, + device, + { + collection: InternalCollection.DEVICES, + engineId: this.config.adminIndex, + } ); device._source = _source; @@ -133,7 +145,7 @@ export class DeviceService extends BaseService { }); if (engineId && engineId !== this.config.adminIndex) { - device = await this.attachEngine(user, engineId, device._id); + device = await this.attachEngine(engineId, device._id, request); refreshableCollections.push({ collection: InternalCollection.DEVICES, @@ -141,7 +153,7 @@ export class DeviceService extends BaseService { }); } - if (refresh) { + if (request.getRefresh() === "wait_for") { await Promise.all( refreshableCollections.map(({ index, collection }) => this.sdk.collection.refresh(index, collection) @@ -154,43 +166,40 @@ export class DeviceService extends BaseService { } public async get( - index: string, - deviceId: string + engineId: string, + deviceId: string, + request: KuzzleRequest ): Promise> { - const device = await this.sdk.document.get( - index, - InternalCollection.DEVICES, - deviceId - ); - - return device; + return this.getDocument(request, deviceId, { + collection: InternalCollection.DEVICES, + engineId, + }); } public async update( - user: User, engineId: string, deviceId: string, metadata: Metadata, - { refresh }: { refresh: any } + request: KuzzleRequest ): Promise> { return lock>( `device:update:${deviceId}`, async () => { - const device = await this.get(engineId, deviceId); + const device = await this.get(engineId, deviceId, request); const updatedPayload = await this.app.trigger( "device-manager:device:update:before", { device, metadata } ); - const updatedDevice = await this.impersonatedSdk( - user - ).document.update( - engineId, - InternalCollection.DEVICES, - deviceId, - { metadata: updatedPayload.metadata }, - { refresh, source: true } + const updatedDevice = await this.updateDocument( + request, + { + _id: deviceId, + _source: { metadata: updatedPayload.metadata }, + }, + { collection: InternalCollection.DEVICES, engineId }, + { source: true } ); await this.app.trigger( @@ -207,13 +216,12 @@ export class DeviceService extends BaseService { } public async delete( - user: User, engineId: string, deviceId: string, - { refresh }: { refresh: any } + request: KuzzleRequest ) { return lock(`device:delete:${deviceId}`, async () => { - const device = await this.get(engineId, deviceId); + const device = await this.get(engineId, deviceId, request); const promises = []; @@ -231,56 +239,51 @@ export class DeviceService extends BaseService { promises.push( // Potential race condition if someone update the asset linkedDevices // at the same time (e.g link or unlink asset) - this.impersonatedSdk(user) - .document.update( - engineId, - InternalCollection.ASSETS, - device._source.assetId, - { linkedDevices }, - { refresh } - ) - .then(async (updatedAsset) => { - const event: AssetHistoryEventUnlink = { - name: "unlink", - unlink: { - deviceId, - }, - }; - - await ask>( - "ask:device-manager:asset:history:add", - { - engineId, - histories: [ - { - asset: updatedAsset._source, - event, - id: updatedAsset._id, - timestamp: Date.now(), - }, - ], - } - ); - }) + this.updateDocument( + request, + { + _id: device._source.assetId, + _source: { linkedDevices }, + }, + { collection: InternalCollection.ASSETS, engineId } + ).then(async (updatedAsset) => { + const event: AssetHistoryEventUnlink = { + name: "unlink", + unlink: { + deviceId, + }, + }; + + await ask>( + "ask:device-manager:asset:history:add", + { + engineId, + histories: [ + { + asset: updatedAsset._source, + event, + id: updatedAsset._id, + timestamp: Date.now(), + }, + ], + } + ); + }) ); } promises.push( - this.sdk.document.delete( - this.config.adminIndex, - InternalCollection.DEVICES, - deviceId, - { refresh } - ) + this.deleteDocument(request, deviceId, { + collection: InternalCollection.DEVICES, + engineId: this.config.adminIndex, + }) ); promises.push( - this.sdk.document.delete( + this.deleteDocument(request, deviceId, { + collection: InternalCollection.DEVICES, engineId, - InternalCollection.DEVICES, - deviceId, - { refresh } - ) + }) ); await Promise.all(promises); @@ -289,22 +292,13 @@ export class DeviceService extends BaseService { public async search( engineId: string, - searchBody: JSONObject, - { - from, - size, - scroll, - lang, - }: { from?: number; size?: number; scroll?: string; lang?: string } + searchParams: SearchParams, + request: KuzzleRequest ): Promise>> { - const result = await this.sdk.document.search( + return await this.searchDocument(request, searchParams, { + collection: InternalCollection.DEVICES, engineId, - InternalCollection.DEVICES, - searchBody, - { from, lang, scroll, size } - ); - - return result; + }); } /** @@ -316,13 +310,12 @@ export class DeviceService extends BaseService { * @param options.strict If true, throw if an operation isn't possible */ async attachEngine( - user: User, engineId: string, deviceId: string, - { refresh }: { refresh?: any } = {} + request: KuzzleRequest ): Promise> { return lock(`device:attachEngine:${deviceId}`, async () => { - const device = await this.get(this.config.adminIndex, deviceId); + const device = await this.get(this.config.adminIndex, deviceId, request); if (device._source.engineId) { throw new BadRequestError( @@ -335,23 +328,18 @@ export class DeviceService extends BaseService { device._source.engineId = engineId; const [updatedDevice] = await Promise.all([ - this.impersonatedSdk(user).document.update( - this.config.adminIndex, - InternalCollection.DEVICES, - device._id, - { engineId }, - { source: true } - ), + this.updateDocument(request, device, { + collection: InternalCollection.DEVICES, + engineId: this.config.adminIndex, + }), - this.impersonatedSdk(user).document.create( - device._source.engineId, - InternalCollection.DEVICES, - device._source, - device._id - ), + this.createDocument(request, device, { + collection: InternalCollection.DEVICES, + engineId, + }), ]); - if (refresh) { + if (request.getRefresh() === "wait_for") { await Promise.all([ this.sdk.collection.refresh( this.config.adminIndex, @@ -371,29 +359,33 @@ export class DeviceService extends BaseService { /** * Detach a device from its attached engine * - * @param deviceId Device id - * @param options.refresh Wait for ES indexation + * @param {string} deviceId Id of the device + * @param {KuzzleRequest} request kuzzle request */ async detachEngine( - user: User, deviceId: string, - { refresh }: { refresh?: any } = {} + request: KuzzleRequest ): Promise> { return lock(`device:detachEngine:${deviceId}`, async () => { - const device = await this.get(this.config.adminIndex, deviceId); + const device = await this.get(this.config.adminIndex, deviceId, request); this.checkAttachedToEngine(device); if (device._source.assetId) { - await this.unlinkAsset(user, deviceId, { refresh }); + await this.unlinkAsset(deviceId, request); } await Promise.all([ - this.impersonatedSdk(user).document.update( - this.config.adminIndex, - InternalCollection.DEVICES, - device._id, - { engineId: null } + this.updateDocument( + request, + { + _id: device._id, + _source: { engineId: null }, + }, + { + collection: InternalCollection.DEVICES, + engineId: this.config.adminIndex, + } ), this.sdk.document.delete( @@ -403,7 +395,7 @@ export class DeviceService extends BaseService { ), ]); - if (refresh) { + if (request.getRefresh() === "wait_for") { await Promise.all([ this.sdk.collection.refresh( this.config.adminIndex, @@ -424,21 +416,18 @@ export class DeviceService extends BaseService { * Link a device to an asset. */ async linkAsset( - user: User, engineId: string, deviceId: string, assetId: string, measureNames: ApiDeviceLinkAssetRequest["body"]["measureNames"], - { - refresh, - implicitMeasuresLinking, - }: { refresh?: any; implicitMeasuresLinking?: boolean } = {} + implicitMeasuresLinking: boolean, + request: KuzzleRequest ): Promise<{ asset: KDocument; device: KDocument; }> { return lock(`device:linkAsset:${deviceId}`, async () => { - const device = await this.get(this.config.adminIndex, deviceId); + const device = await this.get(this.config.adminIndex, deviceId, request); const engine = await this.getEngine(engineId); this.checkAttachedToEngine(device); @@ -509,26 +498,28 @@ export class DeviceService extends BaseService { }); const [updatedDevice, , updatedAsset] = await Promise.all([ - this.impersonatedSdk(user).document.update( - this.config.adminIndex, - InternalCollection.DEVICES, - device._id, - { assetId }, + this.updateDocument( + request, + device, + { + collection: InternalCollection.DEVICES, + engineId: this.config.adminIndex, + }, { source: true } ), - this.impersonatedSdk(user).document.update( - device._source.engineId, - InternalCollection.DEVICES, - device._id, - { assetId } - ), + this.updateDocument(request, device, { + collection: InternalCollection.DEVICES, + engineId: device._source.engineId, + }), - this.impersonatedSdk(user).document.update( - device._source.engineId, - InternalCollection.ASSETS, - asset._id, - { linkedDevices: asset._source.linkedDevices }, + this.updateDocument( + request, + asset, + { + collection: InternalCollection.ASSETS, + engineId: device._source.engineId, + }, { source: true } ), ]); @@ -554,7 +545,7 @@ export class DeviceService extends BaseService { } ); - if (refresh) { + if (request.getRefresh() === "wait_for") { await Promise.all([ this.sdk.collection.refresh( this.config.adminIndex, @@ -579,9 +570,10 @@ export class DeviceService extends BaseService { engineId: string, deviceId: string, measures: DecodedMeasurement[], - payloadUuids: string[] + payloadUuids: string[], + request: KuzzleRequest ) { - const device = await this.get(engineId, deviceId); + const device = await this.get(engineId, deviceId, request); const deviceModel = await this.getDeviceModel(device._source.model); for (const measure of measures) { @@ -679,19 +671,18 @@ export class DeviceService extends BaseService { /** * Unlink a device of an asset * - * @param deviceId Id of the device - * @param options.refresh Wait for ES indexation + * @param {string} deviceId Id of the device + * @param {KuzzleRequest} request kuzzle request */ async unlinkAsset( - user: User, deviceId: string, - { refresh }: { refresh?: any } = {} + request: KuzzleRequest ): Promise<{ asset: KDocument; device: KDocument; }> { return lock(`device:unlinkAsset:${deviceId}`, async () => { - const device = await this.get(this.config.adminIndex, deviceId); + const device = await this.get(this.config.adminIndex, deviceId, request); const engineId = device._source.engineId; this.checkAttachedToEngine(device); @@ -713,26 +704,32 @@ export class DeviceService extends BaseService { ); const [updatedDevice, , updatedAsset] = await Promise.all([ - this.impersonatedSdk(user).document.update( - this.config.adminIndex, - InternalCollection.DEVICES, - device._id, - { assetId: null }, + this.updateDocument( + request, + { _id: device._id, _source: { assetId: null } }, + { + collection: InternalCollection.DEVICES, + engineId: this.config.adminIndex, + }, { source: true } ), - this.impersonatedSdk(user).document.update( - engineId, - InternalCollection.DEVICES, - device._id, - { assetId: null } + this.updateDocument( + request, + { _id: device._id, _source: { assetId: null } }, + { + collection: InternalCollection.DEVICES, + engineId, + } ), - this.impersonatedSdk(user).document.update( - engineId, - InternalCollection.ASSETS, - asset._id, - { linkedDevices }, + this.updateDocument( + request, + { _id: asset._id, _source: { linkedDevices } }, + { + collection: InternalCollection.ASSETS, + engineId, + }, { source: true } ), ]); @@ -758,7 +755,7 @@ export class DeviceService extends BaseService { } ); - if (refresh) { + if (request.getRefresh() === "wait_for") { await Promise.all([ this.sdk.collection.refresh( this.config.adminIndex, diff --git a/lib/modules/device/DevicesController.ts b/lib/modules/device/DevicesController.ts index 97abb42a..241c9a28 100644 --- a/lib/modules/device/DevicesController.ts +++ b/lib/modules/device/DevicesController.ts @@ -170,7 +170,7 @@ export class DevicesController { const deviceId = request.getId(); const engineId = request.getString("engineId"); - const device = await this.deviceService.get(engineId, deviceId); + const device = await this.deviceService.get(engineId, deviceId, request); return DeviceSerializer.serialize(device); } @@ -179,16 +179,12 @@ export class DevicesController { const deviceId = request.getId(); const engineId = request.getString("engineId"); const metadata = request.getBodyObject("metadata"); - const refresh = request.getRefresh(); const updatedDevice = await this.deviceService.update( - request.getUser(), engineId, deviceId, metadata, - { - refresh, - } + request ); return DeviceSerializer.serialize(updatedDevice); @@ -197,52 +193,31 @@ export class DevicesController { async delete(request: KuzzleRequest): Promise { const engineId = request.getString("engineId"); const deviceId = request.getId(); - const refresh = request.getRefresh(); - await this.deviceService.delete(request.getUser(), engineId, deviceId, { - refresh, - }); + await this.deviceService.delete(engineId, deviceId, request); } async search(request: KuzzleRequest): Promise { - const engineId = request.getString("engineId"); - const { - searchBody, - from, - size, - scrollTTL: scroll, - } = request.getSearchParams(); - const lang = request.getLangParam(); - - const result = await this.deviceService.search(engineId, searchBody, { - from, - lang, - scroll, - size, - }); - - return result; + return await this.deviceService.search( + request.getString("engineId"), + request.getSearchParams(), + request + ); } /** * Create and provision a new device */ async create(request: KuzzleRequest): Promise { - const engineId = request.getString("engineId"); const model = request.getBodyString("model"); const reference = request.getBodyString("reference"); const metadata = request.getBodyObject("metadata", {}); - const refresh = request.getRefresh(); const device = await this.deviceService.create( - request.getUser(), model, reference, metadata, - { - engineId, - refresh, - } + request ); return DeviceSerializer.serialize(device); @@ -256,16 +231,8 @@ export class DevicesController { ): Promise { const engineId = request.getString("engineId"); const deviceId = request.getId(); - const refresh = request.getRefresh(); - await this.deviceService.attachEngine( - request.getUser(), - engineId, - deviceId, - { - refresh, - } - ); + await this.deviceService.attachEngine(engineId, deviceId, request); } /** @@ -275,11 +242,8 @@ export class DevicesController { request: KuzzleRequest ): Promise { const deviceId = request.getId(); - const refresh = request.getRefresh(); - await this.deviceService.detachEngine(request.getUser(), deviceId, { - refresh, - }); + await this.deviceService.detachEngine(deviceId, request); } /** @@ -296,7 +260,6 @@ export class DevicesController { const implicitMeasuresLinking = request.getBoolean( "implicitMeasuresLinking" ); - const refresh = request.getRefresh(); if (measureNames.length === 0 && !implicitMeasuresLinking) { throw new BadRequestError( @@ -305,12 +268,12 @@ export class DevicesController { } const { asset, device } = await this.deviceService.linkAsset( - request.getUser(), engineId, deviceId, assetId, measureNames, - { implicitMeasuresLinking, refresh } + implicitMeasuresLinking, + request ); return { @@ -326,14 +289,10 @@ export class DevicesController { request: KuzzleRequest ): Promise { const deviceId = request.getId(); - const refresh = request.getRefresh(); const { asset, device } = await this.deviceService.unlinkAsset( - request.getUser(), deviceId, - { - refresh, - } + request ); return { @@ -480,7 +439,8 @@ export class DevicesController { engineId, deviceId, measures, - payloadUuids + payloadUuids, + request ); } diff --git a/lib/modules/plugin/exports.ts b/lib/modules/plugin/exports.ts index 490e21cb..8197ae3b 100644 --- a/lib/modules/plugin/exports.ts +++ b/lib/modules/plugin/exports.ts @@ -1,2 +1,2 @@ -export * from "./types/DeviceManagerConfiguration"; +export * from "./types/exports"; export * from "./DeviceManagerPlugin"; diff --git a/lib/modules/plugin/index.ts b/lib/modules/plugin/index.ts index cbd3b476..2d7ba0ca 100644 --- a/lib/modules/plugin/index.ts +++ b/lib/modules/plugin/index.ts @@ -1,4 +1,3 @@ -export * from "./types/DeviceManagerConfiguration"; +export * from "./types"; export * from "./DeviceManagerEngine"; export * from "./DeviceManagerPlugin"; -export * from "./types/InternalCollection"; diff --git a/lib/modules/plugin/types/Pipes.ts b/lib/modules/plugin/types/Pipes.ts new file mode 100644 index 00000000..4708f06c --- /dev/null +++ b/lib/modules/plugin/types/Pipes.ts @@ -0,0 +1,22 @@ +import { JSONObject, KDocumentContent, KHit, KuzzleRequest } from "kuzzle"; + +export interface SearchQueryResult { + aggregations?: JSONObject; + hits: Array>; + remaining: unknown; + scrollId: string; + suggest: JSONObject; + total: number; +} + +export type EventGenericDocumentBeforeSearch = { + name: `generic:document:beforeSearch`; + args: [JSONObject, KuzzleRequest]; +}; + +export type EventGenericDocumentAfterSearch< + T extends KDocumentContent = KDocumentContent +> = { + name: `generic:document:afterSearch`; + args: [SearchQueryResult, KuzzleRequest]; +}; diff --git a/lib/modules/plugin/types/exports.ts b/lib/modules/plugin/types/exports.ts new file mode 100644 index 00000000..7715785d --- /dev/null +++ b/lib/modules/plugin/types/exports.ts @@ -0,0 +1 @@ +export * from "./DeviceManagerConfiguration"; diff --git a/lib/modules/plugin/types/index.ts b/lib/modules/plugin/types/index.ts new file mode 100644 index 00000000..30abef8e --- /dev/null +++ b/lib/modules/plugin/types/index.ts @@ -0,0 +1,3 @@ +export * from "./DeviceManagerConfiguration"; +export * from "./InternalCollection"; +export * from "./Pipes"; diff --git a/lib/modules/shared/services/BaseService.ts b/lib/modules/shared/services/BaseService.ts index 7828f9dc..d26b177e 100644 --- a/lib/modules/shared/services/BaseService.ts +++ b/lib/modules/shared/services/BaseService.ts @@ -1,6 +1,42 @@ -import { Backend, EmbeddedSDK, User } from "kuzzle"; +import { + ArgsDocumentControllerCreate, + ArgsDocumentControllerDelete, + ArgsDocumentControllerUpdate, + Backend, + BaseRequest, + DocumentSearchResult, + EmbeddedSDK, + EventGenericDocumentAfterDelete, + EventGenericDocumentAfterGet, + EventGenericDocumentAfterUpdate, + EventGenericDocumentAfterWrite, + EventGenericDocumentBeforeDelete, + EventGenericDocumentBeforeGet, + EventGenericDocumentBeforeUpdate, + EventGenericDocumentBeforeWrite, + KDocument, + KDocumentContent, + KHit, + KuzzleRequest, + SearchResult, + User, +} from "kuzzle"; -import { DeviceManagerPlugin, DeviceManagerConfiguration } from "../../plugin"; +import { + DeviceManagerPlugin, + DeviceManagerConfiguration, + InternalCollection, + EventGenericDocumentBeforeSearch, + EventGenericDocumentAfterSearch, + SearchQueryResult, +} from "../../plugin"; + +interface PayloadRequest { + collection: InternalCollection; + engineId: string; +} + +export type SearchParams = ReturnType; export abstract class BaseService { constructor(private plugin: DeviceManagerPlugin) {} @@ -26,4 +62,220 @@ export abstract class BaseService { return this.sdk; }; } + + /** + * Wrapper to SDK create method with trigger generic:document events + * + * @param {KuzzleRequest} request + * @param {KDocument} documentId + * @param {PayloadRequest} payload + * @param {ArgsDocumentControllerCreate} [options] + * @returns {Promise} + */ + protected async getDocument( + request: KuzzleRequest, + documentId: string, + { engineId, collection }: PayloadRequest, + options: ArgsDocumentControllerCreate = {} + ): Promise> { + const refresh = request.getRefresh(); + + request.input.args.collection = collection; + const [{ _id }] = await this.app.trigger( + "generic:document:beforeGet", + [{ _id: documentId }], + request + ); + + const newDocument = await this.sdk.document.get( + engineId, + collection, + _id, + { refresh, ...options } + ); + + const [endDocument] = await this.app.trigger< + EventGenericDocumentAfterGet + >("generic:document:afterGet", [newDocument], request); + + return endDocument; + } + + /** + * Wrapper to SDK create method with trigger generic:document events + * + * @param {KuzzleRequest} request + * @param {KDocument} document + * @param {PayloadRequest} payload + * @param {ArgsDocumentControllerCreate} [options] + * @returns {Promise} + */ + protected async createDocument( + request: KuzzleRequest, + document: KDocument, + { engineId, collection }: PayloadRequest, + options: ArgsDocumentControllerCreate = {} + ): Promise> { + const user = request.getUser(); + const refresh = request.getRefresh(); + + request.input.args.collection = collection; + const [modifiedDocument] = await this.app.trigger< + EventGenericDocumentBeforeWrite + >("generic:document:beforeWrite", [document], request); + + const newDocument = await this.impersonatedSdk(user).document.create( + engineId, + collection, + modifiedDocument._source, + modifiedDocument._id, + { refresh, ...options } + ); + const [endDocument] = await this.app.trigger< + EventGenericDocumentAfterWrite + >("generic:document:afterWrite", [newDocument], request); + + return endDocument; + } + + /** + * Wrapper to SDK update method with trigger generic:document events + * + * @param {KuzzleRequest} request + * @param {KDocument} document + * @param {PayloadRequest} payload + * @param {ArgsDocumentControllerUpdate} [options] + * @returns {Promise} + */ + protected async updateDocument( + request: KuzzleRequest, + document: KDocument>, + { engineId, collection }: PayloadRequest, + options: ArgsDocumentControllerUpdate = {} + ): Promise> { + const user = request.getUser(); + const refresh = request.getRefresh(); + + request.input.args.collection = collection; + const [modifiedDocument] = await this.app.trigger< + EventGenericDocumentBeforeUpdate> + >("generic:document:beforeUpdate", [document], request); + + const updatedDocument = await this.impersonatedSdk(user).document.update( + engineId, + collection, + modifiedDocument._id, + modifiedDocument._source, + { refresh, ...options } + ); + + const [endDocument] = await this.app.trigger< + EventGenericDocumentAfterUpdate + >("generic:document:afterUpdate", [updatedDocument], request); + + return endDocument; + } + + /** + * Wrapper to SDK delete method with trigger generic:document events + * + * @param {KuzzleRequest} request + * @param {string} documentId + * @param {ArgsDocumentControllerUpdate} [options] + * @returns {Promise<{ _id: string }>} + */ + protected async deleteDocument( + request: KuzzleRequest, + documentId: string, + { engineId, collection }: PayloadRequest, + options: ArgsDocumentControllerDelete = {} + ): Promise<{ _id: string }> { + const user = request.getUser(); + const refresh = request.getRefresh(); + + request.input.args.collection = collection; + const [modifiedDocument] = + await this.app.trigger( + "generic:document:beforeDelete", + [{ _id: documentId }], + request + ); + + const deletedDocument = await this.impersonatedSdk(user).document.delete( + engineId, + collection, + modifiedDocument._id, + { refresh, ...options } + ); + + const [endDocument] = + await this.app.trigger( + "generic:document:afterDelete", + [{ _id: deletedDocument }], + request + ); + + return endDocument; + } + + /** + * Wrapper to SDK search method with trigger generic:document events + * ! Caution the pipes are not applied on next() + * + * @param {KuzzleRequest} request + * @param {string} documentId + * @param {ArgsDocumentControllerUpdate} [options] + * @returns {Promise<{ _id: string }>} + */ + protected async searchDocument( + request: KuzzleRequest, + { from, size, scrollTTL: scroll }: SearchParams, + { engineId, collection }: PayloadRequest + ): Promise>> { + const { + protocol, + misc: { verb = "POST" }, + } = request.context.connection; + + const lang = request.getLangParam(); + const searchBody = request.getSearchBody(); + + request.input.args.collection = collection; + const modifiedBody = + await this.app.trigger( + "generic:document:beforeSearch", + searchBody, + request + ); + + const query = { + action: "search", + body: null, + collection, + controller: "document", + from, + index: engineId, + lang, + scroll, + searchBody: null, + size, + verb, + }; + + if (protocol === "http" && verb === "GET") { + query.searchBody = modifiedBody; + } else { + query.body = modifiedBody; + } + + const { result } = await this.sdk.query>( + query + ); + + const modifiedResult = await this.app.trigger< + EventGenericDocumentAfterSearch + >("generic:document:afterSearch", result, request); + + return new DocumentSearchResult(global, query, {}, modifiedResult); + } }