@researchdatabox/sails-hook-redbox-storage-mongo 1.4.9 → 1.5.1
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/.github/dependabot.yml +12 -0
- package/README.md +0 -0
- package/api/models/DeletedRecord.js +0 -0
- package/api/models/Record.js +0 -0
- package/api/models/RecordAudit.js +0 -0
- package/api/services/MongoStorageService.js +44 -41
- package/config/record.js +0 -0
- package/config/storage.js +0 -0
- package/index.js +0 -0
- package/package.json +29 -18
- package/test/unit/.mocharc.js +21 -0
- package/test/unit/bootstrap.js +63 -0
- package/test/unit/db/storage.test.js +121 -0
- package/transformer/ExportJSONTransformer.js +2 -2
- package/tsconfig.json +0 -0
- package/typescript/api/services/MongoStorageService.ts +60 -31
- package/typescript/transformer/ExportJSONTransformer.ts +5 -5
- package/test/bootstrap.js +0 -65
package/README.md
CHANGED
|
File without changes
|
|
File without changes
|
package/api/models/Record.js
CHANGED
|
File without changes
|
|
File without changes
|
|
@@ -12,8 +12,9 @@ var __await = (this && this.__await) || function (v) { return this instanceof __
|
|
|
12
12
|
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
|
|
13
13
|
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
14
14
|
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
|
15
|
-
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
|
|
16
|
-
function
|
|
15
|
+
return i = {}, verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
|
|
16
|
+
function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }
|
|
17
|
+
function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }
|
|
17
18
|
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
|
|
18
19
|
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
|
|
19
20
|
function fulfill(value) { resume("next", value); }
|
|
@@ -22,9 +23,9 @@ var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _ar
|
|
|
22
23
|
};
|
|
23
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
25
|
exports.Services = void 0;
|
|
25
|
-
const
|
|
26
|
+
const rxjs_1 = require("rxjs");
|
|
26
27
|
const uuid_1 = require("uuid");
|
|
27
|
-
const
|
|
28
|
+
const luxon_1 = require("luxon");
|
|
28
29
|
const mongodb = require("mongodb");
|
|
29
30
|
const util = require("util");
|
|
30
31
|
const stream = require("stream");
|
|
@@ -151,8 +152,14 @@ var Services;
|
|
|
151
152
|
response.success = true;
|
|
152
153
|
}
|
|
153
154
|
catch (err) {
|
|
154
|
-
sails.log.error(`${this.logHeader} Failed to save update to MongoDB
|
|
155
|
-
|
|
155
|
+
sails.log.error(`${this.logHeader} Failed to save update to MongoDB: ${JSON.stringify({
|
|
156
|
+
error: err,
|
|
157
|
+
response: response,
|
|
158
|
+
brand: brand,
|
|
159
|
+
oid: oid,
|
|
160
|
+
record: record,
|
|
161
|
+
user: user,
|
|
162
|
+
})}`);
|
|
156
163
|
response.success = false;
|
|
157
164
|
response.message = err;
|
|
158
165
|
}
|
|
@@ -199,28 +206,24 @@ var Services;
|
|
|
199
206
|
provideUserAccessAndRemovePendingAccess(oid, userid, pendingValue) {
|
|
200
207
|
const batchFn = () => __awaiter(this, void 0, void 0, function* () {
|
|
201
208
|
const metadata = yield this.getMeta(oid);
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
metadata
|
|
212
|
-
metadata
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
metadata['authorization']['viewPending'] = pendingViewArray;
|
|
223
|
-
metadata['authorization']['view'] = viewArray;
|
|
209
|
+
const pendingEditArray = _.get(metadata, 'authorization.editPending', []);
|
|
210
|
+
const editArray = _.get(metadata, 'authorization.edit', []);
|
|
211
|
+
const pendingEditArrayFiltered = pendingEditArray.filter(value => value !== pendingValue);
|
|
212
|
+
const pendingEditFound = pendingEditArray.length > pendingEditArrayFiltered.length;
|
|
213
|
+
if (pendingEditFound && !editArray.includes(userid)) {
|
|
214
|
+
editArray.push(userid);
|
|
215
|
+
}
|
|
216
|
+
_.set(metadata, 'authorization.editPending', pendingEditArrayFiltered);
|
|
217
|
+
_.set(metadata, 'authorization.edit', editArray);
|
|
218
|
+
const pendingViewArray = _.get(metadata, 'authorization.viewPending', []);
|
|
219
|
+
const viewArray = _.get(metadata, 'authorization.view', []);
|
|
220
|
+
const pendingViewArrayFiltered = pendingViewArray.filter(value => value !== pendingValue);
|
|
221
|
+
const pendingViewFound = pendingViewArray.length > pendingViewArrayFiltered.length;
|
|
222
|
+
if (pendingViewFound && !viewArray.includes(userid)) {
|
|
223
|
+
viewArray.push(userid);
|
|
224
|
+
}
|
|
225
|
+
_.set(metadata, 'authorization.viewPending', pendingViewArrayFiltered);
|
|
226
|
+
_.set(metadata, 'authorization.view', viewArray);
|
|
224
227
|
try {
|
|
225
228
|
yield this.updateMeta(null, oid, metadata);
|
|
226
229
|
}
|
|
@@ -231,8 +234,8 @@ var Services;
|
|
|
231
234
|
});
|
|
232
235
|
batchFn();
|
|
233
236
|
}
|
|
234
|
-
getRelatedRecords(
|
|
235
|
-
return __awaiter(this,
|
|
237
|
+
getRelatedRecords(oid_1, brand_1) {
|
|
238
|
+
return __awaiter(this, arguments, void 0, function* (oid, brand, recordTypeName = null, mappingContext = null) {
|
|
236
239
|
let record = yield this.getMeta(oid);
|
|
237
240
|
if (_.isEmpty(recordTypeName)) {
|
|
238
241
|
recordTypeName = record['metaMetadata']['type'];
|
|
@@ -284,8 +287,8 @@ var Services;
|
|
|
284
287
|
return mappingContext;
|
|
285
288
|
});
|
|
286
289
|
}
|
|
287
|
-
delete(
|
|
288
|
-
return __awaiter(this,
|
|
290
|
+
delete(oid_1) {
|
|
291
|
+
return __awaiter(this, arguments, void 0, function* (oid, permanentlyDelete = false) {
|
|
289
292
|
const response = new redbox_core_types_1.StorageServiceResponse();
|
|
290
293
|
try {
|
|
291
294
|
if (permanentlyDelete) {
|
|
@@ -333,7 +336,7 @@ var Services;
|
|
|
333
336
|
const logName = _.get(options, 'logName', null);
|
|
334
337
|
if (logName) {
|
|
335
338
|
let log = _.get(record, logName, null);
|
|
336
|
-
const entry = { date:
|
|
339
|
+
const entry = { date: luxon_1.DateTime.now().toFormat("yyyy-LL-dd'T'HH:mm:ss") };
|
|
337
340
|
if (log) {
|
|
338
341
|
log.push(entry);
|
|
339
342
|
}
|
|
@@ -367,8 +370,8 @@ var Services;
|
|
|
367
370
|
return record;
|
|
368
371
|
});
|
|
369
372
|
}
|
|
370
|
-
getDeletedRecords(
|
|
371
|
-
return __awaiter(this,
|
|
373
|
+
getDeletedRecords(workflowState_1) {
|
|
374
|
+
return __awaiter(this, arguments, void 0, function* (workflowState, recordType = undefined, start, rows = 10, username, roles, brand, editAccessOnly = undefined, packageType = undefined, sort = undefined, filterFields = undefined, filterString = undefined, filterMode = 'regex') {
|
|
372
375
|
let query = {
|
|
373
376
|
"deletedRecordMetadata.metaMetadata.brandId": brand.id
|
|
374
377
|
};
|
|
@@ -446,8 +449,8 @@ var Services;
|
|
|
446
449
|
return response;
|
|
447
450
|
});
|
|
448
451
|
}
|
|
449
|
-
getRecords(
|
|
450
|
-
return __awaiter(this,
|
|
452
|
+
getRecords(workflowState_1) {
|
|
453
|
+
return __awaiter(this, arguments, void 0, function* (workflowState, recordType = undefined, start, rows = 10, username, roles, brand, editAccessOnly = undefined, packageType = undefined, sort = undefined, filterFields = undefined, filterString = undefined, filterMode = undefined, secondarySort = undefined) {
|
|
451
454
|
if (_.isUndefined(filterMode) || _.isNull(filterMode) || _.isEmpty(filterMode)) {
|
|
452
455
|
filterMode = 'regex';
|
|
453
456
|
}
|
|
@@ -563,8 +566,8 @@ var Services;
|
|
|
563
566
|
return { items: yield this.deletedRecordCol.find(query, options).toArray(), totalItems: yield this.deletedRecordCol.count(query) };
|
|
564
567
|
});
|
|
565
568
|
}
|
|
566
|
-
fetchAllRecords(
|
|
567
|
-
return __asyncGenerator(this, arguments, function* fetchAllRecords_1() {
|
|
569
|
+
fetchAllRecords(query_1, options_1) {
|
|
570
|
+
return __asyncGenerator(this, arguments, function* fetchAllRecords_1(query, options, stringifyJSON = false) {
|
|
568
571
|
let skip = 0;
|
|
569
572
|
let limit = options.limit;
|
|
570
573
|
options.skip = skip;
|
|
@@ -689,9 +692,9 @@ var Services;
|
|
|
689
692
|
reqs.push(this.addAndRemoveDatastreams(oid, fileIdsAdded, removeIds));
|
|
690
693
|
}));
|
|
691
694
|
if (_.isEmpty(reqs)) {
|
|
692
|
-
reqs.push(
|
|
695
|
+
reqs.push((0, rxjs_1.of)({ "request": "dummy" }));
|
|
693
696
|
}
|
|
694
|
-
return
|
|
697
|
+
return (0, rxjs_1.of)(reqs);
|
|
695
698
|
});
|
|
696
699
|
}
|
|
697
700
|
removeDatastream(oid, datastream) {
|
package/config/record.js
CHANGED
|
File without changes
|
package/config/storage.js
CHANGED
|
File without changes
|
package/index.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@researchdatabox/sails-hook-redbox-storage-mongo",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"description": "A MongoDB storage plugin for ReDBox.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"sails": {
|
|
@@ -11,9 +11,16 @@
|
|
|
11
11
|
"url": "https://github.com/redbox-mint/sails-hook-redbox-storage-mongo.git"
|
|
12
12
|
},
|
|
13
13
|
"scripts": {
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
14
|
+
"compile": "./node_modules/typescript/bin/tsc -p tsconfig.json",
|
|
15
|
+
"dev:run": "docker compose -f ./support/docker-compose.yml -f ./support/docker-compose.dev.yml up --menu=false --remove-orphans --abort-on-container-exit --exit-code-from rbportal",
|
|
16
|
+
"predev:run": "npm install --ignore-scripts && npm run compile",
|
|
17
|
+
"dev:clean": "docker compose -f ./support/docker-compose.yml -f ./support/docker-compose.dev.yml down",
|
|
18
|
+
"dev:logs": "docker compose -f ./support/docker-compose.yml -f ./support/docker-compose.dev.yml logs",
|
|
19
|
+
"dev:removedata": "docker compose -f ./support/docker-compose.yml -f ./support/docker-compose.dev.yml down -v",
|
|
20
|
+
"test": "docker compose -f ./support/docker-compose.yml -f ./support/docker-compose.mocha.yml up --menu=false --abort-on-container-exit --exit-code-from rbportal",
|
|
21
|
+
"pretest": "npm install --ignore-scripts && npm run compile",
|
|
22
|
+
"posttest": "npm run test:clean",
|
|
23
|
+
"test:clean": "docker compose -f ./support/docker-compose.yml -f ./support/docker-compose.mocha.yml down -v"
|
|
17
24
|
},
|
|
18
25
|
"keywords": [
|
|
19
26
|
"sails",
|
|
@@ -26,27 +33,31 @@
|
|
|
26
33
|
"author": "QCIF Engineering dev@redboxresearchdata.com.au",
|
|
27
34
|
"license": "GPL-3.0",
|
|
28
35
|
"devDependencies": {
|
|
29
|
-
"@researchdatabox/redbox-core-types": "^1.
|
|
30
|
-
"@types/chai": "
|
|
31
|
-
"@types/lodash": "
|
|
32
|
-
"@types/mocha": "
|
|
33
|
-
"
|
|
36
|
+
"@researchdatabox/redbox-core-types": "^1.5.0",
|
|
37
|
+
"@types/chai": "5.2.2",
|
|
38
|
+
"@types/lodash": "4.17.17",
|
|
39
|
+
"@types/mocha": "10.0.10",
|
|
40
|
+
"@types/node": "20.17.51",
|
|
41
|
+
"chai": "5.2.0",
|
|
34
42
|
"fs": "0.0.1-security",
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"util": "^0.12.4"
|
|
43
|
+
"luxon": "^3.7.1",
|
|
44
|
+
"mocha": "11.5.0",
|
|
45
|
+
"mocha-junit-reporter": "2.2.1",
|
|
46
|
+
"mongodb": "6.16.0",
|
|
47
|
+
"sails": "1.5.14",
|
|
48
|
+
"stream": "0.0.3",
|
|
49
|
+
"typescript": "5.5.4",
|
|
50
|
+
"util": "0.12.5"
|
|
44
51
|
},
|
|
45
52
|
"dependencies": {
|
|
46
53
|
"json2csv": "^5.0.3",
|
|
47
54
|
"lodash": "^4.17.21",
|
|
48
55
|
"uuid": "8.3.0"
|
|
49
56
|
},
|
|
57
|
+
"peerDependencies": {
|
|
58
|
+
"luxon": ">=3.0.0",
|
|
59
|
+
"rxjs": ">=7.0.0"
|
|
60
|
+
},
|
|
50
61
|
"publishConfig": {
|
|
51
62
|
"access": "public"
|
|
52
63
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
require: "chai",
|
|
5
|
+
recursive: true,
|
|
6
|
+
slow: 2000,
|
|
7
|
+
timeout: "20s",
|
|
8
|
+
ui: "bdd",
|
|
9
|
+
global: ["sails", "moment", "_", "expect"],
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
if (process.env.CI === "true") {
|
|
13
|
+
console.log("Mocha running in CI.");
|
|
14
|
+
// (For CI) Run mocha and write results to a junit format file:
|
|
15
|
+
module.exports["reporter"] = "mocha-junit-reporter";
|
|
16
|
+
module.exports["reporter-option"] = "mochaFile=/opt/redbox-portal/node_modules/@researchdatabox/sails-hook-redbox-storage-mongo/support/junit/unit-mocha.xml";
|
|
17
|
+
} else {
|
|
18
|
+
console.log("Mocha running in local dev.");
|
|
19
|
+
// (For development) Run mocha and show the results on stdout:
|
|
20
|
+
module.exports["reporter"] = "spec";
|
|
21
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
var sails = require("sails");
|
|
2
|
+
var _ = require("lodash");
|
|
3
|
+
|
|
4
|
+
global.moment = require("moment");
|
|
5
|
+
global.sails = sails;
|
|
6
|
+
global._ = _;
|
|
7
|
+
|
|
8
|
+
/* global before, after */
|
|
9
|
+
|
|
10
|
+
before(function (done) {
|
|
11
|
+
import("chai").then((chai) => {
|
|
12
|
+
global.chai = chai;
|
|
13
|
+
global.should = chai.should();
|
|
14
|
+
global.expect = chai.expect;
|
|
15
|
+
|
|
16
|
+
// Set the timeout so that Sails has enough time to lift.
|
|
17
|
+
this.timeout(60000);
|
|
18
|
+
sails.lift({
|
|
19
|
+
log: {
|
|
20
|
+
level: "verbose",
|
|
21
|
+
},
|
|
22
|
+
hooks: {
|
|
23
|
+
grunt: false,
|
|
24
|
+
},
|
|
25
|
+
models: {
|
|
26
|
+
datastore: "mongodb",
|
|
27
|
+
migrate: "drop",
|
|
28
|
+
},
|
|
29
|
+
datastores: {
|
|
30
|
+
mongodb: {
|
|
31
|
+
adapter: require('sails-mongo'),
|
|
32
|
+
url: "mongodb://mongodb:27017/redbox-portal"
|
|
33
|
+
},
|
|
34
|
+
redboxStorage: {
|
|
35
|
+
adapter: require('sails-mongo'),
|
|
36
|
+
url: 'mongodb://mongodb:27017/redbox-storage'
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
security: {
|
|
40
|
+
csrf: false,
|
|
41
|
+
},
|
|
42
|
+
auth: {
|
|
43
|
+
default: {
|
|
44
|
+
local: {
|
|
45
|
+
default: {
|
|
46
|
+
token: "auth-default-local-default-token",
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
}, function (err, server) {
|
|
52
|
+
if (err) return done(err);
|
|
53
|
+
done(err, sails);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
after(function (done) {
|
|
59
|
+
// here you can clear fixtures, etc.
|
|
60
|
+
if (sails && _.isFunction(sails.lower)) {
|
|
61
|
+
sails.lower(done);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
const service = require("../../../api/services/MongoStorageService");
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
/* global describe, it, expect */
|
|
5
|
+
|
|
6
|
+
async function sleep(ms = 300) {
|
|
7
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
describe("Records", function () {
|
|
11
|
+
[
|
|
12
|
+
{
|
|
13
|
+
// missing 'editPending' does not cause error
|
|
14
|
+
args: {
|
|
15
|
+
record: {
|
|
16
|
+
metadata: {},
|
|
17
|
+
"authorization": {
|
|
18
|
+
"viewRoles": ["Admin", "Librarians"],
|
|
19
|
+
"editRoles": ["Admin", "Librarians"],
|
|
20
|
+
"view": ["example-2@redboxresearchdata.com.au"],
|
|
21
|
+
"edit": [],
|
|
22
|
+
"viewPending": ["example-1@redboxresearchdata.com.au"]
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
expected: {
|
|
27
|
+
record: {
|
|
28
|
+
"authorization": {
|
|
29
|
+
"viewRoles": ["Admin", "Librarians"],
|
|
30
|
+
"editRoles": ["Admin", "Librarians"],
|
|
31
|
+
"view": ["example-2@redboxresearchdata.com.au", "example-1@redboxresearchdata.com.au"],
|
|
32
|
+
"edit": [],
|
|
33
|
+
"viewPending": [],
|
|
34
|
+
"editPending": [],
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
// duplicate entries in pending array are transformed to in one entry in real access array
|
|
41
|
+
args: {
|
|
42
|
+
record: {
|
|
43
|
+
metadata: {},
|
|
44
|
+
"authorization": {
|
|
45
|
+
"viewRoles": ["Admin", "Librarians"],
|
|
46
|
+
"editRoles": ["Admin", "Librarians"],
|
|
47
|
+
"view": ["example-2@redboxresearchdata.com.au"],
|
|
48
|
+
"edit": [],
|
|
49
|
+
"viewPending": [],
|
|
50
|
+
"editPending": ["example-1@redboxresearchdata.com.au", "example-1@redboxresearchdata.com.au"],
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
expected: {
|
|
55
|
+
record: {
|
|
56
|
+
"authorization": {
|
|
57
|
+
"viewRoles": ["Admin", "Librarians"],
|
|
58
|
+
"editRoles": ["Admin", "Librarians"],
|
|
59
|
+
"view": ["example-2@redboxresearchdata.com.au"],
|
|
60
|
+
"edit": ["example-1@redboxresearchdata.com.au"],
|
|
61
|
+
"viewPending": [],
|
|
62
|
+
"editPending": [],
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
// same entry in real access array and pending is removed from pending array
|
|
69
|
+
args: {
|
|
70
|
+
record: {
|
|
71
|
+
metadata: {},
|
|
72
|
+
"authorization": {
|
|
73
|
+
"viewRoles": ["Admin", "Librarians"],
|
|
74
|
+
"editRoles": ["Admin", "Librarians"],
|
|
75
|
+
"view": ["example-2@redboxresearchdata.com.au"],
|
|
76
|
+
"edit": ["example-1@redboxresearchdata.com.au"],
|
|
77
|
+
"viewPending": [],
|
|
78
|
+
"editPending": ["example-1@redboxresearchdata.com.au"],
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
expected: {
|
|
83
|
+
record: {
|
|
84
|
+
"authorization": {
|
|
85
|
+
"viewRoles": ["Admin", "Librarians"],
|
|
86
|
+
"editRoles": ["Admin", "Librarians"],
|
|
87
|
+
"view": ["example-2@redboxresearchdata.com.au"],
|
|
88
|
+
"edit": ["example-1@redboxresearchdata.com.au"],
|
|
89
|
+
"viewPending": [],
|
|
90
|
+
"editPending": [],
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
}
|
|
95
|
+
].forEach(({args, expected}) => {
|
|
96
|
+
it(`should provideUserAccessAndRemovePendingAccess as expected '${JSON.stringify(args)}' = ${JSON.stringify(expected)}`, async function () {
|
|
97
|
+
|
|
98
|
+
const brand = 'testing-brand';
|
|
99
|
+
const record = args.record;
|
|
100
|
+
const recordType = "rdmp";
|
|
101
|
+
|
|
102
|
+
const response = await service.create(brand, record, recordType);
|
|
103
|
+
|
|
104
|
+
expect(response.oid).to.have.lengthOf(32);
|
|
105
|
+
|
|
106
|
+
const oid = response.oid;
|
|
107
|
+
const userid = "example-1@redboxresearchdata.com.au";
|
|
108
|
+
const pendingValue = "example-1@redboxresearchdata.com.au";
|
|
109
|
+
|
|
110
|
+
service.provideUserAccessAndRemovePendingAccess(oid, userid, pendingValue);
|
|
111
|
+
// TODO: provideUserAccessAndRemovePendingAccess is a sync method, but it calls async methods.
|
|
112
|
+
// So, wait for a bit for the method to complete.
|
|
113
|
+
// This means that any errors may not be raised, as they occur in an untracked async function.
|
|
114
|
+
await sleep(5000);
|
|
115
|
+
|
|
116
|
+
const result = await service.getMeta(oid);
|
|
117
|
+
|
|
118
|
+
expect(result.authorization).to.eql(expected.record.authorization);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
});
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const { Transform } = require('stream');
|
|
4
|
-
const
|
|
4
|
+
const luxon_1 = require("luxon");
|
|
5
5
|
class ExportJSONTransformer extends Transform {
|
|
6
6
|
constructor(recordtype, modifiedBefore, modifiedAfter) {
|
|
7
7
|
super();
|
|
8
8
|
this.first = true;
|
|
9
|
-
this.push(`{ "recordType": "${recordtype}",\n "dateGenerated": "${
|
|
9
|
+
this.push(`{ "recordType": "${recordtype}",\n "dateGenerated": "${luxon_1.DateTime.now().toISO()}",\n`);
|
|
10
10
|
if (!_.isEmpty(modifiedBefore) || !_.isEmpty(modifiedAfter)) {
|
|
11
11
|
this.push(`"dateModifiedRange": ${this.getDateModifiedRangeObject(modifiedBefore, modifiedAfter)},\n`);
|
|
12
12
|
}
|
package/tsconfig.json
CHANGED
|
File without changes
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Observable
|
|
3
|
-
} from 'rxjs/Rx';
|
|
1
|
+
import { Observable, of } from 'rxjs';
|
|
4
2
|
|
|
5
3
|
import { Sails, Model } from "sails";
|
|
6
4
|
import { v1 as uuidv1 } from 'uuid';
|
|
7
|
-
import
|
|
5
|
+
import { DateTime } from 'luxon';
|
|
8
6
|
|
|
9
7
|
import mongodb = require('mongodb');
|
|
10
8
|
import util = require('util');
|
|
@@ -162,8 +160,14 @@ export module Services {
|
|
|
162
160
|
await Record.updateOne({ redboxOid: oid }).set(record);
|
|
163
161
|
response.success = true;
|
|
164
162
|
} catch (err) {
|
|
165
|
-
sails.log.error(`${this.logHeader} Failed to save update to MongoDB
|
|
166
|
-
|
|
163
|
+
sails.log.error(`${this.logHeader} Failed to save update to MongoDB: ${JSON.stringify({
|
|
164
|
+
error: err,
|
|
165
|
+
response: response,
|
|
166
|
+
brand: brand,
|
|
167
|
+
oid: oid,
|
|
168
|
+
record: record,
|
|
169
|
+
user: user,
|
|
170
|
+
})}`);
|
|
167
171
|
response.success = false;
|
|
168
172
|
response.message = err;
|
|
169
173
|
}
|
|
@@ -208,33 +212,55 @@ export module Services {
|
|
|
208
212
|
return response;
|
|
209
213
|
}
|
|
210
214
|
|
|
215
|
+
/**
|
|
216
|
+
* If pendingValue is in editPending or viewPending, remove all instances from the pending arrays and
|
|
217
|
+
* put the userid in the matching access / non-pending array, then save the changes to the storage.
|
|
218
|
+
*
|
|
219
|
+
* Implementation Note: This is a sync method, but it calls async methods.
|
|
220
|
+
* This means that the storage will not be updated when this method returns, but at some point later.
|
|
221
|
+
*
|
|
222
|
+
* @param oid The record identifier.
|
|
223
|
+
* @param userid The value to put in the matching access / non-pending arrays.
|
|
224
|
+
* @param pendingValue The value to find in the pending arrays.
|
|
225
|
+
*/
|
|
211
226
|
public provideUserAccessAndRemovePendingAccess(oid, userid, pendingValue): void {
|
|
212
227
|
const batchFn = async () => {
|
|
213
228
|
const metadata = await this.getMeta(oid);
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
229
|
+
|
|
230
|
+
// Update edit authorization - remove pending edit access and add real edit access with userid
|
|
231
|
+
const pendingEditArray: string[] = _.get(metadata, 'authorization.editPending', []);
|
|
232
|
+
const editArray: string[] = _.get(metadata, 'authorization.edit', []);
|
|
233
|
+
|
|
234
|
+
// remove all items matching pendingValue from the pendingEditArray
|
|
235
|
+
const pendingEditArrayFiltered = pendingEditArray.filter(value => value !== pendingValue);
|
|
236
|
+
const pendingEditFound = pendingEditArray.length > pendingEditArrayFiltered.length;
|
|
237
|
+
|
|
238
|
+
// add the item to the editArray if it existed in the pendingEditArray, and it is not in the editArray
|
|
239
|
+
if (pendingEditFound && !editArray.includes(userid)) {
|
|
240
|
+
editArray.push(userid);
|
|
223
241
|
}
|
|
224
|
-
|
|
225
|
-
metadata
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
242
|
+
|
|
243
|
+
// update the metadata with the modified arrays
|
|
244
|
+
_.set(metadata, 'authorization.editPending', pendingEditArrayFiltered);
|
|
245
|
+
_.set(metadata, 'authorization.edit', editArray);
|
|
246
|
+
|
|
247
|
+
// Update view authorization - remove pending view access and add real view access with userid
|
|
248
|
+
const pendingViewArray: string[] = _.get(metadata, 'authorization.viewPending', []);
|
|
249
|
+
const viewArray: string[] = _.get(metadata, 'authorization.view', []);
|
|
250
|
+
|
|
251
|
+
// remove all items matching pendingValue from the pendingViewArray
|
|
252
|
+
const pendingViewArrayFiltered = pendingViewArray.filter(value => value !== pendingValue);
|
|
253
|
+
const pendingViewFound = pendingViewArray.length > pendingViewArrayFiltered.length;
|
|
254
|
+
|
|
255
|
+
// add the item to the viewArray if it existed in the pendingViewArray, and it is not in the viewArray
|
|
256
|
+
if (pendingViewFound && !viewArray.includes(userid)) {
|
|
257
|
+
viewArray.push(userid);
|
|
235
258
|
}
|
|
236
|
-
|
|
237
|
-
metadata
|
|
259
|
+
|
|
260
|
+
// update the metadata with the modified arrays
|
|
261
|
+
_.set(metadata, 'authorization.viewPending', pendingViewArrayFiltered);
|
|
262
|
+
_.set(metadata, 'authorization.view', viewArray);
|
|
263
|
+
|
|
238
264
|
try {
|
|
239
265
|
await this.updateMeta(null, oid, metadata);
|
|
240
266
|
} catch (err) {
|
|
@@ -242,6 +268,8 @@ export module Services {
|
|
|
242
268
|
sails.log.error(JSON.stringify(err));
|
|
243
269
|
}
|
|
244
270
|
};
|
|
271
|
+
|
|
272
|
+
// TODO: Fix this so that the method only returns after the storage is updated.
|
|
245
273
|
batchFn();
|
|
246
274
|
}
|
|
247
275
|
|
|
@@ -345,7 +373,8 @@ export module Services {
|
|
|
345
373
|
const logName = _.get(options, 'logName', null);
|
|
346
374
|
if (logName) {
|
|
347
375
|
let log = _.get(record, logName, null);
|
|
348
|
-
|
|
376
|
+
// Use Luxon for ISO-like local timestamp without timezone offset
|
|
377
|
+
const entry = { date: DateTime.now().toFormat("yyyy-LL-dd'T'HH:mm:ss") };
|
|
349
378
|
if (log) {
|
|
350
379
|
log.push(entry);
|
|
351
380
|
} else {
|
|
@@ -733,9 +762,9 @@ export module Services {
|
|
|
733
762
|
reqs.push(this.addAndRemoveDatastreams(oid, fileIdsAdded, removeIds));
|
|
734
763
|
});
|
|
735
764
|
if (_.isEmpty(reqs)) {
|
|
736
|
-
reqs.push(
|
|
765
|
+
reqs.push(of({ "request": "dummy" }));
|
|
737
766
|
}
|
|
738
|
-
return
|
|
767
|
+
return of(reqs);
|
|
739
768
|
});
|
|
740
769
|
}
|
|
741
770
|
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
const { Transform } = require('stream');
|
|
4
|
+
import { DateTime } from 'luxon';
|
|
5
|
+
declare var require: any;
|
|
6
|
+
declare var module: any;
|
|
7
7
|
declare let sails, _;
|
|
8
8
|
|
|
9
9
|
class ExportJSONTransformer extends Transform {
|
|
10
10
|
first:boolean = true;
|
|
11
11
|
constructor(recordtype:string, modifiedBefore:string, modifiedAfter:string) {
|
|
12
12
|
super();
|
|
13
|
-
|
|
13
|
+
this.push(`{ "recordType": "${recordtype}",\n "dateGenerated": "${DateTime.now().toISO()}",\n`)
|
|
14
14
|
if(!_.isEmpty(modifiedBefore) || !_.isEmpty(modifiedAfter)) {
|
|
15
15
|
this.push(`"dateModifiedRange": ${this.getDateModifiedRangeObject(modifiedBefore, modifiedAfter)},\n`);
|
|
16
16
|
}
|
package/test/bootstrap.js
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
var Sails = require('sails').Sails;
|
|
2
|
-
|
|
3
|
-
describe('Bootstrap tests ::', function() {
|
|
4
|
-
// Var to hold a running sails app instance
|
|
5
|
-
var _sails;
|
|
6
|
-
var appPath = '/opt/redbox-portal'
|
|
7
|
-
|
|
8
|
-
// Before running any tests, attempt to lift Sails
|
|
9
|
-
before(function (done) {
|
|
10
|
-
|
|
11
|
-
// Hook will timeout in 10 seconds
|
|
12
|
-
this.timeout(11000);
|
|
13
|
-
|
|
14
|
-
// Attempt to lift sails
|
|
15
|
-
Sails().lift({
|
|
16
|
-
appPath: appPath,
|
|
17
|
-
models: {
|
|
18
|
-
migrate: 'drop'
|
|
19
|
-
},
|
|
20
|
-
datastores: {
|
|
21
|
-
mongodb: {
|
|
22
|
-
adapter: require(appPath+'/node_modules/sails-mongo'),
|
|
23
|
-
url: "mongodb://mongodb:27017/redbox-portal"
|
|
24
|
-
},
|
|
25
|
-
redboxStorage: {
|
|
26
|
-
adapter: require(appPath+'/node_modules/sails-mongo'),
|
|
27
|
-
url: 'mongodb://mongodb:27017/redbox-storage'
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
globals: {
|
|
31
|
-
sails: true,
|
|
32
|
-
_: require('lodash'),
|
|
33
|
-
async: require('async'),
|
|
34
|
-
models: true,
|
|
35
|
-
services: true
|
|
36
|
-
},
|
|
37
|
-
hooks: {
|
|
38
|
-
// Skip grunt (unless your hook uses it)
|
|
39
|
-
"grunt": false
|
|
40
|
-
},
|
|
41
|
-
log: {level: "verbose"}
|
|
42
|
-
},function (err, __sails) {
|
|
43
|
-
if (err) return done(err);
|
|
44
|
-
_sails = __sails;
|
|
45
|
-
return done();
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
// After tests are complete, lower Sails
|
|
50
|
-
after(function (done) {
|
|
51
|
-
|
|
52
|
-
// Lower Sails (if it successfully lifted)
|
|
53
|
-
if (_sails) {
|
|
54
|
-
return _sails.lower(done);
|
|
55
|
-
}
|
|
56
|
-
// Otherwise just return
|
|
57
|
-
return done();
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
// Test that Sails can lift with the hook in place
|
|
61
|
-
it ('sails does not crash', function() {
|
|
62
|
-
return true;
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
});
|