@researchdatabox/sails-hook-redbox-storage-mongo 1.4.8 → 1.5.0

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.
@@ -0,0 +1,12 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "github-actions"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ target-branch: "master"
8
+ - package-ecosystem: "npm"
9
+ directory: "/"
10
+ schedule:
11
+ interval: "weekly"
12
+ target-branch: "master"
package/README.md CHANGED
File without changes
File without changes
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 verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
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); }
@@ -24,7 +25,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
24
25
  exports.Services = void 0;
25
26
  const Rx_1 = require("rxjs/Rx");
26
27
  const uuid_1 = require("uuid");
27
- const moment = require("moment");
28
+ const luxon_1 = require("luxon");
28
29
  const mongodb = require("mongodb");
29
30
  const util = require("util");
30
31
  const stream = require("stream");
@@ -146,12 +147,19 @@ var Services;
146
147
  _.unset(record, 'dateCreated');
147
148
  _.unset(record, 'lastSaveDate');
148
149
  _.unset(record, '_id');
150
+ _.unset(record, 'id');
149
151
  yield Record.updateOne({ redboxOid: oid }).set(record);
150
152
  response.success = true;
151
153
  }
152
154
  catch (err) {
153
- sails.log.error(`${this.logHeader} Failed to save update to MongoDB:`);
154
- sails.log.error(JSON.stringify(err));
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
+ })}`);
155
163
  response.success = false;
156
164
  response.message = err;
157
165
  }
@@ -198,28 +206,24 @@ var Services;
198
206
  provideUserAccessAndRemovePendingAccess(oid, userid, pendingValue) {
199
207
  const batchFn = () => __awaiter(this, void 0, void 0, function* () {
200
208
  const metadata = yield this.getMeta(oid);
201
- var pendingEditArray = metadata['authorization']['editPending'];
202
- var editArray = metadata['authorization']['edit'];
203
- for (var i = 0; i < pendingEditArray.length; i++) {
204
- if (pendingEditArray[i] == pendingValue) {
205
- pendingEditArray = pendingEditArray.filter(e => e !== pendingValue);
206
- editArray = editArray.filter(e => e !== userid);
207
- editArray.push(userid);
208
- }
209
- }
210
- metadata['authorization']['editPending'] = pendingEditArray;
211
- metadata['authorization']['edit'] = editArray;
212
- var pendingViewArray = metadata['authorization']['viewPending'];
213
- var viewArray = metadata['authorization']['view'];
214
- for (var i = 0; i < pendingViewArray.length; i++) {
215
- if (pendingViewArray[i] == pendingValue) {
216
- pendingViewArray = pendingViewArray.filter(e => e !== pendingValue);
217
- viewArray = viewArray.filter(e => e !== userid);
218
- viewArray.push(userid);
219
- }
220
- }
221
- metadata['authorization']['viewPending'] = pendingViewArray;
222
- 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);
223
227
  try {
224
228
  yield this.updateMeta(null, oid, metadata);
225
229
  }
@@ -230,8 +234,8 @@ var Services;
230
234
  });
231
235
  batchFn();
232
236
  }
233
- getRelatedRecords(oid, brand, recordTypeName = null, mappingContext = null) {
234
- return __awaiter(this, void 0, void 0, function* () {
237
+ getRelatedRecords(oid_1, brand_1) {
238
+ return __awaiter(this, arguments, void 0, function* (oid, brand, recordTypeName = null, mappingContext = null) {
235
239
  let record = yield this.getMeta(oid);
236
240
  if (_.isEmpty(recordTypeName)) {
237
241
  recordTypeName = record['metaMetadata']['type'];
@@ -283,8 +287,8 @@ var Services;
283
287
  return mappingContext;
284
288
  });
285
289
  }
286
- delete(oid, permanentlyDelete = false) {
287
- return __awaiter(this, void 0, void 0, function* () {
290
+ delete(oid_1) {
291
+ return __awaiter(this, arguments, void 0, function* (oid, permanentlyDelete = false) {
288
292
  const response = new redbox_core_types_1.StorageServiceResponse();
289
293
  try {
290
294
  if (permanentlyDelete) {
@@ -332,7 +336,7 @@ var Services;
332
336
  const logName = _.get(options, 'logName', null);
333
337
  if (logName) {
334
338
  let log = _.get(record, logName, null);
335
- const entry = { date: moment().format('YYYY-MM-DDTHH:mm:ss') };
339
+ const entry = { date: luxon_1.DateTime.now().toFormat("yyyy-LL-dd'T'HH:mm:ss") };
336
340
  if (log) {
337
341
  log.push(entry);
338
342
  }
@@ -366,8 +370,8 @@ var Services;
366
370
  return record;
367
371
  });
368
372
  }
369
- getDeletedRecords(workflowState, recordType = undefined, start, rows = 10, username, roles, brand, editAccessOnly = undefined, packageType = undefined, sort = undefined, filterFields = undefined, filterString = undefined, filterMode = 'regex') {
370
- return __awaiter(this, void 0, void 0, function* () {
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') {
371
375
  let query = {
372
376
  "deletedRecordMetadata.metaMetadata.brandId": brand.id
373
377
  };
@@ -445,8 +449,8 @@ var Services;
445
449
  return response;
446
450
  });
447
451
  }
448
- getRecords(workflowState, recordType = undefined, start, rows = 10, username, roles, brand, editAccessOnly = undefined, packageType = undefined, sort = undefined, filterFields = undefined, filterString = undefined, filterMode = undefined, secondarySort = undefined) {
449
- return __awaiter(this, void 0, void 0, function* () {
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) {
450
454
  if (_.isUndefined(filterMode) || _.isNull(filterMode) || _.isEmpty(filterMode)) {
451
455
  filterMode = 'regex';
452
456
  }
@@ -562,8 +566,8 @@ var Services;
562
566
  return { items: yield this.deletedRecordCol.find(query, options).toArray(), totalItems: yield this.deletedRecordCol.count(query) };
563
567
  });
564
568
  }
565
- fetchAllRecords(query, options, stringifyJSON = false) {
566
- 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) {
567
571
  let skip = 0;
568
572
  let limit = options.limit;
569
573
  options.skip = skip;
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.4.8",
3
+ "version": "1.5.0",
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
- "test": "NODE_ENV=test; mocha",
15
- "installHook": "docker run -v $(pwd):/opt/sailshook qcifengineering/redbox-portal /bin/bash -c 'cd /opt/redbox-portal;yarn add \"file:/opt/sailshook\"'; docker commit $(docker ps -lq) redboxportalwithhook",
16
- "runDev": "docker-compose -f support/development/docker-compose.yml up"
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,32 @@
26
33
  "author": "QCIF Engineering dev@redboxresearchdata.com.au",
27
34
  "license": "GPL-3.0",
28
35
  "devDependencies": {
29
- "@researchdatabox/redbox-core-types": "^1.4.3",
30
- "@types/chai": "^4.2.12",
31
- "@types/lodash": "^4.14.159",
32
- "@types/mocha": "^8.0.3",
33
- "chai": "^4.2.0",
36
+ "@researchdatabox/redbox-core-types": "1.4.8",
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
- "mocha": "^8.1.1",
36
- "moment": "^2.29.1",
37
- "mongodb": "^6.2.0",
38
- "rxjs": "^6.6.2",
39
- "rxjs-compat": "^6.6.7",
40
- "sails": "^1.2.5",
41
- "stream": "0.0.2",
42
- "typescript": "^5.2.2",
43
- "util": "^0.12.4"
43
+ "mocha": "11.5.0",
44
+ "mocha-junit-reporter": "2.2.1",
45
+ "luxon": "^3.7.1",
46
+ "mongodb": "6.16.0",
47
+ "rxjs": "6.6.7",
48
+ "rxjs-compat": "6.6.7",
49
+ "sails": "1.5.14",
50
+ "stream": "0.0.3",
51
+ "typescript": "5.5.4",
52
+ "util": "0.12.5"
44
53
  },
45
54
  "dependencies": {
46
55
  "json2csv": "^5.0.3",
47
56
  "lodash": "^4.17.21",
48
57
  "uuid": "8.3.0"
49
58
  },
59
+ "peerDependencies": {
60
+ "luxon": ">=3.0.0"
61
+ },
50
62
  "publishConfig": {
51
63
  "access": "public"
52
64
  }
@@ -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 moment = require("moment");
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": "${moment().toISOString()}",\n`);
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
@@ -4,7 +4,7 @@ import {
4
4
 
5
5
  import { Sails, Model } from "sails";
6
6
  import { v1 as uuidv1 } from 'uuid';
7
- import moment = require('moment');
7
+ import { DateTime } from 'luxon';
8
8
 
9
9
  import mongodb = require('mongodb');
10
10
  import util = require('util');
@@ -153,11 +153,23 @@ export module Services {
153
153
  _.unset(record, 'dateCreated');
154
154
  _.unset(record, 'lastSaveDate');
155
155
  _.unset(record, '_id');
156
+
157
+ // Records with an 'id' property fail to save with error:
158
+ // {"cause":{"name":"AdapterError","adapterMethodName":"update","modelIdentity":"record","raw":{"code":"E_CANNOT_INTERPRET_AS_OBJECTID"}},"isOperational":true}
159
+ // Fix by ensuring the 'id' property is removed.
160
+ _.unset(record, 'id');
161
+
156
162
  await Record.updateOne({ redboxOid: oid }).set(record);
157
163
  response.success = true;
158
164
  } catch (err) {
159
- sails.log.error(`${this.logHeader} Failed to save update to MongoDB:`);
160
- sails.log.error(JSON.stringify(err));
165
+ sails.log.error(`${this.logHeader} Failed to save update to MongoDB: ${JSON.stringify({
166
+ error: err,
167
+ response: response,
168
+ brand: brand,
169
+ oid: oid,
170
+ record: record,
171
+ user: user,
172
+ })}`);
161
173
  response.success = false;
162
174
  response.message = err;
163
175
  }
@@ -202,33 +214,55 @@ export module Services {
202
214
  return response;
203
215
  }
204
216
 
217
+ /**
218
+ * If pendingValue is in editPending or viewPending, remove all instances from the pending arrays and
219
+ * put the userid in the matching access / non-pending array, then save the changes to the storage.
220
+ *
221
+ * Implementation Note: This is a sync method, but it calls async methods.
222
+ * This means that the storage will not be updated when this method returns, but at some point later.
223
+ *
224
+ * @param oid The record identifier.
225
+ * @param userid The value to put in the matching access / non-pending arrays.
226
+ * @param pendingValue The value to find in the pending arrays.
227
+ */
205
228
  public provideUserAccessAndRemovePendingAccess(oid, userid, pendingValue): void {
206
229
  const batchFn = async () => {
207
230
  const metadata = await this.getMeta(oid);
208
- // remove pending edit access and add real edit access with userid
209
- var pendingEditArray = metadata['authorization']['editPending'];
210
- var editArray = metadata['authorization']['edit'];
211
- for (var i = 0; i < pendingEditArray.length; i++) {
212
- if (pendingEditArray[i] == pendingValue) {
213
- pendingEditArray = pendingEditArray.filter(e => e !== pendingValue);
214
- editArray = editArray.filter(e => e !== userid);
215
- editArray.push(userid);
216
- }
231
+
232
+ // Update edit authorization - remove pending edit access and add real edit access with userid
233
+ const pendingEditArray: string[] = _.get(metadata, 'authorization.editPending', []);
234
+ const editArray: string[] = _.get(metadata, 'authorization.edit', []);
235
+
236
+ // remove all items matching pendingValue from the pendingEditArray
237
+ const pendingEditArrayFiltered = pendingEditArray.filter(value => value !== pendingValue);
238
+ const pendingEditFound = pendingEditArray.length > pendingEditArrayFiltered.length;
239
+
240
+ // add the item to the editArray if it existed in the pendingEditArray, and it is not in the editArray
241
+ if (pendingEditFound && !editArray.includes(userid)) {
242
+ editArray.push(userid);
217
243
  }
218
- metadata['authorization']['editPending'] = pendingEditArray;
219
- metadata['authorization']['edit'] = editArray;
220
-
221
- var pendingViewArray = metadata['authorization']['viewPending'];
222
- var viewArray = metadata['authorization']['view'];
223
- for (var i = 0; i < pendingViewArray.length; i++) {
224
- if (pendingViewArray[i] == pendingValue) {
225
- pendingViewArray = pendingViewArray.filter(e => e !== pendingValue);
226
- viewArray = viewArray.filter(e => e !== userid);
227
- viewArray.push(userid);
228
- }
244
+
245
+ // update the metadata with the modified arrays
246
+ _.set(metadata, 'authorization.editPending', pendingEditArrayFiltered);
247
+ _.set(metadata, 'authorization.edit', editArray);
248
+
249
+ // Update view authorization - remove pending view access and add real view access with userid
250
+ const pendingViewArray: string[] = _.get(metadata, 'authorization.viewPending', []);
251
+ const viewArray: string[] = _.get(metadata, 'authorization.view', []);
252
+
253
+ // remove all items matching pendingValue from the pendingViewArray
254
+ const pendingViewArrayFiltered = pendingViewArray.filter(value => value !== pendingValue);
255
+ const pendingViewFound = pendingViewArray.length > pendingViewArrayFiltered.length;
256
+
257
+ // add the item to the viewArray if it existed in the pendingViewArray, and it is not in the viewArray
258
+ if (pendingViewFound && !viewArray.includes(userid)) {
259
+ viewArray.push(userid);
229
260
  }
230
- metadata['authorization']['viewPending'] = pendingViewArray;
231
- metadata['authorization']['view'] = viewArray;
261
+
262
+ // update the metadata with the modified arrays
263
+ _.set(metadata, 'authorization.viewPending', pendingViewArrayFiltered);
264
+ _.set(metadata, 'authorization.view', viewArray);
265
+
232
266
  try {
233
267
  await this.updateMeta(null, oid, metadata);
234
268
  } catch (err) {
@@ -236,6 +270,8 @@ export module Services {
236
270
  sails.log.error(JSON.stringify(err));
237
271
  }
238
272
  };
273
+
274
+ // TODO: Fix this so that the method only returns after the storage is updated.
239
275
  batchFn();
240
276
  }
241
277
 
@@ -339,7 +375,8 @@ export module Services {
339
375
  const logName = _.get(options, 'logName', null);
340
376
  if (logName) {
341
377
  let log = _.get(record, logName, null);
342
- const entry = { date: moment().format('YYYY-MM-DDTHH:mm:ss') };
378
+ // Use Luxon for ISO-like local timestamp without timezone offset
379
+ const entry = { date: DateTime.now().toFormat("yyyy-LL-dd'T'HH:mm:ss") };
343
380
  if (log) {
344
381
  log.push(entry);
345
382
  } else {
@@ -1,16 +1,16 @@
1
1
  'use strict';
2
2
 
3
- const {
4
- Transform
5
- } = require('stream');
6
- import moment = require('moment');
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
- this.push(`{ "recordType": "${recordtype}",\n "dateGenerated": "${moment().toISOString()}",\n`)
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
- });