dce-expresskit 4.0.0 → 4.1.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.
- 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/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 -16
- package/lib/helpers/initServer.js.map +1 -1
- package/package.json +2 -2
- package/src/constants/LOG_REVIEW_PAGE_SIZE.ts +7 -0
- package/src/helpers/getLogReviewerLogs.ts +260 -0
- package/src/helpers/initServer.ts +19 -20
|
@@ -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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Collection } from 'dce-mango';
|
|
2
|
+
import { Log, LogReviewerFilterState } from 'dce-reactkit';
|
|
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,6 +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
|
+
var getLogReviewerLogs_1 = __importDefault(require("./getLogReviewerLogs"));
|
|
58
59
|
// Import shared types
|
|
59
60
|
var ExpressKitErrorCode_1 = __importDefault(require("../types/ExpressKitErrorCode"));
|
|
60
61
|
// Stored copy of dce-mango log collection
|
|
@@ -247,38 +248,36 @@ var initServer = function (opts) {
|
|
|
247
248
|
}); },
|
|
248
249
|
}));
|
|
249
250
|
/**
|
|
250
|
-
* Get
|
|
251
|
-
* @author Gabe Abrams
|
|
252
|
-
* @param
|
|
253
|
-
* @param
|
|
254
|
-
* @returns {Log[]} list of logs
|
|
251
|
+
* Get filtered logs based on provided filters
|
|
252
|
+
* @author Gabe Abrams, Yuen Ler Chow
|
|
253
|
+
* @param pageNumber the page number to get
|
|
254
|
+
* @param filters the filters to apply to the logs
|
|
255
|
+
* @returns {Log[]} list of logs that match the filters
|
|
255
256
|
*/
|
|
256
|
-
opts.app.get(
|
|
257
|
+
opts.app.get(dce_reactkit_1.LOG_REVIEW_GET_LOGS_ROUTE, (0, genRouteHandler_1.default)({
|
|
257
258
|
paramTypes: {
|
|
258
|
-
year: dce_reactkit_1.ParamType.Int,
|
|
259
|
-
month: dce_reactkit_1.ParamType.Int,
|
|
260
259
|
pageNumber: dce_reactkit_1.ParamType.Int,
|
|
260
|
+
filters: dce_reactkit_1.ParamType.JSON,
|
|
261
|
+
countDocuments: dce_reactkit_1.ParamType.Boolean,
|
|
261
262
|
},
|
|
262
263
|
handler: function (_a) { return __awaiter(void 0, [_a], void 0, function (_b) {
|
|
263
|
-
var
|
|
264
|
+
var pageNumber, userId, isAdmin, filters, countDocuments, canReview, response;
|
|
264
265
|
var params = _b.params;
|
|
265
266
|
return __generator(this, function (_c) {
|
|
266
267
|
switch (_c.label) {
|
|
267
268
|
case 0:
|
|
268
|
-
|
|
269
|
+
pageNumber = params.pageNumber, userId = params.userId, isAdmin = params.isAdmin, filters = params.filters, countDocuments = params.countDocuments;
|
|
269
270
|
return [4 /*yield*/, canReviewLogs(userId, isAdmin)];
|
|
270
271
|
case 1:
|
|
271
272
|
canReview = _c.sent();
|
|
272
273
|
if (!canReview) {
|
|
273
274
|
throw new dce_reactkit_1.ErrorWithCode('You cannot access this resource because you do not have the appropriate permissions.', ExpressKitErrorCode_1.default.NotAllowedToReviewLogs);
|
|
274
275
|
}
|
|
275
|
-
return [4 /*yield*/,
|
|
276
|
-
query: {
|
|
277
|
-
year: year,
|
|
278
|
-
month: month,
|
|
279
|
-
},
|
|
280
|
-
perPage: 1000,
|
|
276
|
+
return [4 /*yield*/, (0, getLogReviewerLogs_1.default)({
|
|
281
277
|
pageNumber: pageNumber,
|
|
278
|
+
filters: filters,
|
|
279
|
+
countDocuments: countDocuments,
|
|
280
|
+
logCollection: _logCollection,
|
|
282
281
|
})];
|
|
283
282
|
case 2:
|
|
284
283
|
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,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dce-expresskit",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.1.0",
|
|
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",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"@fortawesome/free-solid-svg-icons": "^6.7.2",
|
|
26
26
|
"@fortawesome/react-fontawesome": "^0.2.2",
|
|
27
27
|
"bootstrap": "^5.3.3",
|
|
28
|
-
"dce-reactkit": "
|
|
28
|
+
"dce-reactkit": "4.0.0-beta-logreviewer.1",
|
|
29
29
|
"react": "^19.0.0"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
// Import dce-mango
|
|
2
|
+
import { Collection } from 'dce-mango';
|
|
3
|
+
|
|
4
|
+
// Import dce-reactkit
|
|
5
|
+
import {
|
|
6
|
+
DAY_IN_MS,
|
|
7
|
+
Log,
|
|
8
|
+
LogReviewerFilterState,
|
|
9
|
+
LogType
|
|
10
|
+
} from 'dce-reactkit';
|
|
11
|
+
|
|
12
|
+
// Import shared types
|
|
13
|
+
import LOG_REVIEW_PAGE_SIZE from '../constants/LOG_REVIEW_PAGE_SIZE';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Get logs for the log reviewer interface
|
|
17
|
+
* @author Yuen Ler Chow
|
|
18
|
+
* @param opts object containing all arguments
|
|
19
|
+
* @param opts.pageNumber the page number to retrieve (1-indexed)
|
|
20
|
+
* @param opts.filters filter criteria for logs
|
|
21
|
+
* @param opts.countDocuments if true, count number of documents matching
|
|
22
|
+
* filters and return num pages (not always required because if changing pages,
|
|
23
|
+
* we don't need to recount documents)
|
|
24
|
+
* @param opts.logCollection MongoDB collection containing logs
|
|
25
|
+
* @returns object with logs for the requested page and optionally total number of pages
|
|
26
|
+
*/
|
|
27
|
+
const getLogReviewerLogs = async (
|
|
28
|
+
opts: {
|
|
29
|
+
pageNumber: number,
|
|
30
|
+
filters: LogReviewerFilterState,
|
|
31
|
+
countDocuments: boolean,
|
|
32
|
+
logCollection: Collection<Log>,
|
|
33
|
+
},
|
|
34
|
+
) => {
|
|
35
|
+
// Destructure opts
|
|
36
|
+
const {
|
|
37
|
+
pageNumber,
|
|
38
|
+
filters,
|
|
39
|
+
countDocuments,
|
|
40
|
+
logCollection,
|
|
41
|
+
} = opts;
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
// Destructure filters
|
|
45
|
+
const {
|
|
46
|
+
dateFilterState,
|
|
47
|
+
contextFilterState,
|
|
48
|
+
tagFilterState,
|
|
49
|
+
actionErrorFilterState,
|
|
50
|
+
advancedFilterState,
|
|
51
|
+
} = filters as LogReviewerFilterState;
|
|
52
|
+
|
|
53
|
+
// Build MongoDB query based on filters
|
|
54
|
+
const query: { [k: string]: any } = {};
|
|
55
|
+
|
|
56
|
+
/* -------------- Date Filter ------------- */
|
|
57
|
+
|
|
58
|
+
// Convert start and end dates from the dateFilterState into timestamps
|
|
59
|
+
const { startDate, endDate } = dateFilterState;
|
|
60
|
+
const startTimestamp = new Date(
|
|
61
|
+
`${startDate.month}/${startDate.day}/${startDate.year}`,
|
|
62
|
+
).getTime();
|
|
63
|
+
const endTimestamp = (
|
|
64
|
+
(new Date(`${endDate.month}/${endDate.day}/${endDate.year}`)).getTime()
|
|
65
|
+
+ DAY_IN_MS
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
// Add a date range condition to the query
|
|
69
|
+
query.timestamp = {
|
|
70
|
+
$gte: startTimestamp,
|
|
71
|
+
$lt: endTimestamp,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/* ------------ Context Filter ------------ */
|
|
75
|
+
|
|
76
|
+
// Process context filters to include selected contexts and subcontexts
|
|
77
|
+
const contextConditions: { [k: string]: any }[] = [];
|
|
78
|
+
Object.keys(contextFilterState).forEach((context) => {
|
|
79
|
+
const value = contextFilterState[context];
|
|
80
|
+
if (typeof value === 'boolean') {
|
|
81
|
+
if (value) {
|
|
82
|
+
// The entire context is selected
|
|
83
|
+
contextConditions.push({ context });
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
// The context has subcontexts
|
|
87
|
+
const subcontexts = Object.keys(value).filter((subcontext) => {
|
|
88
|
+
return value[subcontext];
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
if (subcontexts.length > 0) {
|
|
92
|
+
contextConditions.push({
|
|
93
|
+
context,
|
|
94
|
+
subcontext: { $in: subcontexts },
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
if (contextConditions.length > 0) {
|
|
100
|
+
query.$or = contextConditions;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* -------------- Tag Filter -------------- */
|
|
104
|
+
|
|
105
|
+
const selectedTags = Object.keys(tagFilterState).filter((tag) => { return tagFilterState[tag]; });
|
|
106
|
+
if (selectedTags.length > 0) {
|
|
107
|
+
query.tags = { $in: selectedTags };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* --------- Action/Error Filter ---------- */
|
|
111
|
+
|
|
112
|
+
if (actionErrorFilterState.type) {
|
|
113
|
+
query.type = actionErrorFilterState.type;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (actionErrorFilterState.type === LogType.Error) {
|
|
117
|
+
if (actionErrorFilterState.errorMessage) {
|
|
118
|
+
// Add error message to the query.
|
|
119
|
+
// $i is used for case-insensitive search, and $regex is used for partial matching
|
|
120
|
+
query.errorMessage = {
|
|
121
|
+
$regex: actionErrorFilterState.errorMessage,
|
|
122
|
+
$options: 'i',
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (actionErrorFilterState.errorCode) {
|
|
127
|
+
query.errorCode = {
|
|
128
|
+
$regex: actionErrorFilterState.errorCode,
|
|
129
|
+
$options: 'i',
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (actionErrorFilterState.type === LogType.Action) {
|
|
135
|
+
const selectedTargets = (
|
|
136
|
+
Object.keys(actionErrorFilterState.target)
|
|
137
|
+
.filter((target) => {
|
|
138
|
+
return actionErrorFilterState.target[target];
|
|
139
|
+
})
|
|
140
|
+
);
|
|
141
|
+
const selectedActions = (
|
|
142
|
+
Object.keys(actionErrorFilterState.action)
|
|
143
|
+
.filter((action) => {
|
|
144
|
+
return actionErrorFilterState.action[action];
|
|
145
|
+
})
|
|
146
|
+
);
|
|
147
|
+
if (selectedTargets.length > 0) {
|
|
148
|
+
query.target = { $in: selectedTargets };
|
|
149
|
+
}
|
|
150
|
+
if (selectedActions.length > 0) {
|
|
151
|
+
query.action = { $in: selectedActions };
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/* ------------ Advanced Filter ----------- */
|
|
156
|
+
|
|
157
|
+
if (advancedFilterState.userFirstName) {
|
|
158
|
+
query.userFirstName = {
|
|
159
|
+
$regex: advancedFilterState.userFirstName,
|
|
160
|
+
$options: 'i',
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (advancedFilterState.userLastName) {
|
|
165
|
+
query.userLastName = {
|
|
166
|
+
$regex: advancedFilterState.userLastName,
|
|
167
|
+
$options: 'i',
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (advancedFilterState.userEmail) {
|
|
172
|
+
query.userEmail = {
|
|
173
|
+
$regex: advancedFilterState.userEmail,
|
|
174
|
+
$options: 'i',
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (advancedFilterState.userId) {
|
|
179
|
+
query.userId = Number.parseInt(advancedFilterState.userId, 10);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const roles: {
|
|
183
|
+
isLearner?: boolean,
|
|
184
|
+
isTTM?: boolean,
|
|
185
|
+
isAdmin?: boolean,
|
|
186
|
+
}[] = [];
|
|
187
|
+
if (advancedFilterState.includeLearners) {
|
|
188
|
+
roles.push({ isLearner: true });
|
|
189
|
+
}
|
|
190
|
+
if (advancedFilterState.includeTTMs) {
|
|
191
|
+
roles.push({ isTTM: true });
|
|
192
|
+
}
|
|
193
|
+
if (advancedFilterState.includeAdmins) {
|
|
194
|
+
roles.push({ isAdmin: true });
|
|
195
|
+
}
|
|
196
|
+
// If any roles are selected, add them to the query
|
|
197
|
+
if (roles.length > 0) {
|
|
198
|
+
// The $or operator is used to match any of the roles
|
|
199
|
+
// The $and operator is to ensure that other conditions in the query are met
|
|
200
|
+
query.$and = [{ $or: roles }];
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (advancedFilterState.courseId) {
|
|
204
|
+
query.courseId = Number.parseInt(advancedFilterState.courseId, 10);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (advancedFilterState.courseName) {
|
|
208
|
+
query.courseName = {
|
|
209
|
+
$regex: advancedFilterState.courseName,
|
|
210
|
+
$options: 'i',
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (advancedFilterState.isMobile !== undefined) {
|
|
215
|
+
query['device.isMobile'] = Boolean(advancedFilterState.isMobile);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (advancedFilterState.source) {
|
|
219
|
+
query.source = advancedFilterState.source;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (advancedFilterState.routePath) {
|
|
223
|
+
query.routePath = {
|
|
224
|
+
$regex: advancedFilterState.routePath,
|
|
225
|
+
$options: 'i',
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (advancedFilterState.routeTemplate) {
|
|
230
|
+
query.routeTemplate = {
|
|
231
|
+
$regex: advancedFilterState.routeTemplate,
|
|
232
|
+
$options: 'i',
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Query for logs
|
|
237
|
+
const response = await logCollection.findPaged({
|
|
238
|
+
query,
|
|
239
|
+
perPage: LOG_REVIEW_PAGE_SIZE,
|
|
240
|
+
pageNumber,
|
|
241
|
+
sortDescending: true,
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// Count documents if requested
|
|
245
|
+
if (countDocuments) {
|
|
246
|
+
const numPages = Math.ceil(
|
|
247
|
+
await logCollection.count(query)
|
|
248
|
+
/ LOG_REVIEW_PAGE_SIZE
|
|
249
|
+
);
|
|
250
|
+
return {
|
|
251
|
+
...response,
|
|
252
|
+
numPages,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Return response
|
|
257
|
+
return response;
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
export default getLogReviewerLogs;
|
|
@@ -6,17 +6,18 @@ 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
23
|
import ExpressKitErrorCode from '../types/ExpressKitErrorCode';
|
|
@@ -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
|