Skip to content

Commit

Permalink
mLinkAsset (#51)
Browse files Browse the repository at this point in the history
  • Loading branch information
rolljee authored Apr 1, 2021
1 parent 3077036 commit 0a2555e
Show file tree
Hide file tree
Showing 9 changed files with 9,582 additions and 56 deletions.
6 changes: 3 additions & 3 deletions doc/1/controllers/device/m-attach/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ The device document will be duplicated inside the tenant "devices" collection.
### HTTP

``` http
URL: http://kuzzle:7512/_/device-manager/devices/_mAttach
URL: http://kuzzle:7512/_/device-manager/devices/_mAttach[?refresh=wait_for][&strict=true|false]
Method: PUT
Body:
```
Expand All @@ -31,7 +31,7 @@ Body:
"deviceId": "test-id"
}],
// Using CSV syntax
"csv": "tenant,id\ntenant-kuzzle,test-id"
"csv": "tenantId,deviceId\ntenant-kuzzle,test-id"
}
```

Expand Down Expand Up @@ -61,13 +61,13 @@ Body properties, must contain at least one of

- `records`: an array of object containing `tenantId` and `deviceId`
- `csv`: a csv syntax compatible containing at least this two headers `tenantId,deviceId` with their corresponding values
- `strict`: a boolean value that indicate if the process should fail at first error

---

### Optional:

* `refresh`: if set to `wait_for`, Kuzzle will not respond until the documents are indexed
* `strict`: (boolean) if set, makes the process fail preemptively if at least one link cannot be applied (e.g. devices that aren't attached to a tenant, or because of non-existing assets)

---

Expand Down
6 changes: 2 additions & 4 deletions doc/1/controllers/device/m-detach/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Detach multiple devices from multiple tenants.
### HTTP

``` http
URL: http://kuzzle:7512/_/device-manager/device-manager/devices/_mDetach[?refresh=wait_for]
URL: http://kuzzle:7512/_/device-manager/device-manager/devices/_mDetach[?refresh=wait_for][&strict]
Method: PUT
Body:
```
Expand Down Expand Up @@ -53,15 +53,13 @@ Body properties, must contain at least one of

* `sensorIds`: an array of string containing identifiers of a sensor already attached
* `csv`: a csv syntax compatible containing at least one header `sensorId` with his corresponding values
* `strict`: a boolean value that indicate if the process should fail at first error

---

## Arguments

### Optional:

* `refresh`: if set to `wait_for`, Kuzzle will not respond until the documents are indexed
* `strict`: (boolean) if set, makes the process fail preemptively if at least one link cannot be applied (e.g. devices that aren't attached to a tenant, or because of non-existing assets)

---

Expand Down
86 changes: 86 additions & 0 deletions doc/1/controllers/device/m-link/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
---
code: true
type: page
title: mLink
description: Link multiple devices to multiple assets
---

# mLink

Link multiple devices to multiple assets

---

## Query Syntax

### HTTP

``` http
URL: http://kuzzle:7512/_/device-manager/devices/_mLink[?refresh=wait_for][&strict]
Method: PUT
Body:
```

``` js
{
// Using JSON
"records" [{
"assetId": "myAssetId",
"deviceId": "test-id"
}],
// Using CSV syntax
"csv": "assetId, deviceId\nmyAssetId,test-id"
}
```

### Other protocols

``` js
{
"controller": "device-manager/device",
"action": "mLink",
"body": {
// Using JSON
"records" [{
"assetId": "myAssetId",
"deviceId": "test-id"
}],
// Using CSV syntax
"csv": "assetId,deviceId\nmyAssetId,test-id",
}
}
```

---

## Body properties

Body properties, must contain at least one of the following:

- `records`: an array of objects, each containing an `assetId` and a `deviceId` properties
- `csv`: a csv syntax compatible containing at least this two headers `assetId,deviceId` with their corresponding values

---

### Optional:

* `refresh`: if set to `wait_for`, Kuzzle will not respond until the documents are indexed
* `strict`: (boolean) if set, makes the process fail preemptively if at least one link cannot be applied (e.g. devices that aren't attached to a tenant, or because of non-existing assets)

---

## Response

``` js
{
"status": 200,
"error": null,
"controller": "device-manager/device",
"action": "mLink",
"requestId": "<unique request identifier>",
"result": {
"errors": [],
"successes": []
}
}
```
8 changes: 8 additions & 0 deletions doc/1/guides/devices/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,14 @@ When linked, the device measures are copied inside the asset document.

New measures received by the device will be propagated inside the asset document.

## Link Multiple Devices to Multiple Assets

Multiple Devices can be linked at the same time to multiple assets by using the [device-manager/device:mLink](/kuzzle-iot-platform/device-manager/1/controllers/device/m-link) API action.

Once linked, each device's measures are copied inside their corresponding asset document.

New measures received by the device will be propagated inside each assets documents.

## Metadata

It is possible to attach metadata to the devices within the `metadata` property.
Expand Down
37 changes: 35 additions & 2 deletions features/DeviceController.feature
Original file line number Diff line number Diff line change
Expand Up @@ -134,17 +134,50 @@ Feature: Device Manager device controller
| measures.temperature.degree | 23.3 |
| measures.temperature.qos.battery | 80 |

Scenario: Link multiple device to multiple assets using JSON
When I successfully execute the action "device-manager/device":"mLink" with args:
| body.records.0.deviceId | "DummyTemp_attached-ayse-unlinked" |
| body.records.0.assetId | "PERFO-unlinked" |
Then The document "device-manager":"devices":"DummyTemp_attached-ayse-unlinked" content match:
| assetId | "PERFO-unlinked" |
And The document "tenant-ayse":"devices":"DummyTemp_attached-ayse-unlinked" content match:
| assetId | "PERFO-unlinked" |
And The document "tenant-ayse":"assets":"PERFO-unlinked" content match:
| measures.temperature.id | "DummyTemp_attached-ayse-unlinked" |
| measures.temperature.model | "DummyTemp" |
| measures.temperature.reference | "attached-ayse-unlinked" |
| measures.temperature.updatedAt | 1610793427950 |
| measures.temperature.payloadUuid | "_STRING_" |
| measures.temperature.degree | 23.3 |
| measures.temperature.qos.battery | 80 |

Scenario: Link multiple device to multiple assets using CSV
When I successfully execute the action "device-manager/device":"mLink" with args:
| body.csv | "deviceId,assetId\\nDummyTemp_attached-ayse-unlinked,PERFO-unlinked" |
Then The document "device-manager":"devices":"DummyTemp_attached-ayse-unlinked" content match:
| assetId | "PERFO-unlinked" |
And The document "tenant-ayse":"devices":"DummyTemp_attached-ayse-unlinked" content match:
| assetId | "PERFO-unlinked" |
And The document "tenant-ayse":"assets":"PERFO-unlinked" content match:
| measures.temperature.id | "DummyTemp_attached-ayse-unlinked" |
| measures.temperature.model | "DummyTemp" |
| measures.temperature.reference | "attached-ayse-unlinked" |
| measures.temperature.updatedAt | 1610793427950 |
| measures.temperature.payloadUuid | "_STRING_" |
| measures.temperature.degree | 23.3 |
| measures.temperature.qos.battery | 80 |

Scenario: Error when linking device to an asset
When I execute the action "device-manager/device":"linkAsset" with args:
| _id | "DummyTemp_detached" |
| assetId | "PERFO-unlinked" |
Then I should receive an error matching:
| message | "Device \"DummyTemp_detached\" is not attached to a tenant" |
| message | "Devices \"DummyTemp_detached\" are not attached to a tenant" |
When I execute the action "device-manager/device":"linkAsset" with args:
| _id | "DummyTemp_attached-ayse-unlinked" |
| assetId | "PERFO-non-existing" |
Then I should receive an error matching:
| message | "Asset \"PERFO-non-existing\" does not exists" |
| message | "Assets \"PERFO-non-existing\" do not exist" |

Scenario: Unlink device from an asset
Given I successfully execute the action "device-manager/device":"linkAsset" with args:
Expand Down
30 changes: 24 additions & 6 deletions lib/controllers/DeviceController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ export class DeviceController extends CRUDController {
handler: this.linkAsset.bind(this),
http: [{ verb: 'put', path: 'device-manager/:index/devices/:_id/_link/:assetId' }]
},
mLink: {
handler: this.mLink.bind(this),
http: [{ verb: 'put', path: 'device-manager/devices/_mLink' }]
},
unlink: {
handler: this.unlink.bind(this),
http: [{ verb: 'delete', path: 'device-manager/:index/devices/:_id/_unlink' }]
Expand Down Expand Up @@ -118,13 +122,25 @@ export class DeviceController extends CRUDController {
/**
* Link a device to an asset.
*/
async linkAsset(request: KuzzleRequest) {
async linkAsset (request: KuzzleRequest) {
const assetId = this.getString(request, 'assetId');
const deviceId = this.getId(request);

const device = await this.getDevice(deviceId);
const document: DeviceBulkContent = { deviceId, assetId };
const devices = await this.mGetDevice([document]);

await this.deviceService.linkAsset(device, assetId, this.decoders);
await this.deviceService.mLink(devices, [document], this.decoders, { strict: true });
}

/**
* Link multiple devices to multiple assets.
*/
async mLink (request: KuzzleRequest) {
const { bulkData, strict } = await this.mParseRequest(request);

const devices = await this.mGetDevice(bulkData);

return this.deviceService.mLink(devices, bulkData, this.decoders, { strict });
}

/**
Expand All @@ -147,6 +163,8 @@ export class DeviceController extends CRUDController {
return new Device(document._source, document._id);
}



private async mGetDevice (devices: DeviceBulkContent[]): Promise<Device[]> {
const deviceIds = devices.map(doc => doc.deviceId);
const result: any = await this.sdk.document.mGet(
Expand All @@ -158,15 +176,15 @@ export class DeviceController extends CRUDController {
}

private async mParseRequest (request: KuzzleRequest) {
const { body } = request.input;
const { body, args } = request.input;

let bulkData: DeviceBulkContent[];

if (body.csv) {
const lines = await csv({ delimiter: 'auto' })
.fromString(body.csv);

bulkData = lines.map(line => ({ tenantId: line.tenantId, deviceId: line.deviceId }));
bulkData = lines.map(line => ({ tenantId: line.tenantId, deviceId: line.deviceId, assetId: line.assetId }));
}
else if (body.records) {
bulkData = body.records;
Expand All @@ -178,7 +196,7 @@ export class DeviceController extends CRUDController {
throw new BadRequestError(`Malformed request missing property csv, records, deviceIds`);
}

const strict = body.strict || false;
const strict = args.strict ? args.strict : false;

return { strict, bulkData };
}
Expand Down
Loading

0 comments on commit 0a2555e

Please sign in to comment.