@plusscommunities/pluss-maintenance-aws-forms 2.1.41 → 2.1.43

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.
@@ -100,6 +100,7 @@ module.exports = async (
100
100
  requestToSave.jobId = (requestToSave.jobNo || 0) + "";
101
101
  }
102
102
 
103
+ requestToSave.priority = "Low";
103
104
  await updateRef(values.tableNameMaintenance, requestToSave);
104
105
  return requestToSave.id;
105
106
  };
package/feature.config.js CHANGED
@@ -211,6 +211,7 @@ exports.serverless = {
211
211
  { name: "jobId", type: "S" },
212
212
  { name: "jobNo", type: "N" },
213
213
  { name: "userID", type: "S" },
214
+ { name: "AssigneeId", type: "S" },
214
215
  ],
215
216
  id: "id",
216
217
  indexes: [
@@ -239,6 +240,13 @@ exports.serverless = {
239
240
  { name: "userID", type: "RANGE" },
240
241
  ],
241
242
  },
243
+ {
244
+ name: "MaintenanceSiteAssigneeIndex",
245
+ keys: [
246
+ { name: "site", type: "HASH" },
247
+ { name: "AssigneeId", type: "RANGE" },
248
+ ],
249
+ },
242
250
  ],
243
251
  },
244
252
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plusscommunities/pluss-maintenance-aws-forms",
3
- "version": "2.1.41",
3
+ "version": "2.1.43",
4
4
  "description": "Extension package to enable maintenance on Pluss Communities Platform",
5
5
  "scripts": {
6
6
  "gc": "node ../../tools/gc ./",
@@ -16,8 +16,8 @@
16
16
  "copy:get": "echo $npm_package_name",
17
17
  "copy:set": "run(){ target='\\@plusscommunities\\/pluss-maintenance-aws'; ext=${1:-default}; [ $ext == 'default' ] && replace=$target || replace=$target'-'$ext; echo 'Setting target to '$replace; test -f values.config.$ext.js && cp -f values.config.$ext.js values.config.js; sed -i '' -e 's/'$target'.*\"/'$replace'\"/g' package.json; }; run",
18
18
  "copy:deploy": "for file in `ls ./values.config.*.js`; do dup=`echo $file | sed 's/.*values\\.config\\.\\(.*\\)\\.js/\\1/'`; npm run copy:set $dup; npm run deploy; done; npm run copy:set; npm run gs;",
19
- "copy:betaupload": "npm run betapach; for file in `ls ./values.config.*.js`; do dup=`echo $file | sed 's/.*values\\.config\\.\\(.*\\)\\.js/\\1/'`; npm run copy:set $dup; npm run betaupload; done; npm run copy:set;",
20
- "copy:upload": "npm run patch; for file in `ls ./values.config.*.js`; do dup=`echo $file | sed 's/.*values\\.config\\.\\(.*\\)\\.js/\\1/'`; npm run copy:set $dup; npm run upload; done; npm run copy:set;",
19
+ "copy:betaupload": "for file in `ls ./values.config.*.js`; do dup=`echo $file | sed 's/.*values\\.config\\.\\(.*\\)\\.js/\\1/'`; npm run copy:set $dup; npm run betaupload; done; npm run copy:set;",
20
+ "copy:upload": "for file in `ls ./values.config.*.js`; do dup=`echo $file | sed 's/.*values\\.config\\.\\(.*\\)\\.js/\\1/'`; npm run copy:set $dup; npm run upload; done; npm run copy:set;",
21
21
  "test": "jest tests -i"
22
22
  },
23
23
  "author": "Thorbjorn Kappel Davis",
@@ -5,6 +5,75 @@ const validateSiteAccess = require("@plusscommunities/pluss-core-aws/helper/auth
5
5
  const indexQuery = require("@plusscommunities/pluss-core-aws/db/common/indexQuery");
6
6
  const { values } = require("../values.config");
7
7
 
8
+ // Normalise legacy/null status to "Open" (null = very old jobs, "Unassigned" = pre-rename)
9
+ const STATUS_OPEN = "Open";
10
+ const normalizeStatus = (status) =>
11
+ !status || status === "Unassigned" ? STATUS_OPEN : status;
12
+
13
+ // HACK: Lax "complete" match handles minor label variations across sites
14
+ const isCompleted = (status) =>
15
+ status && status.toLowerCase().includes("complete");
16
+
17
+ // Priority defaults to "Low" when not set (not set on creation)
18
+ const DEFAULT_PRIORITY = "Low";
19
+ const normalizePriority = (priority) =>
20
+ priority == null ? DEFAULT_PRIORITY : priority;
21
+
22
+ // Minimum number of filtered results to return before stopping.
23
+ // Because DynamoDB pages are unfiltered and we filter after query,
24
+ // a single page may yield very few matching results. We keep
25
+ // fetching pages until we have this many items to return.
26
+ const MIN_RESULT_COUNT = 50;
27
+
28
+ /**
29
+ * Apply all post-query filters to a set of jobs.
30
+ * Extracted so the same logic runs on every auto-fill page.
31
+ */
32
+ const filterJobs = (jobs, qParams, authorised, assigneeTracking, userId) => {
33
+ let filtered = jobs;
34
+
35
+ if (qParams.status) {
36
+ if (qParams.status === "Incomplete") {
37
+ filtered = filtered.filter((j) => !isCompleted(normalizeStatus(j.status)));
38
+ } else {
39
+ filtered = filtered.filter((j) => qParams.status.includes(normalizeStatus(j.status)));
40
+ }
41
+ }
42
+
43
+ if (qParams.priority) {
44
+ filtered = filtered.filter((j) => qParams.priority.includes(normalizePriority(j.priority)));
45
+ }
46
+
47
+ if (qParams.type) {
48
+ filtered = filtered.filter((j) => qParams.type.includes(j.type));
49
+ }
50
+
51
+ if (!authorised && assigneeTracking) {
52
+ filtered = filtered.filter((j) => j.AssigneeId === userId || j.userID === userId);
53
+ }
54
+
55
+ if (qParams.startTime) {
56
+ const startTime = parseInt(qParams.startTime, 10);
57
+ filtered = filtered.filter((j) => j.createdUnix >= startTime);
58
+ }
59
+ if (qParams.endTime) {
60
+ const endTime = parseInt(qParams.endTime, 10);
61
+ filtered = filtered.filter((j) => j.createdUnix <= endTime);
62
+ }
63
+
64
+ if (qParams.search) {
65
+ const searchLower = qParams.search.toLowerCase();
66
+ filtered = filtered.filter((j) => {
67
+ if (j.jobId && j.jobId === qParams.search) return true;
68
+ if (j.room && j.room.toLowerCase().indexOf(searchLower) > -1) return true;
69
+ if (j.title && j.title.toLowerCase().indexOf(searchLower) > -1) return true;
70
+ return false;
71
+ });
72
+ }
73
+
74
+ return filtered;
75
+ };
76
+
8
77
  module.exports = async (event) => {
9
78
  const qParams = event.queryStringParameters;
10
79
  const logId = log("getRequests", "Params", qParams);
@@ -59,6 +128,13 @@ module.exports = async (event) => {
59
128
  ":userId": userId,
60
129
  },
61
130
  };
131
+
132
+ // Use the assignee GSI when filtering by assignee (avoids fetching the entire site's jobs)
133
+ if (qParams.assignee && (authorised || assigneeTracking)) {
134
+ query.IndexName = "MaintenanceSiteAssigneeIndex";
135
+ query.KeyConditionExpression = "site = :site AND AssigneeId = :assigneeId";
136
+ query.ExpressionAttributeValues[":assigneeId"] = qParams.assignee;
137
+ }
62
138
  log("getRequests", "query", query, logId);
63
139
 
64
140
  // check whether pagination is applied
@@ -68,69 +144,28 @@ module.exports = async (event) => {
68
144
  } catch (e) {}
69
145
  }
70
146
 
71
- // get jobs
72
- const result = await indexQuery(values.tableNameMaintenance, query);
73
- let jobs = result.Items;
74
-
75
- log("getRequests", "LastEvaluatedKey", result.LastEvaluatedKey, logId);
76
- log("getRequests", "JobsLength", jobs.length, logId);
77
-
78
- // filter on status
79
- if (qParams.status) {
80
- jobs = jobs.filter((j) => qParams.status.includes(j.status));
81
- log("getRequests", "FilteredOnStatus", jobs.length, logId);
82
- }
83
-
84
- // filter on priority
85
- if (qParams.priority) {
86
- jobs = jobs.filter((j) => qParams.priority.includes(j.priority));
87
- log("getRequests", "FilterOnPriority", jobs.length, logId);
88
- }
89
-
90
- // filter on type
91
- if (qParams.type) {
92
- jobs = jobs.filter((j) => qParams.type.includes(j.type));
93
- log("getRequests", "FilteredOnType", jobs.length, logId);
94
- }
95
-
96
- // filter on assignee (for users with tracking permission)
97
- if (qParams.assignee) {
98
- jobs = jobs.filter((j) => j.AssigneeId === qParams.assignee);
99
- log("getRequests", "FilteredOnAssigneeFilter", jobs.length, logId);
100
- }
101
-
102
- // filter to assigned jobs
103
- if (!authorised && assigneeTracking) {
104
- jobs = jobs.filter((j) => j.AssigneeId === userId || j.userID === userId);
105
- log("getRequests", "FilteredOnAssignee", jobs.length, logId);
147
+ // get first page of jobs
148
+ let result = await indexQuery(values.tableNameMaintenance, query);
149
+ let allJobs = filterJobs(result.Items, qParams, authorised, assigneeTracking, userId);
150
+ let lastKey = result.LastEvaluatedKey;
151
+
152
+ log("getRequests", "LastEvaluatedKey", lastKey, logId);
153
+ log("getRequests", "FirstPageFiltered", allJobs.length, logId);
154
+
155
+ // auto-fill: keep fetching pages until we have MIN_RESULT_COUNT filtered results
156
+ while (lastKey && allJobs.length < MIN_RESULT_COUNT) {
157
+ const nextQuery = { ...query, ExclusiveStartKey: lastKey };
158
+ result = await indexQuery(values.tableNameMaintenance, nextQuery);
159
+ const filtered = filterJobs(result.Items, qParams, authorised, assigneeTracking, userId);
160
+ allJobs = [...allJobs, ...filtered];
161
+ lastKey = result.LastEvaluatedKey;
106
162
  }
107
163
 
108
- // filter on time range
109
- if (qParams.startTime) {
110
- const startTime = parseInt(qParams.startTime, 10);
111
- jobs = jobs.filter((j) => j.createdUnix >= startTime);
112
- log("getRequests", "FilteredOnStartTime", jobs.length, logId);
113
- }
114
- if (qParams.endTime) {
115
- const endTime = parseInt(qParams.endTime, 10);
116
- jobs = jobs.filter((j) => j.createdUnix <= endTime);
117
- log("getRequests", "FilteredOnEndTime", jobs.length, logId);
118
- }
119
-
120
- // filter on search text (jobId exact match, or room/title contains)
121
- if (qParams.search) {
122
- const searchLower = qParams.search.toLowerCase();
123
- jobs = jobs.filter((j) => {
124
- if (j.jobId && j.jobId === qParams.search) return true;
125
- if (j.room && j.room.toLowerCase().indexOf(searchLower) > -1) return true;
126
- if (j.title && j.title.toLowerCase().indexOf(searchLower) > -1) return true;
127
- return false;
128
- });
129
- log("getRequests", "FilteredOnSearch", jobs.length, logId);
130
- }
164
+ log("getRequests", "TotalFiltered", allJobs.length, logId);
165
+ log("getRequests", "PagesFetched", lastKey ? "more available" : "exhausted", logId);
131
166
 
132
167
  // compile results
133
- const results = { Items: jobs, LastKey: result.LastEvaluatedKey };
168
+ const results = { Items: allJobs, LastKey: lastKey };
134
169
  log("getRequests", "Done", true, logId);
135
170
  return { status: 200, data: results };
136
171
  };