dce-expresskit 4.0.0-beta.9 → 4.0.0-log-reviewer-beta.10
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/genEncodedSecret.ts +75 -98
- package/lib/constants/LOG_REVIEW_PAGE_SIZE.d.ts +6 -0
- package/lib/constants/LOG_REVIEW_PAGE_SIZE.js +9 -0
- package/lib/constants/LOG_REVIEW_PAGE_SIZE.js.map +1 -0
- package/lib/helpers/dataSigner.js +15 -5
- package/lib/helpers/dataSigner.js.map +1 -1
- package/lib/helpers/getLogReviewerLogs.d.ts +27 -0
- package/lib/helpers/getLogReviewerLogs.js +238 -0
- package/lib/helpers/getLogReviewerLogs.js.map +1 -0
- package/lib/helpers/initServer.js +15 -17
- package/lib/helpers/initServer.js.map +1 -1
- package/package.json +3 -4
- package/src/constants/LOG_REVIEW_PAGE_SIZE.ts +7 -0
- package/src/helpers/dataSigner.ts +25 -3
- package/src/helpers/getLogReviewerLogs.ts +259 -0
- package/src/helpers/initServer.ts +20 -21
- package/genSalt.ts +0 -15
- package/src/constants/LOG_REVIEW_ROUTE_PATH_PREFIX.ts +0 -9
- package/src/constants/LOG_REVIEW_STATUS_ROUTE.ts +0 -10
- package/src/constants/LOG_ROUTE_PATH.ts +0 -9
- package/src/constants/ROUTE_PATH_PREFIX.ts +0 -7
- package/src/errors/ErrorWithCode.tsx +0 -15
package/genEncodedSecret.ts
CHANGED
|
@@ -1,107 +1,84 @@
|
|
|
1
1
|
// Import crypto lib
|
|
2
2
|
import crypto from 'crypto';
|
|
3
3
|
|
|
4
|
-
// Prompt
|
|
5
|
-
import readline from 'readline';
|
|
6
|
-
|
|
7
|
-
// Create a readline interface
|
|
8
|
-
const readlineInterface = readline.createInterface({
|
|
9
|
-
input: process.stdin,
|
|
10
|
-
output: process.stdout
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Prompt user for input
|
|
15
|
-
* @author Gabe Abrams
|
|
16
|
-
* @param question the question to ask the user
|
|
17
|
-
* @returns the text from the user
|
|
18
|
-
*/
|
|
19
|
-
const prompt = (question: string): Promise<string> => {
|
|
20
|
-
return new Promise((resolve, reject) => {
|
|
21
|
-
readlineInterface.question(question, (answer: string) => {
|
|
22
|
-
if (!answer || answer.trim().length === 0) {
|
|
23
|
-
console.log('\nValue cannot be empty. Exiting...');
|
|
24
|
-
process.exit(0);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
resolve(answer);
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
// All chars for randomizer
|
|
33
4
|
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
34
5
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
console.log('
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
console.log('
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
console.log('
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
6
|
+
// Get args
|
|
7
|
+
const DCEKIT_CRED_ENCODING_SALT = process.env.npm_config_salt;
|
|
8
|
+
if (!DCEKIT_CRED_ENCODING_SALT) {
|
|
9
|
+
console.log('Encoding salt is required: --salt=...');
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Get the key
|
|
14
|
+
let key = process.env.npm_config_key;
|
|
15
|
+
if (!key) {
|
|
16
|
+
console.log('Key is required: --key=...');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Get the description
|
|
21
|
+
let description = process.env.npm_config_description;
|
|
22
|
+
if (!description) {
|
|
23
|
+
console.log('Description is required: --description=...');
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Get secret
|
|
28
|
+
let secret = process.env.npm_config_secret;
|
|
29
|
+
if (!secret) {
|
|
59
30
|
// Generate a random secret
|
|
60
|
-
|
|
31
|
+
secret = '';
|
|
61
32
|
for (let i = 0; i < 32; i++) {
|
|
62
33
|
secret += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
63
34
|
}
|
|
64
|
-
secret
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
35
|
+
console.log('Generated a random secret. If you have one in mind, use --secret=...');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Get the host name
|
|
39
|
+
const host = process.env.npm_config_host;
|
|
40
|
+
if (!host) {
|
|
41
|
+
console.log('Host of the receiving server is required: --host=...');
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Encryption process based on:
|
|
46
|
+
// https://medium.com/@tony.infisical/guide-to-nodes-crypto-module-for-encryption-decryption-65c077176980
|
|
47
|
+
|
|
48
|
+
// Create a random initialization vector
|
|
49
|
+
const iv = crypto.randomBytes(12).toString('base64');
|
|
50
|
+
|
|
51
|
+
// Create a cipher
|
|
52
|
+
const cipher = crypto.createCipheriv(
|
|
53
|
+
'aes-256-gcm',
|
|
54
|
+
Buffer.from(secret, 'base64'),
|
|
55
|
+
Buffer.from(iv, 'base64'),
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
// Encrypt the string
|
|
59
|
+
let ciphertext = cipher.update(secret, 'utf8', 'base64');
|
|
60
|
+
|
|
61
|
+
// Finalize the encryption
|
|
62
|
+
ciphertext += cipher.final('base64');
|
|
63
|
+
|
|
64
|
+
// Get the authentication tag
|
|
65
|
+
const tag = cipher.getAuthTag();
|
|
66
|
+
|
|
67
|
+
// JSONify the encrypted data
|
|
68
|
+
const encryptionPack = encodeURIComponent(JSON.stringify({
|
|
69
|
+
ciphertext,
|
|
70
|
+
iv,
|
|
71
|
+
tag,
|
|
72
|
+
}));
|
|
73
|
+
|
|
74
|
+
// Show the encrypted data
|
|
75
|
+
console.log('\n\n');
|
|
76
|
+
console.log('––––– Done! What\'s Next: –––––');
|
|
77
|
+
console.log('');
|
|
78
|
+
console.log('On the server *sending* the requests, append the following to the DCEKIT_CROSS_SERVER_CREDENTIALS env var:');
|
|
79
|
+
console.log(`|${host}:${key}:${secret}|`);
|
|
80
|
+
console.log('');
|
|
81
|
+
console.log('On the server *receiving* the requests, add an entry to the "CrossServerCredential" collection:');
|
|
82
|
+
console.log(`{ "description": "${description}", "key": "${key}", "encodedeSecret": "${encryptionPack}", "scopes": [] }`);
|
|
83
|
+
console.log('');
|
|
84
|
+
console.log('For all scopes that the server should have access to, add them to the "scopes" array.');
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* Log reviewer page size
|
|
5
|
+
* @author Yuen Ler Chow
|
|
6
|
+
*/
|
|
7
|
+
var LOG_REVIEW_PAGE_SIZE = 100;
|
|
8
|
+
exports.default = LOG_REVIEW_PAGE_SIZE;
|
|
9
|
+
//# sourceMappingURL=LOG_REVIEW_PAGE_SIZE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LOG_REVIEW_PAGE_SIZE.js","sourceRoot":"","sources":["../../src/constants/LOG_REVIEW_PAGE_SIZE.ts"],"names":[],"mappings":";;AAAA;;;GAGG;AACH,IAAM,oBAAoB,GAAG,GAAG,CAAC;AAEjC,kBAAe,oBAAoB,CAAC"}
|
|
@@ -165,7 +165,7 @@ exports.signRequest = signRequest;
|
|
|
165
165
|
* @returns parsed and validated params
|
|
166
166
|
*/
|
|
167
167
|
var validateSignedRequest = function (opts) { return __awaiter(void 0, void 0, void 0, function () {
|
|
168
|
-
var signature, timestamp, key, method, path, params, crossServerCredentialCollection, crossServerCredentialMatches, crossServerCredential, allowedScopes, secret, expectedSignature, elapsedMs;
|
|
168
|
+
var signature, timestamp, key, method, path, params, scope, crossServerCredentialCollection, crossServerCredentialMatches, crossServerCredential, allowedScopes, secret, paramsToSign, expectedSignature, elapsedMs;
|
|
169
169
|
return __generator(this, function (_a) {
|
|
170
170
|
switch (_a.label) {
|
|
171
171
|
case 0:
|
|
@@ -189,7 +189,7 @@ var validateSignedRequest = function (opts) { return __awaiter(void 0, void 0, v
|
|
|
189
189
|
throw new dce_reactkit_1.ErrorWithCode('Could not validate a cross-server request there was no oauth consumer key.', ExpressKitErrorCode_1.default.CrossServerMissingSignedRequestInfo);
|
|
190
190
|
}
|
|
191
191
|
key = opts.params.oauth_consumer_key;
|
|
192
|
-
method = opts.method, path = opts.path, params = opts.params;
|
|
192
|
+
method = opts.method, path = opts.path, params = opts.params, scope = opts.scope;
|
|
193
193
|
crossServerCredentialCollection = (0, initServer_1.internalGetCrossServerCredentialCollection)();
|
|
194
194
|
if (!crossServerCredentialCollection) {
|
|
195
195
|
throw new dce_reactkit_1.ErrorWithCode('Could not validate a cross-server request because the cross-server credential collection was not ready in time.', ExpressKitErrorCode_1.default.SignedRequestInvalidCollection);
|
|
@@ -202,16 +202,26 @@ var validateSignedRequest = function (opts) { return __awaiter(void 0, void 0, v
|
|
|
202
202
|
}
|
|
203
203
|
crossServerCredential = crossServerCredentialMatches[0];
|
|
204
204
|
allowedScopes = crossServerCredential.scopes;
|
|
205
|
-
if (!allowedScopes || !Array.isArray(allowedScopes)
|
|
205
|
+
if (!allowedScopes || !Array.isArray(allowedScopes)) {
|
|
206
|
+
throw new dce_reactkit_1.ErrorWithCode('Could not validate a cross-server request because the credential does not have access to any scopes.', ExpressKitErrorCode_1.default.SignedRequestInvalidScope);
|
|
207
|
+
}
|
|
208
|
+
if (!allowedScopes.includes(scope)) {
|
|
206
209
|
throw new dce_reactkit_1.ErrorWithCode('Could not validate a cross-server request because the required scope was not approved for the credential.', ExpressKitErrorCode_1.default.SignedRequestInvalidScope);
|
|
207
210
|
}
|
|
208
211
|
return [4 /*yield*/, decrypt(crossServerCredential.encodedeSecret)];
|
|
209
212
|
case 2:
|
|
210
213
|
secret = _a.sent();
|
|
214
|
+
paramsToSign = __assign({}, params);
|
|
215
|
+
Object.keys(paramsToSign).forEach(function (key) {
|
|
216
|
+
// Delete oauth params
|
|
217
|
+
if (key.startsWith('oauth_')) {
|
|
218
|
+
delete paramsToSign[key];
|
|
219
|
+
}
|
|
220
|
+
});
|
|
211
221
|
return [4 /*yield*/, genSignature({
|
|
212
222
|
method: method,
|
|
213
223
|
path: path,
|
|
214
|
-
params:
|
|
224
|
+
params: paramsToSign,
|
|
215
225
|
secret: secret,
|
|
216
226
|
})];
|
|
217
227
|
case 3:
|
|
@@ -221,7 +231,7 @@ var validateSignedRequest = function (opts) { return __awaiter(void 0, void 0, v
|
|
|
221
231
|
throw new dce_reactkit_1.ErrorWithCode('Could not validate a cross-server request because the signature did not match.', ExpressKitErrorCode_1.default.SignedRequestInvalidSignature);
|
|
222
232
|
}
|
|
223
233
|
elapsedMs = Math.abs(Date.now() - timestamp);
|
|
224
|
-
if (elapsedMs
|
|
234
|
+
if (elapsedMs > dce_reactkit_1.MINUTE_IN_MS) {
|
|
225
235
|
throw new dce_reactkit_1.ErrorWithCode('Could not validate a cross-server request because the request was too old.', ExpressKitErrorCode_1.default.SignedRequestInvalidTimestamp);
|
|
226
236
|
}
|
|
227
237
|
return [2 /*return*/];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataSigner.js","sourceRoot":"","sources":["../../src/helpers/dataSigner.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"dataSigner.js","sourceRoot":"","sources":["../../src/helpers/dataSigner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Log, LogReviewerFilterState } from 'dce-reactkit';
|
|
2
|
+
import { Collection } from 'dce-mango';
|
|
3
|
+
/**
|
|
4
|
+
* Get logs for the log reviewer interface
|
|
5
|
+
* @author Yuen Ler Chow
|
|
6
|
+
* @param opts object containing all arguments
|
|
7
|
+
* @param opts.pageNumber the page number to retrieve (1-indexed)
|
|
8
|
+
* @param opts.filters filter criteria for logs
|
|
9
|
+
* @param opts.countDocuments if true, count number of documents matching
|
|
10
|
+
* filters and return num pages (not always required because if changing pages,
|
|
11
|
+
* we don't need to recount documents)
|
|
12
|
+
* @param opts.logCollection MongoDB collection containing logs
|
|
13
|
+
* @returns object with logs for the requested page and optionally total number of pages
|
|
14
|
+
*/
|
|
15
|
+
declare const getLogReviewerLogs: (opts: {
|
|
16
|
+
pageNumber: number;
|
|
17
|
+
filters: LogReviewerFilterState;
|
|
18
|
+
countDocuments: boolean;
|
|
19
|
+
logCollection: Collection<Log>;
|
|
20
|
+
}) => Promise<import("dce-mango/lib/types/PaginatedResponse").default<Log> | {
|
|
21
|
+
numPages: number;
|
|
22
|
+
items: Log[];
|
|
23
|
+
currentPageNumber: number;
|
|
24
|
+
perPage: number;
|
|
25
|
+
hasAnotherPage: boolean;
|
|
26
|
+
}>;
|
|
27
|
+
export default getLogReviewerLogs;
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
13
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
14
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
15
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
16
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
17
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
18
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
19
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
23
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
24
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
25
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
26
|
+
function step(op) {
|
|
27
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
28
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
29
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
30
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
31
|
+
switch (op[0]) {
|
|
32
|
+
case 0: case 1: t = op; break;
|
|
33
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
34
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
35
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
36
|
+
default:
|
|
37
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
38
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
39
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
40
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
41
|
+
if (t[2]) _.ops.pop();
|
|
42
|
+
_.trys.pop(); continue;
|
|
43
|
+
}
|
|
44
|
+
op = body.call(thisArg, _);
|
|
45
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
46
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
50
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
51
|
+
};
|
|
52
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
53
|
+
// Import dce-reactkit
|
|
54
|
+
var dce_reactkit_1 = require("dce-reactkit");
|
|
55
|
+
// Import shared types
|
|
56
|
+
var LOG_REVIEW_PAGE_SIZE_1 = __importDefault(require("../constants/LOG_REVIEW_PAGE_SIZE"));
|
|
57
|
+
/**
|
|
58
|
+
* Get logs for the log reviewer interface
|
|
59
|
+
* @author Yuen Ler Chow
|
|
60
|
+
* @param opts object containing all arguments
|
|
61
|
+
* @param opts.pageNumber the page number to retrieve (1-indexed)
|
|
62
|
+
* @param opts.filters filter criteria for logs
|
|
63
|
+
* @param opts.countDocuments if true, count number of documents matching
|
|
64
|
+
* filters and return num pages (not always required because if changing pages,
|
|
65
|
+
* we don't need to recount documents)
|
|
66
|
+
* @param opts.logCollection MongoDB collection containing logs
|
|
67
|
+
* @returns object with logs for the requested page and optionally total number of pages
|
|
68
|
+
*/
|
|
69
|
+
var getLogReviewerLogs = function (opts) { return __awaiter(void 0, void 0, void 0, function () {
|
|
70
|
+
var pageNumber, filters, countDocuments, logCollection, _a, dateFilterState, contextFilterState, tagFilterState, actionErrorFilterState, advancedFilterState, query, startDate, endDate, startTimestamp, endTimestamp, contextConditions, selectedTags, selectedTargets, selectedActions, roles, response, numPages, _b, _c;
|
|
71
|
+
return __generator(this, function (_d) {
|
|
72
|
+
switch (_d.label) {
|
|
73
|
+
case 0:
|
|
74
|
+
pageNumber = opts.pageNumber, filters = opts.filters, countDocuments = opts.countDocuments, logCollection = opts.logCollection;
|
|
75
|
+
_a = filters, dateFilterState = _a.dateFilterState, contextFilterState = _a.contextFilterState, tagFilterState = _a.tagFilterState, actionErrorFilterState = _a.actionErrorFilterState, advancedFilterState = _a.advancedFilterState;
|
|
76
|
+
query = {};
|
|
77
|
+
startDate = dateFilterState.startDate, endDate = dateFilterState.endDate;
|
|
78
|
+
startTimestamp = new Date("".concat(startDate.month, "/").concat(startDate.day, "/").concat(startDate.year)).getTime();
|
|
79
|
+
endTimestamp = ((new Date("".concat(endDate.month, "/").concat(endDate.day, "/").concat(endDate.year))).getTime()
|
|
80
|
+
+ dce_reactkit_1.DAY_IN_MS);
|
|
81
|
+
// Add a date range condition to the query
|
|
82
|
+
query.timestamp = {
|
|
83
|
+
$gte: startTimestamp,
|
|
84
|
+
$lt: endTimestamp,
|
|
85
|
+
};
|
|
86
|
+
contextConditions = [];
|
|
87
|
+
Object.keys(contextFilterState).forEach(function (context) {
|
|
88
|
+
var value = contextFilterState[context];
|
|
89
|
+
if (typeof value === 'boolean') {
|
|
90
|
+
if (value) {
|
|
91
|
+
// The entire context is selected
|
|
92
|
+
contextConditions.push({ context: context });
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
// The context has subcontexts
|
|
97
|
+
var subcontexts = Object.keys(value).filter(function (subcontext) {
|
|
98
|
+
return value[subcontext];
|
|
99
|
+
});
|
|
100
|
+
if (subcontexts.length > 0) {
|
|
101
|
+
contextConditions.push({
|
|
102
|
+
context: context,
|
|
103
|
+
subcontext: { $in: subcontexts },
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
if (contextConditions.length > 0) {
|
|
109
|
+
query.$or = contextConditions;
|
|
110
|
+
}
|
|
111
|
+
selectedTags = Object.keys(tagFilterState).filter(function (tag) { return tagFilterState[tag]; });
|
|
112
|
+
if (selectedTags.length > 0) {
|
|
113
|
+
query.tags = { $in: selectedTags };
|
|
114
|
+
}
|
|
115
|
+
/* --------- Action/Error Filter ---------- */
|
|
116
|
+
if (actionErrorFilterState.type) {
|
|
117
|
+
query.type = actionErrorFilterState.type;
|
|
118
|
+
}
|
|
119
|
+
if (actionErrorFilterState.type === dce_reactkit_1.LogType.Error) {
|
|
120
|
+
if (actionErrorFilterState.errorMessage) {
|
|
121
|
+
// Add error message to the query.
|
|
122
|
+
// $i is used for case-insensitive search, and $regex is used for partial matching
|
|
123
|
+
query.errorMessage = {
|
|
124
|
+
$regex: actionErrorFilterState.errorMessage,
|
|
125
|
+
$options: 'i',
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
if (actionErrorFilterState.errorCode) {
|
|
129
|
+
query.errorCode = {
|
|
130
|
+
$regex: actionErrorFilterState.errorCode,
|
|
131
|
+
$options: 'i',
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (actionErrorFilterState.type === dce_reactkit_1.LogType.Action) {
|
|
136
|
+
selectedTargets = (Object.keys(actionErrorFilterState.target)
|
|
137
|
+
.filter(function (target) {
|
|
138
|
+
return actionErrorFilterState.target[target];
|
|
139
|
+
}));
|
|
140
|
+
selectedActions = (Object.keys(actionErrorFilterState.action)
|
|
141
|
+
.filter(function (action) {
|
|
142
|
+
return actionErrorFilterState.action[action];
|
|
143
|
+
}));
|
|
144
|
+
if (selectedTargets.length > 0) {
|
|
145
|
+
query.target = { $in: selectedTargets };
|
|
146
|
+
}
|
|
147
|
+
if (selectedActions.length > 0) {
|
|
148
|
+
query.action = { $in: selectedActions };
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/* ------------ Advanced Filter ----------- */
|
|
152
|
+
if (advancedFilterState.userFirstName) {
|
|
153
|
+
query.userFirstName = {
|
|
154
|
+
$regex: advancedFilterState.userFirstName,
|
|
155
|
+
$options: 'i',
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
if (advancedFilterState.userLastName) {
|
|
159
|
+
query.userLastName = {
|
|
160
|
+
$regex: advancedFilterState.userLastName,
|
|
161
|
+
$options: 'i',
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
if (advancedFilterState.userEmail) {
|
|
165
|
+
query.userEmail = {
|
|
166
|
+
$regex: advancedFilterState.userEmail,
|
|
167
|
+
$options: 'i',
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
if (advancedFilterState.userId) {
|
|
171
|
+
query.userId = Number.parseInt(advancedFilterState.userId, 10);
|
|
172
|
+
}
|
|
173
|
+
roles = [];
|
|
174
|
+
if (advancedFilterState.includeLearners) {
|
|
175
|
+
roles.push({ isLearner: true });
|
|
176
|
+
}
|
|
177
|
+
if (advancedFilterState.includeTTMs) {
|
|
178
|
+
roles.push({ isTTM: true });
|
|
179
|
+
}
|
|
180
|
+
if (advancedFilterState.includeAdmins) {
|
|
181
|
+
roles.push({ isAdmin: true });
|
|
182
|
+
}
|
|
183
|
+
// If any roles are selected, add them to the query
|
|
184
|
+
if (roles.length > 0) {
|
|
185
|
+
// The $or operator is used to match any of the roles
|
|
186
|
+
// The $and operator is to ensure that other conditions in the query are met
|
|
187
|
+
query.$and = [{ $or: roles }];
|
|
188
|
+
}
|
|
189
|
+
if (advancedFilterState.courseId) {
|
|
190
|
+
query.courseId = Number.parseInt(advancedFilterState.courseId, 10);
|
|
191
|
+
}
|
|
192
|
+
if (advancedFilterState.courseName) {
|
|
193
|
+
query.courseName = {
|
|
194
|
+
$regex: advancedFilterState.courseName,
|
|
195
|
+
$options: 'i',
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
if (advancedFilterState.isMobile !== undefined) {
|
|
199
|
+
query['device.isMobile'] = Boolean(advancedFilterState.isMobile);
|
|
200
|
+
}
|
|
201
|
+
if (advancedFilterState.source) {
|
|
202
|
+
query.source = advancedFilterState.source;
|
|
203
|
+
}
|
|
204
|
+
if (advancedFilterState.routePath) {
|
|
205
|
+
query.routePath = {
|
|
206
|
+
$regex: advancedFilterState.routePath,
|
|
207
|
+
$options: 'i',
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
if (advancedFilterState.routeTemplate) {
|
|
211
|
+
query.routeTemplate = {
|
|
212
|
+
$regex: advancedFilterState.routeTemplate,
|
|
213
|
+
$options: 'i',
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
return [4 /*yield*/, logCollection.findPaged({
|
|
217
|
+
query: query,
|
|
218
|
+
perPage: LOG_REVIEW_PAGE_SIZE_1.default,
|
|
219
|
+
pageNumber: pageNumber,
|
|
220
|
+
sortDescending: true,
|
|
221
|
+
})];
|
|
222
|
+
case 1:
|
|
223
|
+
response = _d.sent();
|
|
224
|
+
if (!countDocuments) return [3 /*break*/, 3];
|
|
225
|
+
_c = (_b = Math).ceil;
|
|
226
|
+
return [4 /*yield*/, logCollection.count(query)];
|
|
227
|
+
case 2:
|
|
228
|
+
numPages = _c.apply(_b, [(_d.sent())
|
|
229
|
+
/ LOG_REVIEW_PAGE_SIZE_1.default]);
|
|
230
|
+
return [2 /*return*/, __assign(__assign({}, response), { numPages: numPages })];
|
|
231
|
+
case 3:
|
|
232
|
+
// Return response
|
|
233
|
+
return [2 /*return*/, response];
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
}); };
|
|
237
|
+
exports.default = getLogReviewerLogs;
|
|
238
|
+
//# sourceMappingURL=getLogReviewerLogs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getLogReviewerLogs.js","sourceRoot":"","sources":["../../src/helpers/getLogReviewerLogs.ts"],"names":[],"mappings":"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"}
|
|
@@ -55,7 +55,7 @@ exports.internalGetCrossServerCredentialCollection = exports.internalGetLogColle
|
|
|
55
55
|
var dce_reactkit_1 = require("dce-reactkit");
|
|
56
56
|
// Import shared helpers
|
|
57
57
|
var genRouteHandler_1 = __importDefault(require("./genRouteHandler"));
|
|
58
|
-
|
|
58
|
+
var getLogReviewerLogs_1 = __importDefault(require("./getLogReviewerLogs"));
|
|
59
59
|
var ExpressKitErrorCode_1 = __importDefault(require("../types/ExpressKitErrorCode"));
|
|
60
60
|
// Stored copy of dce-mango log collection
|
|
61
61
|
var _logCollection;
|
|
@@ -247,38 +247,36 @@ var initServer = function (opts) {
|
|
|
247
247
|
}); },
|
|
248
248
|
}));
|
|
249
249
|
/**
|
|
250
|
-
* Get
|
|
251
|
-
* @author Gabe Abrams
|
|
252
|
-
* @param
|
|
253
|
-
* @param
|
|
254
|
-
* @returns {Log[]} list of logs
|
|
250
|
+
* Get filtered logs based on provided filters
|
|
251
|
+
* @author Gabe Abrams, Yuen Ler Chow
|
|
252
|
+
* @param pageNumber the page number to get
|
|
253
|
+
* @param filters the filters to apply to the logs
|
|
254
|
+
* @returns {Log[]} list of logs that match the filters
|
|
255
255
|
*/
|
|
256
|
-
opts.app.get(
|
|
256
|
+
opts.app.get(dce_reactkit_1.LOG_REVIEW_GET_LOGS_ROUTE, (0, genRouteHandler_1.default)({
|
|
257
257
|
paramTypes: {
|
|
258
|
-
year: dce_reactkit_1.ParamType.Int,
|
|
259
|
-
month: dce_reactkit_1.ParamType.Int,
|
|
260
258
|
pageNumber: dce_reactkit_1.ParamType.Int,
|
|
259
|
+
filters: dce_reactkit_1.ParamType.JSON,
|
|
260
|
+
countDocuments: dce_reactkit_1.ParamType.Boolean,
|
|
261
261
|
},
|
|
262
262
|
handler: function (_a) { return __awaiter(void 0, [_a], void 0, function (_b) {
|
|
263
|
-
var
|
|
263
|
+
var pageNumber, userId, isAdmin, filters, countDocuments, canReview, response;
|
|
264
264
|
var params = _b.params;
|
|
265
265
|
return __generator(this, function (_c) {
|
|
266
266
|
switch (_c.label) {
|
|
267
267
|
case 0:
|
|
268
|
-
|
|
268
|
+
pageNumber = params.pageNumber, userId = params.userId, isAdmin = params.isAdmin, filters = params.filters, countDocuments = params.countDocuments;
|
|
269
269
|
return [4 /*yield*/, canReviewLogs(userId, isAdmin)];
|
|
270
270
|
case 1:
|
|
271
271
|
canReview = _c.sent();
|
|
272
272
|
if (!canReview) {
|
|
273
273
|
throw new dce_reactkit_1.ErrorWithCode('You cannot access this resource because you do not have the appropriate permissions.', ExpressKitErrorCode_1.default.NotAllowedToReviewLogs);
|
|
274
274
|
}
|
|
275
|
-
return [4 /*yield*/,
|
|
276
|
-
query: {
|
|
277
|
-
year: year,
|
|
278
|
-
month: month,
|
|
279
|
-
},
|
|
280
|
-
perPage: 1000,
|
|
275
|
+
return [4 /*yield*/, (0, getLogReviewerLogs_1.default)({
|
|
281
276
|
pageNumber: pageNumber,
|
|
277
|
+
filters: filters,
|
|
278
|
+
countDocuments: countDocuments,
|
|
279
|
+
logCollection: _logCollection,
|
|
282
280
|
})];
|
|
283
281
|
case 2:
|
|
284
282
|
response = _c.sent();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"initServer.js","sourceRoot":"","sources":["../../src/helpers/initServer.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMA,sBAAsB;AACtB,6CAQsB;AAEtB,wBAAwB;AACxB,sEAAgD;
|
|
1
|
+
{"version":3,"file":"initServer.js","sourceRoot":"","sources":["../../src/helpers/initServer.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dce-expresskit",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-log-reviewer-beta.10",
|
|
4
4
|
"description": "Shared functions, helpers, and tools for Harvard DCE Express-based servers",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"types": "./lib/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"build": "tsc --project ./tsconfig.json",
|
|
9
|
-
"gen-cross-server-secret": "npx tsx genEncodedSecret.ts"
|
|
10
|
-
"gen-cross-server-salt": "npx tsx genSalt.ts"
|
|
9
|
+
"gen-cross-server-secret": "npx tsx genEncodedSecret.ts"
|
|
11
10
|
},
|
|
12
11
|
"repository": {
|
|
13
12
|
"type": "git",
|
|
@@ -25,7 +24,7 @@
|
|
|
25
24
|
"@fortawesome/free-solid-svg-icons": "^6.7.2",
|
|
26
25
|
"@fortawesome/react-fontawesome": "^0.2.2",
|
|
27
26
|
"bootstrap": "^5.3.3",
|
|
28
|
-
"dce-reactkit": "^4.0.0-beta.
|
|
27
|
+
"dce-reactkit": "^4.0.0-beta-logreviewer.1",
|
|
29
28
|
"react": "^19.0.0"
|
|
30
29
|
},
|
|
31
30
|
"peerDependencies": {
|
|
@@ -172,6 +172,7 @@ export const signRequest = async (
|
|
|
172
172
|
// Add signature to the augmented params
|
|
173
173
|
augmentedParams.oauth_signature = signature;
|
|
174
174
|
|
|
175
|
+
|
|
175
176
|
// Return the augmented params
|
|
176
177
|
return augmentedParams;
|
|
177
178
|
};
|
|
@@ -233,6 +234,7 @@ export const validateSignedRequest = async (
|
|
|
233
234
|
method,
|
|
234
235
|
path,
|
|
235
236
|
params,
|
|
237
|
+
scope,
|
|
236
238
|
} = opts;
|
|
237
239
|
|
|
238
240
|
/* ------- Look Up Credential ------- */
|
|
@@ -258,7 +260,14 @@ export const validateSignedRequest = async (
|
|
|
258
260
|
|
|
259
261
|
// Make sure the scope is included
|
|
260
262
|
const allowedScopes = crossServerCredential.scopes;
|
|
261
|
-
if (!allowedScopes || !Array.isArray(allowedScopes)
|
|
263
|
+
if (!allowedScopes || !Array.isArray(allowedScopes)) {
|
|
264
|
+
throw new ErrorWithCode(
|
|
265
|
+
'Could not validate a cross-server request because the credential does not have access to any scopes.',
|
|
266
|
+
ExpressKitErrorCode.SignedRequestInvalidScope,
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
}
|
|
270
|
+
if (!allowedScopes.includes(scope)) {
|
|
262
271
|
throw new ErrorWithCode(
|
|
263
272
|
'Could not validate a cross-server request because the required scope was not approved for the credential.',
|
|
264
273
|
ExpressKitErrorCode.SignedRequestInvalidScope,
|
|
@@ -270,11 +279,24 @@ export const validateSignedRequest = async (
|
|
|
270
279
|
|
|
271
280
|
/* -------- Verify Signature -------- */
|
|
272
281
|
|
|
282
|
+
// Curate what goes into the params
|
|
283
|
+
const paramsToSign: {
|
|
284
|
+
[key: string]: any,
|
|
285
|
+
} = {
|
|
286
|
+
...params,
|
|
287
|
+
};
|
|
288
|
+
Object.keys(paramsToSign).forEach((key) => {
|
|
289
|
+
// Delete oauth params
|
|
290
|
+
if (key.startsWith('oauth_')) {
|
|
291
|
+
delete paramsToSign[key];
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
|
|
273
295
|
// Generate a new signature to compare
|
|
274
296
|
const expectedSignature = await genSignature({
|
|
275
297
|
method,
|
|
276
298
|
path,
|
|
277
|
-
params,
|
|
299
|
+
params: paramsToSign,
|
|
278
300
|
secret,
|
|
279
301
|
});
|
|
280
302
|
|
|
@@ -288,7 +310,7 @@ export const validateSignedRequest = async (
|
|
|
288
310
|
|
|
289
311
|
// Make sure the timestamp was recent enough
|
|
290
312
|
const elapsedMs = Math.abs(Date.now() - timestamp);
|
|
291
|
-
if (elapsedMs
|
|
313
|
+
if (elapsedMs > MINUTE_IN_MS) {
|
|
292
314
|
throw new ErrorWithCode(
|
|
293
315
|
'Could not validate a cross-server request because the request was too old.',
|
|
294
316
|
ExpressKitErrorCode.SignedRequestInvalidTimestamp,
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
// Import dce-reactkit
|
|
2
|
+
import {
|
|
3
|
+
DAY_IN_MS,
|
|
4
|
+
Log,
|
|
5
|
+
LogReviewerFilterState,
|
|
6
|
+
LogType
|
|
7
|
+
} from 'dce-reactkit';
|
|
8
|
+
|
|
9
|
+
// Import shared types
|
|
10
|
+
import LOG_REVIEW_PAGE_SIZE from '../constants/LOG_REVIEW_PAGE_SIZE';
|
|
11
|
+
import { Collection } from 'dce-mango';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Get logs for the log reviewer interface
|
|
15
|
+
* @author Yuen Ler Chow
|
|
16
|
+
* @param opts object containing all arguments
|
|
17
|
+
* @param opts.pageNumber the page number to retrieve (1-indexed)
|
|
18
|
+
* @param opts.filters filter criteria for logs
|
|
19
|
+
* @param opts.countDocuments if true, count number of documents matching
|
|
20
|
+
* filters and return num pages (not always required because if changing pages,
|
|
21
|
+
* we don't need to recount documents)
|
|
22
|
+
* @param opts.logCollection MongoDB collection containing logs
|
|
23
|
+
* @returns object with logs for the requested page and optionally total number of pages
|
|
24
|
+
*/
|
|
25
|
+
const getLogReviewerLogs = async (
|
|
26
|
+
opts: {
|
|
27
|
+
pageNumber: number,
|
|
28
|
+
filters: LogReviewerFilterState,
|
|
29
|
+
countDocuments: boolean,
|
|
30
|
+
logCollection: Collection<Log>,
|
|
31
|
+
},
|
|
32
|
+
) => {
|
|
33
|
+
|
|
34
|
+
// Destructure opts
|
|
35
|
+
const {
|
|
36
|
+
pageNumber,
|
|
37
|
+
filters,
|
|
38
|
+
countDocuments,
|
|
39
|
+
logCollection,
|
|
40
|
+
} = opts;
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
// Destructure filters
|
|
44
|
+
const {
|
|
45
|
+
dateFilterState,
|
|
46
|
+
contextFilterState,
|
|
47
|
+
tagFilterState,
|
|
48
|
+
actionErrorFilterState,
|
|
49
|
+
advancedFilterState,
|
|
50
|
+
} = filters as LogReviewerFilterState;
|
|
51
|
+
|
|
52
|
+
// Build MongoDB query based on filters
|
|
53
|
+
const query: { [k: string]: any } = {};
|
|
54
|
+
|
|
55
|
+
/* -------------- Date Filter ------------- */
|
|
56
|
+
|
|
57
|
+
// Convert start and end dates from the dateFilterState into timestamps
|
|
58
|
+
const { startDate, endDate } = dateFilterState;
|
|
59
|
+
const startTimestamp = new Date(
|
|
60
|
+
`${startDate.month}/${startDate.day}/${startDate.year}`,
|
|
61
|
+
).getTime();
|
|
62
|
+
const endTimestamp = (
|
|
63
|
+
(new Date(`${endDate.month}/${endDate.day}/${endDate.year}`)).getTime()
|
|
64
|
+
+ DAY_IN_MS
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
// Add a date range condition to the query
|
|
68
|
+
query.timestamp = {
|
|
69
|
+
$gte: startTimestamp,
|
|
70
|
+
$lt: endTimestamp,
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
/* ------------ Context Filter ------------ */
|
|
74
|
+
|
|
75
|
+
// Process context filters to include selected contexts and subcontexts
|
|
76
|
+
const contextConditions: { [k: string]: any }[] = [];
|
|
77
|
+
Object.keys(contextFilterState).forEach((context) => {
|
|
78
|
+
const value = contextFilterState[context];
|
|
79
|
+
if (typeof value === 'boolean') {
|
|
80
|
+
if (value) {
|
|
81
|
+
// The entire context is selected
|
|
82
|
+
contextConditions.push({ context });
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
// The context has subcontexts
|
|
86
|
+
const subcontexts = Object.keys(value).filter((subcontext) => {
|
|
87
|
+
return value[subcontext];
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
if (subcontexts.length > 0) {
|
|
91
|
+
contextConditions.push({
|
|
92
|
+
context,
|
|
93
|
+
subcontext: { $in: subcontexts },
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
if (contextConditions.length > 0) {
|
|
99
|
+
query.$or = contextConditions;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* -------------- Tag Filter -------------- */
|
|
103
|
+
|
|
104
|
+
const selectedTags = Object.keys(tagFilterState).filter((tag) => { return tagFilterState[tag]; });
|
|
105
|
+
if (selectedTags.length > 0) {
|
|
106
|
+
query.tags = { $in: selectedTags };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/* --------- Action/Error Filter ---------- */
|
|
110
|
+
|
|
111
|
+
if (actionErrorFilterState.type) {
|
|
112
|
+
query.type = actionErrorFilterState.type;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (actionErrorFilterState.type === LogType.Error) {
|
|
116
|
+
if (actionErrorFilterState.errorMessage) {
|
|
117
|
+
// Add error message to the query.
|
|
118
|
+
// $i is used for case-insensitive search, and $regex is used for partial matching
|
|
119
|
+
query.errorMessage = {
|
|
120
|
+
$regex: actionErrorFilterState.errorMessage,
|
|
121
|
+
$options: 'i',
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (actionErrorFilterState.errorCode) {
|
|
126
|
+
query.errorCode = {
|
|
127
|
+
$regex: actionErrorFilterState.errorCode,
|
|
128
|
+
$options: 'i',
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (actionErrorFilterState.type === LogType.Action) {
|
|
134
|
+
const selectedTargets = (
|
|
135
|
+
Object.keys(actionErrorFilterState.target)
|
|
136
|
+
.filter((target) => {
|
|
137
|
+
return actionErrorFilterState.target[target];
|
|
138
|
+
})
|
|
139
|
+
);
|
|
140
|
+
const selectedActions = (
|
|
141
|
+
Object.keys(actionErrorFilterState.action)
|
|
142
|
+
.filter((action) => {
|
|
143
|
+
return actionErrorFilterState.action[action];
|
|
144
|
+
})
|
|
145
|
+
);
|
|
146
|
+
if (selectedTargets.length > 0) {
|
|
147
|
+
query.target = { $in: selectedTargets };
|
|
148
|
+
}
|
|
149
|
+
if (selectedActions.length > 0) {
|
|
150
|
+
query.action = { $in: selectedActions };
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/* ------------ Advanced Filter ----------- */
|
|
155
|
+
|
|
156
|
+
if (advancedFilterState.userFirstName) {
|
|
157
|
+
query.userFirstName = {
|
|
158
|
+
$regex: advancedFilterState.userFirstName,
|
|
159
|
+
$options: 'i',
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (advancedFilterState.userLastName) {
|
|
164
|
+
query.userLastName = {
|
|
165
|
+
$regex: advancedFilterState.userLastName,
|
|
166
|
+
$options: 'i',
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (advancedFilterState.userEmail) {
|
|
171
|
+
query.userEmail = {
|
|
172
|
+
$regex: advancedFilterState.userEmail,
|
|
173
|
+
$options: 'i',
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (advancedFilterState.userId) {
|
|
178
|
+
query.userId = Number.parseInt(advancedFilterState.userId, 10);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const roles: {
|
|
182
|
+
isLearner?: boolean,
|
|
183
|
+
isTTM?: boolean,
|
|
184
|
+
isAdmin?: boolean,
|
|
185
|
+
}[] = [];
|
|
186
|
+
if (advancedFilterState.includeLearners) {
|
|
187
|
+
roles.push({ isLearner: true });
|
|
188
|
+
}
|
|
189
|
+
if (advancedFilterState.includeTTMs) {
|
|
190
|
+
roles.push({ isTTM: true });
|
|
191
|
+
}
|
|
192
|
+
if (advancedFilterState.includeAdmins) {
|
|
193
|
+
roles.push({ isAdmin: true });
|
|
194
|
+
}
|
|
195
|
+
// If any roles are selected, add them to the query
|
|
196
|
+
if (roles.length > 0) {
|
|
197
|
+
// The $or operator is used to match any of the roles
|
|
198
|
+
// The $and operator is to ensure that other conditions in the query are met
|
|
199
|
+
query.$and = [{ $or: roles }];
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (advancedFilterState.courseId) {
|
|
203
|
+
query.courseId = Number.parseInt(advancedFilterState.courseId, 10);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (advancedFilterState.courseName) {
|
|
207
|
+
query.courseName = {
|
|
208
|
+
$regex: advancedFilterState.courseName,
|
|
209
|
+
$options: 'i',
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (advancedFilterState.isMobile !== undefined) {
|
|
214
|
+
query['device.isMobile'] = Boolean(advancedFilterState.isMobile);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (advancedFilterState.source) {
|
|
218
|
+
query.source = advancedFilterState.source;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (advancedFilterState.routePath) {
|
|
222
|
+
query.routePath = {
|
|
223
|
+
$regex: advancedFilterState.routePath,
|
|
224
|
+
$options: 'i',
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (advancedFilterState.routeTemplate) {
|
|
229
|
+
query.routeTemplate = {
|
|
230
|
+
$regex: advancedFilterState.routeTemplate,
|
|
231
|
+
$options: 'i',
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Query for logs
|
|
236
|
+
const response = await logCollection.findPaged({
|
|
237
|
+
query,
|
|
238
|
+
perPage: LOG_REVIEW_PAGE_SIZE,
|
|
239
|
+
pageNumber,
|
|
240
|
+
sortDescending: true,
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// Count documents if requested
|
|
244
|
+
if (countDocuments) {
|
|
245
|
+
const numPages = Math.ceil(
|
|
246
|
+
await logCollection.count(query)
|
|
247
|
+
/ LOG_REVIEW_PAGE_SIZE
|
|
248
|
+
);
|
|
249
|
+
return {
|
|
250
|
+
...response,
|
|
251
|
+
numPages,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Return response
|
|
256
|
+
return response;
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
export default getLogReviewerLogs;
|
|
@@ -6,21 +6,22 @@ import { Collection } from 'dce-mango';
|
|
|
6
6
|
|
|
7
7
|
// Import dce-reactkit
|
|
8
8
|
import {
|
|
9
|
-
ErrorWithCode,
|
|
10
9
|
ParamType,
|
|
11
10
|
LogFunction,
|
|
12
|
-
LOG_REVIEW_ROUTE_PATH_PREFIX,
|
|
13
11
|
LOG_ROUTE_PATH,
|
|
14
12
|
LOG_REVIEW_STATUS_ROUTE,
|
|
15
13
|
Log,
|
|
14
|
+
LOG_REVIEW_GET_LOGS_ROUTE,
|
|
15
|
+
ErrorWithCode,
|
|
16
16
|
} from 'dce-reactkit';
|
|
17
17
|
|
|
18
18
|
// Import shared helpers
|
|
19
19
|
import genRouteHandler from './genRouteHandler';
|
|
20
|
+
import getLogReviewerLogs from './getLogReviewerLogs';
|
|
20
21
|
|
|
21
22
|
// Import shared types
|
|
22
|
-
import ExpressKitErrorCode from '../types/ExpressKitErrorCode';
|
|
23
23
|
import CrossServerCredential from '../types/CrossServerCredential';
|
|
24
|
+
import ExpressKitErrorCode from '../types/ExpressKitErrorCode';
|
|
24
25
|
|
|
25
26
|
// Stored copy of dce-mango log collection
|
|
26
27
|
let _logCollection: Collection<Log>;
|
|
@@ -231,28 +232,28 @@ const initServer = (
|
|
|
231
232
|
);
|
|
232
233
|
|
|
233
234
|
/**
|
|
234
|
-
* Get
|
|
235
|
-
* @author Gabe Abrams
|
|
236
|
-
* @param
|
|
237
|
-
* @param
|
|
238
|
-
* @returns {Log[]} list of logs
|
|
235
|
+
* Get filtered logs based on provided filters
|
|
236
|
+
* @author Gabe Abrams, Yuen Ler Chow
|
|
237
|
+
* @param pageNumber the page number to get
|
|
238
|
+
* @param filters the filters to apply to the logs
|
|
239
|
+
* @returns {Log[]} list of logs that match the filters
|
|
239
240
|
*/
|
|
240
241
|
opts.app.get(
|
|
241
|
-
|
|
242
|
+
LOG_REVIEW_GET_LOGS_ROUTE,
|
|
242
243
|
genRouteHandler({
|
|
243
244
|
paramTypes: {
|
|
244
|
-
year: ParamType.Int,
|
|
245
|
-
month: ParamType.Int,
|
|
246
245
|
pageNumber: ParamType.Int,
|
|
246
|
+
filters: ParamType.JSON,
|
|
247
|
+
countDocuments: ParamType.Boolean,
|
|
247
248
|
},
|
|
248
249
|
handler: async ({ params }) => {
|
|
249
|
-
//
|
|
250
|
+
// Destructure params
|
|
250
251
|
const {
|
|
251
|
-
year,
|
|
252
|
-
month,
|
|
253
252
|
pageNumber,
|
|
254
253
|
userId,
|
|
255
254
|
isAdmin,
|
|
255
|
+
filters,
|
|
256
|
+
countDocuments,
|
|
256
257
|
} = params;
|
|
257
258
|
|
|
258
259
|
// Validate user
|
|
@@ -264,14 +265,12 @@ const initServer = (
|
|
|
264
265
|
);
|
|
265
266
|
}
|
|
266
267
|
|
|
267
|
-
//
|
|
268
|
-
const response = await
|
|
269
|
-
query: {
|
|
270
|
-
year,
|
|
271
|
-
month,
|
|
272
|
-
},
|
|
273
|
-
perPage: 1000,
|
|
268
|
+
// Get logs
|
|
269
|
+
const response = await getLogReviewerLogs({
|
|
274
270
|
pageNumber,
|
|
271
|
+
filters,
|
|
272
|
+
countDocuments,
|
|
273
|
+
logCollection: _logCollection,
|
|
275
274
|
});
|
|
276
275
|
|
|
277
276
|
// Return response
|
package/genSalt.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
// All chars for randomizer
|
|
2
|
-
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
3
|
-
|
|
4
|
-
// Generate a random salt
|
|
5
|
-
let salt = '';
|
|
6
|
-
for (let i = 0; i < 32; i++) {
|
|
7
|
-
salt += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
8
|
-
}
|
|
9
|
-
salt = Buffer.from(salt).toString('base64');
|
|
10
|
-
|
|
11
|
-
// Generates 32 byte salt
|
|
12
|
-
console.log('New *receiving* server salt:')
|
|
13
|
-
|
|
14
|
-
Buffer.from("Hello World").toString('base64')
|
|
15
|
-
console.log(salt);
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import ROUTE_PATH_PREFIX from './ROUTE_PATH_PREFIX';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Route for checking the status of the current user's
|
|
5
|
-
* access to log review
|
|
6
|
-
* @author Gabe Abrams
|
|
7
|
-
*/
|
|
8
|
-
const LOG_REVIEW_STATUS_ROUTE = `${ROUTE_PATH_PREFIX}/logs/access_allowed`;
|
|
9
|
-
|
|
10
|
-
export default LOG_REVIEW_STATUS_ROUTE;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* An error with a code
|
|
3
|
-
* @author Gabe Abrams
|
|
4
|
-
*/
|
|
5
|
-
class ErrorWithCode extends Error {
|
|
6
|
-
code: string;
|
|
7
|
-
|
|
8
|
-
constructor(message: string, code: string) {
|
|
9
|
-
super(message);
|
|
10
|
-
this.name = 'ErrorWithCode';
|
|
11
|
-
this.code = code;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export default ErrorWithCode;
|