Skip to content

Commit d29cd20

Browse files
authored
Change grouptag to array to save multiple tags for a device (#536)
* Change grouptag to array to save multiple tags for a device * Update grouptag to array in tests * Check different chai stuff * Update grouptag test cases * Fix migration * Change grouptag query * Remove unnecessary check * Update sketch-templater * Update node version to 16 * Set timeout * Return from promise * Try calling done() * Return again * Use done() in beofre and after * use chai-http * Use done() and set headers * Back to chakram * Return in hooks * Use old sketch templater * Return from hooks * Update sketch-templater dependency * Update sketch templater to latest version
1 parent 2b68fa3 commit d29cd20

File tree

11 files changed

+272
-55
lines changed

11 files changed

+272
-55
lines changed

.github/workflows/test.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ jobs:
1515
steps:
1616
- uses: actions/checkout@v2
1717

18-
- name: Install Node.js 12
18+
- name: Install Node.js 16
1919
uses: actions/[email protected]
2020
with:
21-
node-version: 12
21+
node-version: 16
2222

2323
- name: Get yarn cache directory path
2424
id: yarn-cache-dir-path

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"@sensebox/eslint-config-sensebox": "^1.1.0",
2323
"@turf/invariant": "^6.1.2",
2424
"chai": "^4.3.4",
25+
"chai-http": "^4.3.0",
2526
"chakram": "^1.5.0",
2627
"cheerio": "^1.0.0-rc.6",
2728
"csv-parse": "^4.15.4",

packages/api/lib/controllers/boxesController.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ const
7676
* @apiUse TTNBody
7777
*
7878
* @apiParam (RequestBody) {String} [name] the name of this senseBox.
79-
* @apiParam (RequestBody) {String} [grouptag] the grouptag of this senseBox. Send '' (empty string) to delete this property.
79+
* @apiParam (RequestBody) {String[]} [grouptag] the grouptag(s) of this senseBox. Send [] (empty array) to delete this property.
8080
* @apiParam (RequestBody) {Location} [location] the new coordinates of this senseBox. Measurements will keep the reference to their correct location
8181
* @apiParam (RequestBody) {Sensor[]} [sensors] an array containing the sensors of this senseBox. Only use if model is unspecified
8282
* @apiParam (RequestBody) {MqttOption} [mqtt] settings for the MQTT integration of this senseBox
@@ -520,7 +520,7 @@ module.exports = {
520520
retrieveParameters([
521521
{ predef: 'boxId', required: true },
522522
{ name: 'name' },
523-
{ name: 'grouptag', dataType: 'StringWithEmpty' },
523+
{ name: 'grouptag', dataType: ['String'] },
524524
{ name: 'description', dataType: 'StringWithEmpty' },
525525
{ name: 'weblink', dataType: 'StringWithEmpty' },
526526
{ name: 'image', dataType: 'base64Image' },
@@ -551,7 +551,7 @@ module.exports = {
551551
checkContentType,
552552
retrieveParameters([
553553
{ name: 'name', required: true },
554-
{ name: 'grouptag', aliases: ['tag'] },
554+
{ name: 'grouptag', dataType: ['String'], aliases: ['tag'] },
555555
{ name: 'exposure', allowedValues: Box.BOX_VALID_EXPOSURES },
556556
{ name: 'model', allowedValues: Box.BOX_VALID_MODELS },
557557
{ name: 'sensors', dataType: ['object'] },
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/* eslint-disable */
2+
"use strict";
3+
4+
const models = require("../../../models");
5+
const { mongoose, connect } = models.db;
6+
const moment = require("moment");
7+
8+
const { Box } = models;
9+
10+
const migrate = function migrate() {
11+
const schemaVersion = mongoose.connection.db.collection("schemaVersion");
12+
13+
console.log('Starting "convert grouptag to array" migration');
14+
15+
return schemaVersion
16+
.find({})
17+
.next()
18+
.then(function (latestVersion) {
19+
if (latestVersion.schemaVersion !== 8) {
20+
throw new Error("Unexpected schema version... Exiting!");
21+
}
22+
23+
return Box.find({grouptag: {$exists: true}}, ['grouptag']).exec();
24+
})
25+
.then(function (boxes) {
26+
const promises = [];
27+
for (let index = 0; index < boxes.length; index++) {
28+
const box = boxes[index];
29+
30+
const grouptags = [];
31+
grouptags.push(box.grouptag);
32+
33+
box.set("grouptag", grouptags);
34+
promises.push(box.save());
35+
}
36+
37+
return Promise.all(promises).then(function () {
38+
console.log("Migration done!");
39+
40+
return schemaVersion.update({}, { $inc: { schemaVersion: 1 } });
41+
});
42+
});
43+
};
44+
45+
// Connect to db and run migration
46+
connect()
47+
.then(function () {
48+
migrate()
49+
.then(function () {
50+
mongoose.disconnect();
51+
})
52+
.catch(function (err) {
53+
console.log(err);
54+
mongoose.disconnect();
55+
});
56+
})
57+
.catch(function (err) {
58+
console.log(err);
59+
});

packages/models/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"@grpc/grpc-js": "^1.3.7",
99
"@grpc/proto-loader": "^0.6.4",
1010
"@sensebox/osem-protos": "^1.1.0",
11-
"@sensebox/sketch-templater": "^1.10.5",
11+
"@sensebox/sketch-templater": "1.11.2",
1212
"bcrypt": "^5.0.1",
1313
"bunyan": "^1.8.15",
1414
"config": "^3.3.6",

packages/models/src/box/box.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ const boxSchema = new Schema({
6565
enum: ['unknown', 'indoor', 'outdoor', 'mobile']
6666
},
6767
grouptag: {
68-
type: String,
68+
type: [String], // Default value for array is [] (empty array)
6969
trim: true,
7070
required: false
7171
},
@@ -880,7 +880,7 @@ boxSchema.methods.updateBox = function updateBox (args) {
880880
// only grouptag, description and weblink can removed through setting them to empty string ('')
881881
for (const prop of ['name', 'exposure', 'grouptag', 'description', 'weblink', 'image', 'integrations.mqtt', 'integrations.ttn', 'model', 'useAuth']) {
882882
if (typeof args[prop] !== 'undefined') {
883-
box.set(prop, (args[prop] === '' ? undefined : args[prop]));
883+
box.set(prop, ((args[prop] === '' || (Array.isArray(args[prop]) && args[prop].length === 0)) ? undefined : args[prop]));
884884
}
885885
}
886886

@@ -938,16 +938,20 @@ boxSchema.methods.getLocations = function getLocations ({ format, fromDate, toDa
938938
};
939939

940940
const buildFindBoxesQuery = function buildFindBoxesQuery (opts = {}) {
941-
const { phenomenon, fromDate, toDate, bbox, near, maxDistance } = opts,
941+
const { phenomenon, fromDate, toDate, bbox, near, maxDistance, grouptag } = opts,
942942
query = {};
943943

944944
// simple string parameters
945-
for (const param of ['exposure', 'model', 'grouptag']) {
945+
for (const param of ['exposure', 'model']) {
946946
if (opts[param]) {
947947
query[param] = { '$in': opts[param] };
948948
}
949949
}
950950

951+
if (grouptag) {
952+
query['grouptag'] = { '$all': grouptag };
953+
}
954+
951955
// bbox search parameter
952956
if (bbox) {
953957
query['locations'] = { '$geoWithin': { '$geometry': bbox } };

packages/models/test/tests/1-box.js

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ describe('Box model', function () {
4343
.then(shouldBeABoxWithSecrets)
4444
.then(function (box) {
4545
expect(box.name).equal('testSensebox');
46-
expect(box.grouptag).not.exist;
46+
expect(box.grouptag).to.be.an('array').that.is.empty;
4747
expect(box.model).equal('homeEthernet');
4848

4949
expect(box.integrations.mqtt.enabled).false;
@@ -60,7 +60,7 @@ describe('Box model', function () {
6060
it('should persist integrations and other properties upon creation', function () {
6161
const box = senseBox({
6262
name: 'integrationsbox',
63-
grouptag: 'grouptagTest',
63+
grouptag: ['grouptagTest'],
6464
exposure: 'outdoor',
6565
ttn: {
6666
dev_id: 'test_devid',
@@ -88,7 +88,8 @@ describe('Box model', function () {
8888
.then(function ({ integrations, name, grouptag, exposure }) {
8989
expect(name).equal('integrationsbox');
9090

91-
expect(grouptag).equal('grouptagTest');
91+
// expect(grouptag).equal(['grouptagTest']);
92+
expect(grouptag).to.be.an('array').that.include('grouptagTest');
9293

9394
expect(exposure).equal('outdoor');
9495

@@ -560,7 +561,7 @@ describe('Box model', function () {
560561
}) {
561562
expect(name).equal(updatePayload.name);
562563
expect(exposure).equal(updatePayload.exposure);
563-
expect(grouptag).equal(updatePayload.grouptag);
564+
expect(grouptag).to.be.an('array').that.include(updatePayload.grouptag);
564565
expect(weblink).equal(updatePayload.weblink);
565566
expect(description).equal(updatePayload.description);
566567
expect(model).equal(updatePayload.model);
@@ -616,11 +617,11 @@ describe('Box model', function () {
616617
return Box.findById(box._id);
617618
})
618619
.then(function (box) {
619-
expect(box.grouptag).equal(updatePayload.grouptag);
620+
expect(box.grouptag).to.be.an('array').that.include(updatePayload.grouptag);
620621
expect(box.weblink).equal(updatePayload.weblink);
621622
expect(box.description).equal(updatePayload.description);
622623

623-
updatePayload.grouptag = '';
624+
updatePayload.grouptag = [];
624625
updatePayload.weblink = '';
625626
updatePayload.description = '';
626627

@@ -630,7 +631,7 @@ describe('Box model', function () {
630631
return Box.findById(box._id);
631632
})
632633
.then(function ({ grouptag, weblink, description }) {
633-
expect(grouptag).not.exist;
634+
expect(grouptag).to.be.an('array').that.is.empty;
634635
expect(weblink).not.exist;
635636
expect(description).not.exist;
636637
});

tests/data/senseBoxSchema.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ module.exports = {
1717
'type': 'string'
1818
},
1919
'grouptag': {
20-
'type': 'string'
20+
'type': ['array', 'string'],
21+
'items': {
22+
'type': 'string'
23+
}
2124
},
2225
'exposure': {
2326
'type': 'string'

tests/tests/002-location_tests.js

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,25 @@ const minimalSensebox = function minimalSensebox (location = [123, 12, 34], expo
2626
describe('openSenseMap API locations tests', function () {
2727
let authHeader, authHeaderBox, csvAndAuthHeader, box, submitTimeLoc1;
2828

29-
before('add test user', function (done) {
29+
before('add test user', function () {
3030
const user = { name: 'locationtestuser', email: '[email protected]', password: '12345678' };
3131

32-
chakram.post(`${process.env.OSEM_TEST_BASE_URL}/users/register`, user)
32+
return chakram.post(`${process.env.OSEM_TEST_BASE_URL}/users/register`, user)
3333
.then(logResponseIfError)
3434
.then(function (response) {
3535
expect(response.body.token).to.exist;
3636
authHeader = { headers: { 'Authorization': `Bearer ${response.body.token}` } };
37-
done();
37+
38+
return chakram.wait();
3839
});
3940
});
4041

41-
after('delete user', function (done) {
42-
chakram.delete(`${process.env.OSEM_TEST_BASE_URL}/users/me`, { password: '12345678' }, authHeader)
42+
after('delete user', function () {
43+
return chakram.delete(`${process.env.OSEM_TEST_BASE_URL}/users/me`, { password: '12345678' }, authHeader)
4344
.then(logResponseIfError)
44-
.then(() => done());
45+
.then(() => {
46+
return chakram.wait();
47+
});
4548
});
4649

4750
describe('location validation', function () {
@@ -115,6 +118,7 @@ describe('openSenseMap API locations tests', function () {
115118

116119
return chakram.wait();
117120
});
121+
// .then(done, done);
118122
});
119123

120124
it('should allow to set the location for a new box as latLng object', function () {
@@ -217,15 +221,17 @@ describe('openSenseMap API locations tests', function () {
217221
let BASE_URL = `${process.env.OSEM_TEST_BASE_URL}/boxes`;
218222
let result;
219223

220-
before('get box', function (done) {
224+
before('get box', function () {
221225
BASE_URL = `${BASE_URL}/${box._id}`; // need to append at test runtime, not at parsetime
222226

223-
chakram.get(BASE_URL)
227+
return chakram.get(BASE_URL)
224228
.then(logResponseIfError)
225229
.then(function (response) {
226230
expect(response).to.have.status(200);
227231
result = response.body;
228-
done();
232+
// done();
233+
234+
return chakram.wait();
229235
});
230236
});
231237

tests/tests/005-create-boxes-test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ describe('openSenseMap API Routes: /boxes', function () {
538538
expect(response).to.have.status(200);
539539
expect(response).to.comprise.of.json('data.name', update_payload.name);
540540
expect(response).to.comprise.of.json('data.exposure', update_payload.exposure);
541-
expect(response).to.comprise.of.json('data.grouptag', update_payload.grouptag);
541+
expect(response.body.data.grouptag).to.be.an('array').that.include(update_payload.grouptag);
542542
expect(response).to.comprise.of.json('data.description', update_payload.description);
543543
expect(response).to.comprise.of.json('data.currentLocation', {
544544
type: 'Point',
@@ -676,7 +676,7 @@ describe('openSenseMap API Routes: /boxes', function () {
676676
});
677677

678678
it('should allow to unset the grouptag, description and weblink of the box via PUT', function () {
679-
const update_payload = { grouptag: '', description: '', weblink: '' };
679+
const update_payload = { grouptag: [], description: '', weblink: '' };
680680

681681
return chakram.put(`${BASE_URL}/boxes/${boxIds[1]}`, update_payload, { headers: { 'Authorization': `Bearer ${jwt2}` } })
682682
.then(function (response) {

0 commit comments

Comments
 (0)