@plusscommunities/pluss-maintenance-aws-forms 2.1.7-beta.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/createJob.js +136 -0
- package/createJobType.js +64 -0
- package/db/maintenance/addMaintenanceJob.js +105 -0
- package/db/maintenance/editMaintenanceJob.js +18 -0
- package/db/maintenance/getJobEmail.js +28 -0
- package/deleteJob.js +74 -0
- package/deleteJobType.js +54 -0
- package/editJob.js +83 -0
- package/editJobStatus.js +81 -0
- package/editJobType.js +76 -0
- package/editNote.js +134 -0
- package/feature.config.js +255 -0
- package/getData.js +49 -0
- package/getJob.js +14 -0
- package/getJobType.js +47 -0
- package/getJobTypes.js +70 -0
- package/getJobs.js +63 -0
- package/integration/IntegrationStrategy.js +35 -0
- package/integration/archibus/ArchibusStrategy.js +463 -0
- package/integration/index.js +23 -0
- package/jobChanged.js +73 -0
- package/package-lock.json +7653 -0
- package/package.json +64 -0
- package/requests/assignRequest.js +106 -0
- package/requests/getAssignees.js +40 -0
- package/requests/getRequest.js +89 -0
- package/requests/getRequests.js +100 -0
- package/requests/helper/hasRequestPermission.js +25 -0
- package/requests/helper/isValidAssignee.js +23 -0
- package/scheduleJobImport.js +81 -0
- package/sendJobEmail.js +153 -0
- package/updateData.js +33 -0
- package/values.config.a.js +26 -0
- package/values.config.b.js +26 -0
- package/values.config.c.js +26 -0
- package/values.config.d.js +26 -0
- package/values.config.default.js +28 -0
- package/values.config.forms.js +28 -0
- package/values.config.js +28 -0
- package/watchJobs.js +177 -0
package/getJobs.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
const config = require("./config.json");
|
|
2
|
+
const { init } = require("@plusscommunities/pluss-core-aws/config");
|
|
3
|
+
const { getBody } = require("@plusscommunities/pluss-core-aws/helper");
|
|
4
|
+
const generateJsonResponse = require("@plusscommunities/pluss-core-aws/helper/generateJsonResponse");
|
|
5
|
+
const indexQuery = require("@plusscommunities/pluss-core-aws/db/common/indexQuery");
|
|
6
|
+
const validateMasterAuth = require("@plusscommunities/pluss-core-aws/helper/auth/validateMasterAuth");
|
|
7
|
+
const getSessionUser = require("@plusscommunities/pluss-core-aws/helper/auth/getSessionUser");
|
|
8
|
+
const { values } = require("./values.config");
|
|
9
|
+
|
|
10
|
+
module.exports.getJobs = async (event, context, callback) => {
|
|
11
|
+
init(config);
|
|
12
|
+
const data = getBody(event);
|
|
13
|
+
|
|
14
|
+
if (!data.site) {
|
|
15
|
+
return callback(
|
|
16
|
+
null,
|
|
17
|
+
generateJsonResponse(422, {
|
|
18
|
+
error: { message: "User Types fetch -- no site detected." },
|
|
19
|
+
})
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
const authorised = await validateMasterAuth(
|
|
25
|
+
event,
|
|
26
|
+
values.permissionMaintenanceTracking
|
|
27
|
+
);
|
|
28
|
+
const userId = authorised
|
|
29
|
+
? null
|
|
30
|
+
: await getSessionUser(event.headers.authkey);
|
|
31
|
+
console.log("getting jobs for user", userId);
|
|
32
|
+
|
|
33
|
+
const query = {
|
|
34
|
+
IndexName: "MaintenanceSiteIndex",
|
|
35
|
+
KeyConditionExpression: "site = :site",
|
|
36
|
+
ExpressionAttributeValues: {
|
|
37
|
+
":site": data.site,
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const res = await indexQuery(values.tableNameMaintenance, query);
|
|
43
|
+
let jobs = userId
|
|
44
|
+
? res.Items.filter((job) => job.userID === userId)
|
|
45
|
+
: res.Items;
|
|
46
|
+
if (data.status)
|
|
47
|
+
jobs = jobs.filter((j) => data.status.includes(j.status));
|
|
48
|
+
if (data.type) jobs = jobs.filter((j) => data.type.includes(j.type));
|
|
49
|
+
console.log("jobs count", jobs?.length);
|
|
50
|
+
return callback(null, generateJsonResponse(200, jobs));
|
|
51
|
+
} catch (error1) {
|
|
52
|
+
return callback(
|
|
53
|
+
null,
|
|
54
|
+
generateJsonResponse(200, {
|
|
55
|
+
userFetchFail: true,
|
|
56
|
+
message: "Fail on user query. Please try again.",
|
|
57
|
+
})
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
} catch (error) {
|
|
61
|
+
callback(null, generateJsonResponse(422, { fail: true, error }));
|
|
62
|
+
}
|
|
63
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
class IntegrationStrategy {
|
|
2
|
+
getEntityType = () => {
|
|
3
|
+
return "maintenance_null";
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
isValidIntegration = () => {
|
|
7
|
+
return false;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
getRefreshInterval = () => {
|
|
11
|
+
return 15 * 60 * 1000; // 15 minutes
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// creates a request on the integrated system
|
|
15
|
+
createRequest = async (request) => {
|
|
16
|
+
return null;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// gets a request from the integrated system
|
|
20
|
+
getRequest = async (requestId) => {
|
|
21
|
+
return null;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// refreshed a request from the integrated system
|
|
25
|
+
refreshFromSource = async (requestId) => {
|
|
26
|
+
return null;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// actions taken when a request is marked as completed
|
|
30
|
+
onCompleteRequest = async (request) => {
|
|
31
|
+
return null;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = IntegrationStrategy;
|
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
const axios = require("axios");
|
|
2
|
+
const moment = require("moment");
|
|
3
|
+
const _ = require("lodash");
|
|
4
|
+
const { encode } = require("base64-arraybuffer");
|
|
5
|
+
const IntegrationStrategy = require("../IntegrationStrategy");
|
|
6
|
+
const { log, getRowId } = require("@plusscommunities/pluss-core-aws/helper");
|
|
7
|
+
const editRef = require("@plusscommunities/pluss-core-aws/db/common/editRef");
|
|
8
|
+
const updateRef = require("@plusscommunities/pluss-core-aws/db/common/updateRef");
|
|
9
|
+
const indexQuery = require("@plusscommunities/pluss-core-aws/db/common/indexQuery");
|
|
10
|
+
const publishNotifications = require("@plusscommunities/pluss-core-aws/db/notifications/publishNotifications");
|
|
11
|
+
const getRef = require("@plusscommunities/pluss-core-aws/db/common/getRef");
|
|
12
|
+
const { values } = require("../../values.config");
|
|
13
|
+
|
|
14
|
+
class ArchibusStrategy extends IntegrationStrategy {
|
|
15
|
+
constructor(config) {
|
|
16
|
+
super();
|
|
17
|
+
this.baseUrl = config.BaseUrl; // base URL for the API
|
|
18
|
+
this.apiKeyHeader = config.APIKeyHeader; // header to use for API key
|
|
19
|
+
this.apiKey = config.APIKey; // API key
|
|
20
|
+
|
|
21
|
+
const url = new URL(this.baseUrl);
|
|
22
|
+
this.host = url.host;
|
|
23
|
+
|
|
24
|
+
this.statusMap = config.StatusMap;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Gets the entity type for the integration
|
|
29
|
+
*
|
|
30
|
+
* @returns {String} The entity type for the integration
|
|
31
|
+
*/
|
|
32
|
+
getEntityType = () => {
|
|
33
|
+
return `${values.serviceKey}_Archibus`;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Validates the integration
|
|
38
|
+
*
|
|
39
|
+
* @returns {Boolean} Whether the integration is valid
|
|
40
|
+
*/
|
|
41
|
+
isValidIntegration = () => {
|
|
42
|
+
return true;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Gets the refresh interval for the Archibus system
|
|
47
|
+
*
|
|
48
|
+
* @returns {Number} The refresh interval in milliseconds
|
|
49
|
+
*/
|
|
50
|
+
getRefreshInterval = () => {
|
|
51
|
+
return 15 * 60 * 1000; // 15 minutes
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Creates a request from the Archibus system
|
|
56
|
+
*
|
|
57
|
+
* @param {Object} request - Request definition on Pluss
|
|
58
|
+
* @returns {Boolean} Whether the request was created on Archibus
|
|
59
|
+
*/
|
|
60
|
+
createRequest = async (request) => {
|
|
61
|
+
const logId = log("Archibus:CreateRequest", "Start", request);
|
|
62
|
+
try {
|
|
63
|
+
const response = await axios({
|
|
64
|
+
method: "PUT",
|
|
65
|
+
url: `${this.baseUrl}/createWorkRequest`,
|
|
66
|
+
timeout: 15000,
|
|
67
|
+
headers: {
|
|
68
|
+
[this.apiKeyHeader]: this.apiKey,
|
|
69
|
+
"Content-Type": "application/json",
|
|
70
|
+
Host: this.host,
|
|
71
|
+
},
|
|
72
|
+
data: {
|
|
73
|
+
prob_type: "1.ON-SITE|1. MAINTENANCE",
|
|
74
|
+
requestor: "PLUSS",
|
|
75
|
+
description: `${request.title}${
|
|
76
|
+
_.isEmpty(request.description) ? "" : `\n\n${request.description}`
|
|
77
|
+
}${_.isEmpty(request.room) ? "" : `\n\nLocation: ${request.room}`}${
|
|
78
|
+
_.isEmpty(request.userName) ? "" : `\n\nName: ${request.userName}`
|
|
79
|
+
}${_.isEmpty(request.phone) ? "" : `\n\nPhone: ${request.phone}`}${
|
|
80
|
+
_.isEmpty(request.type) ? "" : `\n\nJob Type: ${request.type}`
|
|
81
|
+
}${
|
|
82
|
+
_.isEmpty(request.images)
|
|
83
|
+
? ""
|
|
84
|
+
: `\n\nImages: ${request.images.join("\n")}`
|
|
85
|
+
}`,
|
|
86
|
+
site_id: "2025", //TODO need to do site mapping 2025 is WooloowareShores in prod
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
log("Archibus:CreateRequest", "Response", response.data, logId);
|
|
90
|
+
|
|
91
|
+
// Save the ID to external entities for future reference
|
|
92
|
+
await updateRef("externalentities", {
|
|
93
|
+
RowId: `${this.getEntityType()}_${response.data.wrId}`,
|
|
94
|
+
LastUpdated: moment().valueOf(),
|
|
95
|
+
EntityType: this.getEntityType(),
|
|
96
|
+
InternalId: request.id,
|
|
97
|
+
ExternalId: response.data.wrId,
|
|
98
|
+
TrackedData: {},
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Save the Archibus ID as the job number
|
|
102
|
+
await editRef(values.tableNameMaintenance, "id", request.id, {
|
|
103
|
+
jobNo: response.data.wrId,
|
|
104
|
+
jobId: response.data.wrId + "",
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// add images
|
|
108
|
+
if (!_.isEmpty(request.images)) {
|
|
109
|
+
const imagePromises = [];
|
|
110
|
+
request.images.forEach((url) => {
|
|
111
|
+
imagePromises.push(this.addFileToRequest(response.data.wrId, url));
|
|
112
|
+
});
|
|
113
|
+
await Promise.all(imagePromises);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return true;
|
|
117
|
+
} catch (e) {
|
|
118
|
+
log("Archibus:CreateRequest", "Error", e, logId);
|
|
119
|
+
}
|
|
120
|
+
return false;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Fetches a request from the Archibus system
|
|
125
|
+
*
|
|
126
|
+
* @param {String} externalId - Id of the request on the Archibus
|
|
127
|
+
* @returns {Object} The request as it exists on Archibus
|
|
128
|
+
*/
|
|
129
|
+
getRequest = async (externalId) => {
|
|
130
|
+
const logId = log("Archibus:GetRequest", "Start", externalId);
|
|
131
|
+
try {
|
|
132
|
+
const response = await axios({
|
|
133
|
+
method: "GET",
|
|
134
|
+
url: `${this.baseUrl}/getWorkRequest/${externalId}`,
|
|
135
|
+
timeout: 15000,
|
|
136
|
+
headers: {
|
|
137
|
+
[this.apiKeyHeader]: this.apiKey,
|
|
138
|
+
"Content-Type": "application/json",
|
|
139
|
+
Host: this.host,
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
log("Archibus:GetRequest", "Response", response.data, logId);
|
|
143
|
+
|
|
144
|
+
return response.data;
|
|
145
|
+
} catch (e) {
|
|
146
|
+
log("Archibus:GetRequest", "Error", e, logId);
|
|
147
|
+
}
|
|
148
|
+
return null;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Refreshes a request from the Archibus system
|
|
153
|
+
*
|
|
154
|
+
* @param {String} requestId - Id of the request on Pluss.
|
|
155
|
+
* @param {String} externalId - Id of the request on Archibus.
|
|
156
|
+
* @param {Object} trackedData - The set of fields tracked.
|
|
157
|
+
* @returns {Boolean} Whether the request had any changes on Archibus.
|
|
158
|
+
*/
|
|
159
|
+
refreshFromSource = async (requestId, externalId, trackedData) => {
|
|
160
|
+
const logId = log("Archibus:RefreshFromSource", "Start", {
|
|
161
|
+
requestId,
|
|
162
|
+
externalId,
|
|
163
|
+
trackedData,
|
|
164
|
+
});
|
|
165
|
+
const request = await this.getRequest(externalId);
|
|
166
|
+
if (!request) {
|
|
167
|
+
log("Archibus:RefreshFromSource", "Result:NoResponse", false, logId);
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (trackedData && trackedData.status === request.status) {
|
|
172
|
+
log("Archibus:RefreshFromSource", "Result:UnchangedStatus", false, logId);
|
|
173
|
+
// status has not changed
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const statusToUse = this.statusMap[request.status];
|
|
178
|
+
log("Archibus:RefreshFromSource", "UpdatedStatus", statusToUse, logId);
|
|
179
|
+
|
|
180
|
+
if (statusToUse) {
|
|
181
|
+
let plussRequest = await getRef(
|
|
182
|
+
values.tableNameMaintenance,
|
|
183
|
+
"id",
|
|
184
|
+
requestId
|
|
185
|
+
);
|
|
186
|
+
// check how the new status map to what is saved in Pluss
|
|
187
|
+
|
|
188
|
+
if (statusToUse.Status !== plussRequest.status) {
|
|
189
|
+
// save updated status
|
|
190
|
+
|
|
191
|
+
plussRequest = await editRef(
|
|
192
|
+
values.tableNameMaintenance,
|
|
193
|
+
"id",
|
|
194
|
+
requestId,
|
|
195
|
+
{
|
|
196
|
+
status: statusToUse.Status,
|
|
197
|
+
}
|
|
198
|
+
);
|
|
199
|
+
log(
|
|
200
|
+
"Archibus:RefreshFromSource",
|
|
201
|
+
"SavedStatus",
|
|
202
|
+
statusToUse.Status,
|
|
203
|
+
logId
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
if (statusToUse.Notification) {
|
|
207
|
+
publishNotifications(
|
|
208
|
+
[plussRequest.userID],
|
|
209
|
+
values.activityMaintenanceJobStatusChanged,
|
|
210
|
+
plussRequest.site,
|
|
211
|
+
plussRequest.id,
|
|
212
|
+
plussRequest,
|
|
213
|
+
true
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// save tracked data
|
|
220
|
+
await editRef(
|
|
221
|
+
"externalentities",
|
|
222
|
+
"RowId",
|
|
223
|
+
`${this.getEntityType()}_${externalId}`,
|
|
224
|
+
{
|
|
225
|
+
TrackedData: {
|
|
226
|
+
status: request.status,
|
|
227
|
+
},
|
|
228
|
+
}
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
log("Archibus:RefreshFromSource", "Result", true, logId);
|
|
232
|
+
return true;
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Adds a comment to a request in Archibus
|
|
237
|
+
*
|
|
238
|
+
* @param {Number} externalId - Id of the request on Archibus.
|
|
239
|
+
* @param {String} comment - Text to add to Archibus request.
|
|
240
|
+
* @param {moment.Moment} time - The time to save against the comment
|
|
241
|
+
*/
|
|
242
|
+
addCommentToRequest = async (externalId, comment, time) => {
|
|
243
|
+
const logId = log("Archibus:AddComment", "Start", {
|
|
244
|
+
externalId,
|
|
245
|
+
comment,
|
|
246
|
+
time,
|
|
247
|
+
});
|
|
248
|
+
try {
|
|
249
|
+
// Format the time
|
|
250
|
+
const timeToUse = (time || moment()).format("YYYY-MM-DD hh:mm:ss");
|
|
251
|
+
|
|
252
|
+
// Generate the POST data
|
|
253
|
+
const postData = {
|
|
254
|
+
actionTime: timeToUse,
|
|
255
|
+
comments: comment,
|
|
256
|
+
wr_id: externalId,
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
log("Archibus:AddComment", "PostData", postData, logId);
|
|
260
|
+
|
|
261
|
+
// Save to Archibus
|
|
262
|
+
const response = await axios({
|
|
263
|
+
method: "POST",
|
|
264
|
+
url: `${this.baseUrl}/addCommentsToWRSteps`,
|
|
265
|
+
data: postData,
|
|
266
|
+
timeout: 15000,
|
|
267
|
+
headers: {
|
|
268
|
+
[this.apiKeyHeader]: this.apiKey,
|
|
269
|
+
"Content-Type": "application/json",
|
|
270
|
+
Host: this.host,
|
|
271
|
+
},
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
log("Archibus:AddComment", "ResponseStatus", response.status, logId);
|
|
275
|
+
|
|
276
|
+
return response;
|
|
277
|
+
} catch (error) {
|
|
278
|
+
log("Archibus:AddComment", "Error", error, logId);
|
|
279
|
+
}
|
|
280
|
+
return false;
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Adds a file to a request in Archibus
|
|
285
|
+
*
|
|
286
|
+
* @param {Number} externalId - Id of the request on Archibus.
|
|
287
|
+
* @param {String} fileUrl - URL of the file to attach
|
|
288
|
+
* @param {moment.Moment} time - The time to save against the file
|
|
289
|
+
* @returns
|
|
290
|
+
*/
|
|
291
|
+
addFileToRequest = async (externalId, fileUrl, time) => {
|
|
292
|
+
const logId = log("Archibus:AddFile", "Start", {
|
|
293
|
+
externalId,
|
|
294
|
+
fileUrl,
|
|
295
|
+
time,
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
// This endpoint is not currently functional. Instead, use the addCommentToRequest method to add a comment with the file URL.
|
|
299
|
+
// return this.addCommentToRequest(externalId, fileUrl, time);
|
|
300
|
+
|
|
301
|
+
try {
|
|
302
|
+
// Download the file content from the URL
|
|
303
|
+
const fileResponse = await axios.get(fileUrl, {
|
|
304
|
+
responseType: "arraybuffer",
|
|
305
|
+
});
|
|
306
|
+
log("Archibus:AddFile", "GotFileResponse", fileResponse.status, logId);
|
|
307
|
+
|
|
308
|
+
// Encode the file content in base64
|
|
309
|
+
const fileContentBase64 = encode(fileResponse.data);
|
|
310
|
+
log("Archibus:AddFile", "EncodedFileResponse", true, logId);
|
|
311
|
+
|
|
312
|
+
// Extract file name from the URL
|
|
313
|
+
const fileName = fileUrl.split("/").pop();
|
|
314
|
+
|
|
315
|
+
// Format the time
|
|
316
|
+
const timeToUse = (time || moment()).format("YYYY-MM-DD hh:mm:ss");
|
|
317
|
+
|
|
318
|
+
// Generate the POST data
|
|
319
|
+
const postData = {
|
|
320
|
+
actionTime: timeToUse,
|
|
321
|
+
docName: fileName,
|
|
322
|
+
docUrl: "https://anglicare.plusscommunities.com/",
|
|
323
|
+
fileContent: fileContentBase64,
|
|
324
|
+
fileName: fileName,
|
|
325
|
+
wrId: externalId,
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
log("Archibus:AddFile", "PostData", postData, logId);
|
|
329
|
+
|
|
330
|
+
// Save to Archibus
|
|
331
|
+
const response = await axios({
|
|
332
|
+
method: "POST",
|
|
333
|
+
url: `${this.baseUrl}/addDocumentToWorkRequest`,
|
|
334
|
+
data: postData,
|
|
335
|
+
timeout: 60000,
|
|
336
|
+
headers: {
|
|
337
|
+
[this.apiKeyHeader]: this.apiKey,
|
|
338
|
+
"Content-Type": "application/json",
|
|
339
|
+
Host: this.host,
|
|
340
|
+
},
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
log("Archibus:AddFile", "ResponseStatus", response.status, logId);
|
|
344
|
+
|
|
345
|
+
return response;
|
|
346
|
+
} catch (error) {
|
|
347
|
+
log("Archibus:AddFile", "Error", error, logId);
|
|
348
|
+
}
|
|
349
|
+
return false;
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
*
|
|
354
|
+
* @param {Object} request - Request definition on Pluss
|
|
355
|
+
* @returns {Boolean} Represents whether the actions were successful
|
|
356
|
+
*/
|
|
357
|
+
onCompleteRequest = async (request) => {
|
|
358
|
+
const logId = log("Archibus:OnComplete", "Start", {
|
|
359
|
+
Id: request.id,
|
|
360
|
+
});
|
|
361
|
+
try {
|
|
362
|
+
// get external id
|
|
363
|
+
const externalEntityQuery = await indexQuery("externalentities", {
|
|
364
|
+
IndexName: "InternalIdIndex",
|
|
365
|
+
KeyConditionExpression:
|
|
366
|
+
"EntityType = :entityType AND InternalId = :internalId",
|
|
367
|
+
ExpressionAttributeValues: {
|
|
368
|
+
":entityType": this.getEntityType(),
|
|
369
|
+
":internalId": request.id,
|
|
370
|
+
},
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
log(
|
|
374
|
+
"Archibus:OnComplete",
|
|
375
|
+
"ExternalLength",
|
|
376
|
+
externalEntityQuery.Items.length,
|
|
377
|
+
logId
|
|
378
|
+
);
|
|
379
|
+
if (_.isEmpty(externalEntityQuery.Items)) {
|
|
380
|
+
return true;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const externalId = externalEntityQuery.Items[0].ExternalId;
|
|
384
|
+
log("Archibus:OnComplete", "ExternalId", externalId, logId);
|
|
385
|
+
|
|
386
|
+
// get comments
|
|
387
|
+
const commentsQuery = {
|
|
388
|
+
IndexName: "CommentsEntityIdIndex",
|
|
389
|
+
KeyConditionExpression: "EntityId = :groupId",
|
|
390
|
+
ExpressionAttributeValues: {
|
|
391
|
+
":groupId": getRowId(request.id, values.serviceKey),
|
|
392
|
+
},
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
const commentsQueryRes = await indexQuery("comments", commentsQuery);
|
|
396
|
+
const comments = commentsQueryRes.Items;
|
|
397
|
+
log("Archibus:OnComplete", "CommentsLength", comments.length, logId);
|
|
398
|
+
|
|
399
|
+
const promises = [];
|
|
400
|
+
|
|
401
|
+
// save history as a comment
|
|
402
|
+
if (!_.isEmpty(request.history)) {
|
|
403
|
+
const historyComment = _.map(request.history, (entry) => {
|
|
404
|
+
if (entry.EntryType === "assignment") {
|
|
405
|
+
return "";
|
|
406
|
+
}
|
|
407
|
+
const time = moment(Number.parseFloat(entry.timestamp + "")).format(
|
|
408
|
+
"D MMM YYYY HH:mm:ss"
|
|
409
|
+
);
|
|
410
|
+
const user = entry.user ? ` by ${entry.user.displayName}` : "";
|
|
411
|
+
return `${time}: Marked ${entry.status}${user}`;
|
|
412
|
+
}).join("\n");
|
|
413
|
+
promises.push(this.addCommentToRequest(externalId, historyComment));
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// save history as a comment
|
|
417
|
+
if (!_.isEmpty(request.Notes)) {
|
|
418
|
+
// format comment to save
|
|
419
|
+
const notesComment = _.map(request.Notes, (entry) => {
|
|
420
|
+
const time = moment(Number.parseFloat(entry.Timestamp + "")).format(
|
|
421
|
+
"YYYY-MM-DD HH:mm:ss"
|
|
422
|
+
);
|
|
423
|
+
const user = entry.User ? entry.User.displayName : "Unknown User";
|
|
424
|
+
const note = entry.Note ? `Note: ${entry.Note}` : "No Note";
|
|
425
|
+
if (!_.isEmpty(entry.Attachments)) {
|
|
426
|
+
entry.Attachments.forEach((att) => {
|
|
427
|
+
promises.push(this.addFileToRequest(externalId, att.Source));
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
const attachments =
|
|
431
|
+
entry.Attachments && entry.Attachments.length > 0
|
|
432
|
+
? `Attachments: ${entry.Attachments.map(
|
|
433
|
+
(att) => `${att.Title} (${att.Source})`
|
|
434
|
+
).join(", ")}`
|
|
435
|
+
: "No Attachments";
|
|
436
|
+
return `${time} by ${user}\n${note}\n${attachments}`;
|
|
437
|
+
}).join("\n\n");
|
|
438
|
+
// save comment
|
|
439
|
+
promises.push(this.addCommentToRequest(externalId, notesComment));
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// save comments to Archibus
|
|
443
|
+
comments.forEach((comment) => {
|
|
444
|
+
const commentText = `${comment.User.displayName}:\n\n${
|
|
445
|
+
comment.Comment
|
|
446
|
+
}${!_.isEmpty(comment.Image) ? `\n\nImage: ${comment.Image}` : ""}}`;
|
|
447
|
+
const commentTime = moment(comment.Timestamp);
|
|
448
|
+
promises.push(
|
|
449
|
+
this.addCommentToRequest(externalId, commentText, commentTime)
|
|
450
|
+
);
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
await Promise.all(promises);
|
|
454
|
+
|
|
455
|
+
return true;
|
|
456
|
+
} catch (error) {
|
|
457
|
+
log("Archibus:OnComplete", "Error", error.toString(), logId);
|
|
458
|
+
}
|
|
459
|
+
return false;
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
module.exports = ArchibusStrategy;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const getString = require("@plusscommunities/pluss-core-aws/db/strings/getString");
|
|
2
|
+
const { getRowId, log } = require("@plusscommunities/pluss-core-aws/helper");
|
|
3
|
+
const ArchibusStrategy = require("./archibus/ArchibusStrategy");
|
|
4
|
+
const IntegrationStrategy = require("./IntegrationStrategy");
|
|
5
|
+
const { values } = require("../values.config");
|
|
6
|
+
|
|
7
|
+
exports.getStrategy = async (site) => {
|
|
8
|
+
let importConfig;
|
|
9
|
+
const logId = log("getStrategy", "Site", site);
|
|
10
|
+
try {
|
|
11
|
+
importConfig = await getString(
|
|
12
|
+
getRowId(site, `${values.serviceKey}integration`),
|
|
13
|
+
"plussSpace"
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
switch (importConfig.Strategy) {
|
|
17
|
+
case "Archibus":
|
|
18
|
+
return new ArchibusStrategy(importConfig);
|
|
19
|
+
default:
|
|
20
|
+
return new IntegrationStrategy();
|
|
21
|
+
}
|
|
22
|
+
} catch (e) {}
|
|
23
|
+
};
|
package/jobChanged.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
const { Marshaller } = require("@aws/dynamodb-auto-marshaller");
|
|
2
|
+
const config = require("./config.json");
|
|
3
|
+
const { init } = require("@plusscommunities/pluss-core-aws/config");
|
|
4
|
+
const logUpdate = require("@plusscommunities/pluss-core-aws/db/strings/logUpdate");
|
|
5
|
+
const { getStrategy } = require("./integration");
|
|
6
|
+
const { log } = require("@plusscommunities/pluss-core-aws/helper");
|
|
7
|
+
const { values } = require("./values.config");
|
|
8
|
+
|
|
9
|
+
const marshaller = new Marshaller();
|
|
10
|
+
|
|
11
|
+
const pushRequestToIntegration = async (request) => {
|
|
12
|
+
const integrationStrategy = await getStrategy(request.site);
|
|
13
|
+
await integrationStrategy.createRequest(request);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const onCompletedRequest = async (request) => {
|
|
17
|
+
const integrationStrategy = await getStrategy(request.site);
|
|
18
|
+
await integrationStrategy.onCompleteRequest(request);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Checks for any necessary integration actions based on the change in the request data
|
|
23
|
+
* @param {Object} request The new request data
|
|
24
|
+
* @param {Object} prevRequest The previous request data
|
|
25
|
+
*/
|
|
26
|
+
const checkIntegrationActions = async (request, prevRequest) => {
|
|
27
|
+
if (
|
|
28
|
+
request.ExtCreateRetry &&
|
|
29
|
+
request.ExtCreateRetry !== prevRequest.ExtCreateRetry
|
|
30
|
+
) {
|
|
31
|
+
log("checkIntegrationActions", "Retrying", true);
|
|
32
|
+
await pushRequestToIntegration(request);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (request.status === "Completed" && prevRequest.status !== "Completed") {
|
|
36
|
+
log("checkIntegrationActions", "CompletedRequest", true);
|
|
37
|
+
await onCompletedRequest(request);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
module.exports.jobChanged = (event, context, callback) => {
|
|
42
|
+
init(config);
|
|
43
|
+
|
|
44
|
+
event.Records.forEach((record) => {
|
|
45
|
+
let site;
|
|
46
|
+
if (record.eventName == "INSERT") {
|
|
47
|
+
console.log("INSERT");
|
|
48
|
+
const data = marshaller.unmarshallItem(record.dynamodb.NewImage);
|
|
49
|
+
console.log("Record: ", JSON.stringify(data));
|
|
50
|
+
|
|
51
|
+
site = data.site;
|
|
52
|
+
|
|
53
|
+
pushRequestToIntegration(data);
|
|
54
|
+
} else if (record.eventName == "MODIFY") {
|
|
55
|
+
console.log("MODIFY");
|
|
56
|
+
const data = marshaller.unmarshallItem(record.dynamodb.NewImage);
|
|
57
|
+
const previousData = marshaller.unmarshallItem(record.dynamodb.OldImage);
|
|
58
|
+
console.log("New record: ", JSON.stringify(data));
|
|
59
|
+
console.log("Old record: ", JSON.stringify(previousData));
|
|
60
|
+
|
|
61
|
+
checkIntegrationActions(data, previousData);
|
|
62
|
+
|
|
63
|
+
site = data.site;
|
|
64
|
+
} else if (record.eventName == "REMOVE") {
|
|
65
|
+
console.log("REMOVE");
|
|
66
|
+
const previousData = marshaller.unmarshallItem(record.dynamodb.OldImage);
|
|
67
|
+
console.log("Old record: ", JSON.stringify(previousData));
|
|
68
|
+
|
|
69
|
+
site = previousData.site;
|
|
70
|
+
}
|
|
71
|
+
logUpdate(site, values.updateKey);
|
|
72
|
+
});
|
|
73
|
+
};
|