@plusscommunities/pluss-maintenance-aws-feedback 2.1.15-beta.1

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/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,50 @@
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's status has changed
30
+ onStatusChanged = async (request) => {
31
+ return null;
32
+ };
33
+
34
+ // actions taken when a comment has been added to a request
35
+ onCommentAdded = async (request) => {
36
+ return null;
37
+ };
38
+
39
+ // actions taken when a note has been added to a request
40
+ onNotesAdded = async (request) => {
41
+ return null;
42
+ };
43
+
44
+ // actions taken when a request is marked as completed
45
+ onCompleteRequest = async (request) => {
46
+ return null;
47
+ };
48
+ }
49
+
50
+ module.exports = IntegrationStrategy;
@@ -0,0 +1,591 @@
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 getString = require("@plusscommunities/pluss-core-aws/db/strings/getString");
13
+ const { values } = require("../../values.config");
14
+
15
+ class ArchibusStrategy extends IntegrationStrategy {
16
+ constructor(config) {
17
+ super();
18
+ this.baseUrl = config.BaseUrl; // base URL for the API
19
+ this.apiKeyHeader = config.APIKeyHeader; // header to use for API key
20
+ this.apiKey = config.APIKey; // API key
21
+
22
+ const url = new URL(this.baseUrl);
23
+ this.host = url.host;
24
+
25
+ this.statusMap = config.StatusMap;
26
+ this.siteMap = config.SiteMap ?? {};
27
+ this.buildingCodes = [];
28
+ }
29
+
30
+ /**
31
+ * Gets the entity type for the integration
32
+ *
33
+ * @returns {String} The entity type for the integration
34
+ */
35
+ getEntityType = () => {
36
+ return `${values.serviceKey}_Archibus`;
37
+ };
38
+
39
+ /**
40
+ * Validates the integration
41
+ *
42
+ * @returns {Boolean} Whether the integration is valid
43
+ */
44
+ isValidIntegration = () => {
45
+ return true;
46
+ };
47
+
48
+ /**
49
+ * Gets the refresh interval for the Archibus system
50
+ *
51
+ * @returns {Number} The refresh interval in milliseconds
52
+ */
53
+ getRefreshInterval = () => {
54
+ return 15 * 60 * 1000; // 15 minutes
55
+ };
56
+
57
+ /**
58
+ * Creates a request from the Archibus system
59
+ *
60
+ * @param {Object} request - Request definition on Pluss
61
+ * @param {Object} mockResponse - Mock response from Archibus to simulate response
62
+ * @returns {Boolean} Whether the request was created on Archibus
63
+ */
64
+ createRequest = async (request, mockResponse = null) => {
65
+ const logId = log("Archibus:CreateRequest", "Start", request);
66
+
67
+ let siteId = this.siteMap[request.site];
68
+ let buildingCode = null;
69
+ if (request.room) {
70
+ if (this.buildingCodes.length === 0) {
71
+ this.buildingCodes = await getString(
72
+ getRowId(request.site, `${values.serviceKey}buildingcodes`),
73
+ "plussSpace"
74
+ );
75
+ }
76
+ const building = this.buildingCodes.find((b) => {
77
+ const address = request.room.toLowerCase();
78
+ const search = b.SearchString.toLowerCase();
79
+ const name = b.BuildingName.toLowerCase();
80
+ return address.includes(search) || address.includes(name);
81
+ });
82
+
83
+ if (building?.SiteCode) siteId = building.SiteCode.toString();
84
+ buildingCode = building?.BuildingCode;
85
+ }
86
+ if (!siteId) return false;
87
+
88
+ try {
89
+ const data = {
90
+ prob_type: "1.ON-SITE|1. MAINTENANCE",
91
+ requestor: "PLUSS",
92
+ description: `${request.title}${
93
+ _.isEmpty(request.description) ? "" : `\n\n${request.description}`
94
+ }${_.isEmpty(request.room) ? "" : `\n\nLocation: ${request.room}`}${
95
+ _.isEmpty(request.userName) ? "" : `\n\nName: ${request.userName}`
96
+ }${_.isEmpty(request.phone) ? "" : `\n\nPhone: ${request.phone}`}${
97
+ _.isEmpty(request.type) ? "" : `\n\nJob Type: ${request.type}`
98
+ }${
99
+ _.isEmpty(request.images)
100
+ ? ""
101
+ : `\n\nImages: ${request.images.join("\n")}`
102
+ }`,
103
+ site_id: siteId,
104
+ };
105
+ if (buildingCode) data.bl_id = buildingCode;
106
+ log("Archibus:CreateRequest", "Request", data, logId);
107
+
108
+ const response =
109
+ mockResponse ??
110
+ (await axios({
111
+ method: "PUT",
112
+ url: `${this.baseUrl}/createWorkRequest`,
113
+ timeout: 30000,
114
+ headers: {
115
+ [this.apiKeyHeader]: this.apiKey,
116
+ "Content-Type": "application/json",
117
+ Host: this.host,
118
+ },
119
+ data,
120
+ }));
121
+ log("Archibus:CreateRequest", "Response", response.data, logId);
122
+
123
+ // Save the ID to external entities for future reference
124
+ await updateRef("externalentities", {
125
+ RowId: `${this.getEntityType()}_${response.data.wrId}`,
126
+ LastUpdated: moment().valueOf(),
127
+ EntityType: this.getEntityType(),
128
+ InternalId: request.id,
129
+ ExternalId: response.data.wrId,
130
+ TrackedData: {},
131
+ });
132
+
133
+ // Save the Archibus ID as the job number
134
+ await editRef(values.tableNameMaintenance, "id", request.id, {
135
+ jobNo: response.data.wrId,
136
+ jobId: response.data.wrId + "",
137
+ });
138
+
139
+ // add images
140
+ if (!mockResponse && !_.isEmpty(request.images)) {
141
+ const imagePromises = [];
142
+ request.images.forEach((url) => {
143
+ imagePromises.push(this.addFileToRequest(response.data.wrId, url));
144
+ });
145
+ await Promise.all(imagePromises);
146
+ }
147
+
148
+ return true;
149
+ } catch (e) {
150
+ log("Archibus:CreateRequest", "Error", e, logId);
151
+ }
152
+ return false;
153
+ };
154
+
155
+ /**
156
+ * Fetches a request from the Archibus system
157
+ *
158
+ * @param {String} externalId - Id of the request on the Archibus
159
+ * @returns {Object} The request as it exists on Archibus
160
+ */
161
+ getRequest = async (externalId) => {
162
+ const logId = log("Archibus:GetRequest", "Start", externalId);
163
+ try {
164
+ const response = await axios({
165
+ method: "GET",
166
+ url: `${this.baseUrl}/getWorkRequest/${externalId}`,
167
+ timeout: 30000,
168
+ headers: {
169
+ [this.apiKeyHeader]: this.apiKey,
170
+ "Content-Type": "application/json",
171
+ Host: this.host,
172
+ },
173
+ });
174
+ log("Archibus:GetRequest", "Response", response.data, logId);
175
+
176
+ return response.data;
177
+ } catch (e) {
178
+ log("Archibus:GetRequest", "Error", e, logId);
179
+ }
180
+ return null;
181
+ };
182
+
183
+ /**
184
+ * Refreshes a request from the Archibus system
185
+ *
186
+ * @param {String} requestId - Id of the request on Pluss.
187
+ * @param {String} externalId - Id of the request on Archibus.
188
+ * @param {Object} trackedData - The set of fields tracked.
189
+ * @returns {Boolean} Whether the request had any changes on Archibus.
190
+ */
191
+ refreshFromSource = async (requestId, externalId, trackedData) => {
192
+ const logId = log("Archibus:RefreshFromSource", "Start", {
193
+ requestId,
194
+ externalId,
195
+ trackedData,
196
+ });
197
+ const request = await this.getRequest(externalId);
198
+ if (!request) {
199
+ log("Archibus:RefreshFromSource", "Result:NoResponse", false, logId);
200
+ return false;
201
+ }
202
+
203
+ if (trackedData && trackedData.status === request.status) {
204
+ log("Archibus:RefreshFromSource", "Result:UnchangedStatus", false, logId);
205
+ // status has not changed
206
+ return false;
207
+ }
208
+
209
+ const statusToUse = this.statusMap[request.status];
210
+ log("Archibus:RefreshFromSource", "UpdatedStatus", statusToUse, logId);
211
+
212
+ if (statusToUse) {
213
+ let plussRequest = await getRef(
214
+ values.tableNameMaintenance,
215
+ "id",
216
+ requestId
217
+ );
218
+ // check how the new status map to what is saved in Pluss
219
+
220
+ if (statusToUse.Status !== plussRequest.status) {
221
+ // save updated status
222
+
223
+ plussRequest = await editRef(
224
+ values.tableNameMaintenance,
225
+ "id",
226
+ requestId,
227
+ {
228
+ status: statusToUse.Status,
229
+ }
230
+ );
231
+ log(
232
+ "Archibus:RefreshFromSource",
233
+ "SavedStatus",
234
+ statusToUse.Status,
235
+ logId
236
+ );
237
+
238
+ if (statusToUse.Notification) {
239
+ publishNotifications(
240
+ [plussRequest.userID],
241
+ values.activityMaintenanceJobStatusChanged,
242
+ plussRequest.site,
243
+ plussRequest.id,
244
+ plussRequest,
245
+ true
246
+ );
247
+ }
248
+ }
249
+ }
250
+
251
+ // save tracked data
252
+ await editRef(
253
+ "externalentities",
254
+ "RowId",
255
+ `${this.getEntityType()}_${externalId}`,
256
+ {
257
+ TrackedData: {
258
+ status: request.status,
259
+ },
260
+ }
261
+ );
262
+
263
+ log("Archibus:RefreshFromSource", "Result", true, logId);
264
+ return true;
265
+ };
266
+
267
+ /**
268
+ * Adds a comment to a request in Archibus
269
+ *
270
+ * @param {Number} externalId - Id of the request on Archibus.
271
+ * @param {String} comment - Text to add to Archibus request.
272
+ * @param {moment.Moment} time - The time to save against the comment
273
+ */
274
+ addCommentToRequest = async (externalId, comment, time) => {
275
+ const logId = log("Archibus:AddComment", "Start", {
276
+ externalId,
277
+ comment,
278
+ time,
279
+ });
280
+ try {
281
+ // Format the time
282
+ const timeToUse = (time || moment()).format("YYYY-MM-DD hh:mm:ss");
283
+
284
+ // Generate the POST data
285
+ const postData = {
286
+ actionTime: timeToUse,
287
+ comments: comment,
288
+ wr_id: externalId,
289
+ };
290
+
291
+ log("Archibus:AddComment", "PostData", postData, logId);
292
+
293
+ // Save to Archibus
294
+ const response = await axios({
295
+ method: "POST",
296
+ url: `${this.baseUrl}/addCommentsToWRSteps`,
297
+ data: postData,
298
+ timeout: 30000,
299
+ headers: {
300
+ [this.apiKeyHeader]: this.apiKey,
301
+ "Content-Type": "application/json",
302
+ Host: this.host,
303
+ },
304
+ });
305
+
306
+ log("Archibus:AddComment", "ResponseStatus", response.status, logId);
307
+
308
+ return response;
309
+ } catch (error) {
310
+ log("Archibus:AddComment", "Error", error, logId);
311
+ }
312
+ return false;
313
+ };
314
+
315
+ /**
316
+ * Adds a file to a request in Archibus
317
+ *
318
+ * @param {Number} externalId - Id of the request on Archibus.
319
+ * @param {String} fileUrl - URL of the file to attach
320
+ * @param {moment.Moment} time - The time to save against the file
321
+ * @returns
322
+ */
323
+ addFileToRequest = async (externalId, fileUrl, time) => {
324
+ const logId = log("Archibus:AddFile", "Start", {
325
+ externalId,
326
+ fileUrl,
327
+ time,
328
+ });
329
+
330
+ // This endpoint is not currently functional. Instead, use the addCommentToRequest method to add a comment with the file URL.
331
+ // return this.addCommentToRequest(externalId, fileUrl, time);
332
+
333
+ try {
334
+ // Download the file content from the URL
335
+ const fileResponse = await axios.get(fileUrl, {
336
+ responseType: "arraybuffer",
337
+ });
338
+ log("Archibus:AddFile", "GotFileResponse", fileResponse.status, logId);
339
+
340
+ // Encode the file content in base64
341
+ const fileContentBase64 = encode(fileResponse.data);
342
+ log("Archibus:AddFile", "EncodedFileResponse", true, logId);
343
+
344
+ // Extract file name from the URL
345
+ const fileName = fileUrl.split("/").pop();
346
+
347
+ // Format the time
348
+ const timeToUse = (time || moment()).format("YYYY-MM-DD hh:mm:ss");
349
+
350
+ // Generate the POST data
351
+ const postData = {
352
+ actionTime: timeToUse,
353
+ docName: fileName,
354
+ docUrl: "https://anglicare.plusscommunities.com/",
355
+ fileContent: fileContentBase64,
356
+ fileName: fileName,
357
+ wrId: externalId,
358
+ };
359
+
360
+ log("Archibus:AddFile", "PostData", postData, logId);
361
+
362
+ // Save to Archibus
363
+ const response = await axios({
364
+ method: "POST",
365
+ url: `${this.baseUrl}/addDocumentToWorkRequest`,
366
+ data: postData,
367
+ timeout: 60000,
368
+ headers: {
369
+ [this.apiKeyHeader]: this.apiKey,
370
+ "Content-Type": "application/json",
371
+ Host: this.host,
372
+ },
373
+ });
374
+
375
+ log("Archibus:AddFile", "ResponseStatus", response.status, logId);
376
+
377
+ return response;
378
+ } catch (error) {
379
+ log("Archibus:AddFile", "Error", error, logId);
380
+ }
381
+ return false;
382
+ };
383
+
384
+ /**
385
+ * Get Archibus Id of the request
386
+ *
387
+ * @param {Object} request - Request definition on Pluss
388
+ * @returns {Number} Id of the request on Archibus (null if not exists)
389
+ */
390
+ getExternalId = async (request) => {
391
+ const logId = log("Archibus:GetExternalId", "Start", { Id: request.id });
392
+
393
+ // get external id
394
+ const externalEntityQuery = await indexQuery("externalentities", {
395
+ IndexName: "InternalIdIndex",
396
+ KeyConditionExpression:
397
+ "EntityType = :entityType AND InternalId = :internalId",
398
+ ExpressionAttributeValues: {
399
+ ":entityType": this.getEntityType(),
400
+ ":internalId": request.id,
401
+ },
402
+ });
403
+
404
+ log(
405
+ "Archibus:GetExternalId",
406
+ "ExternalLength",
407
+ externalEntityQuery.Items.length,
408
+ logId
409
+ );
410
+ if (_.isEmpty(externalEntityQuery.Items)) {
411
+ return null;
412
+ }
413
+
414
+ const externalId = externalEntityQuery.Items[0].ExternalId;
415
+ log("Archibus:GetExternalId", "ExternalId", externalId, logId);
416
+
417
+ return externalId;
418
+ };
419
+
420
+ /**
421
+ * Get latest comment for a request
422
+ *
423
+ * @param {Object} request - Request definition on Pluss
424
+ * @param {String} entityKey - Request entity key (e.g. maintenancerequest)
425
+ * @returns {Object} Latest comment (null if not exists)
426
+ */
427
+ getLatestComment = async (request, entityKey) => {
428
+ const logId = log("Archibus:GetLatestComment", "Start", { Id: request.id });
429
+
430
+ // get comments
431
+ const commentsQuery = {
432
+ IndexName: "CommentsEntityIdIndex",
433
+ KeyConditionExpression: "EntityId = :groupId",
434
+ ExpressionAttributeValues: {
435
+ ":groupId": getRowId(request.id, entityKey),
436
+ },
437
+ };
438
+
439
+ const commentsQueryRes = await indexQuery("comments", commentsQuery);
440
+ const comments = _.orderBy(commentsQueryRes.Items, "Timestamp", "desc");
441
+ log(
442
+ "Archibus:GetLatestComment",
443
+ `CommentsLength - ${entityKey}`,
444
+ comments.length,
445
+ logId
446
+ );
447
+
448
+ return comments.length > 0 ? comments[0] : null;
449
+ };
450
+
451
+ /**
452
+ * Perform actions when a task's status has changed
453
+ *
454
+ * @param {Object} request - Request definition on Pluss
455
+ * @returns {Boolean} Represents whether the actions were successful
456
+ */
457
+ onStatusChanged = async (request) => {
458
+ const logId = log("Archibus:OnStatusChanged", "Start", { Id: request.id });
459
+
460
+ try {
461
+ const externalId = await this.getExternalId(request);
462
+ if (_.isNil(externalId)) return true;
463
+
464
+ const statues = _.orderBy(
465
+ (request.history ?? []).filter(
466
+ (entry) => entry.EntryType !== "assignment"
467
+ ),
468
+ "timestamp",
469
+ "desc"
470
+ );
471
+ const latest = statues.length > 0 ? statues[0] : null;
472
+
473
+ if (latest) {
474
+ const time = moment(Number.parseFloat(latest.timestamp + "")).format(
475
+ "D MMM YYYY HH:mm:ss"
476
+ );
477
+ const user = latest.user ? ` by ${latest.user.displayName}` : "";
478
+ const comment = `${time}: Marked ${latest.status}${user}`;
479
+ await this.addCommentToRequest(externalId, comment);
480
+ }
481
+
482
+ return true;
483
+ } catch (error) {
484
+ log("Archibus:OnStatusChanged", "Error", error.toString(), logId);
485
+ }
486
+ return false;
487
+ };
488
+
489
+ /**
490
+ * Perform actions when a a comment has been added to a task
491
+ *
492
+ * @param {Object} request - Request definition on Pluss
493
+ * @returns {Boolean} Represents whether the actions were successful
494
+ */
495
+ onCommentAdded = async (request) => {
496
+ const logId = log("Archibus:OnCommentAdded", "Start", {
497
+ Id: request.id,
498
+ });
499
+
500
+ try {
501
+ const externalId = await this.getExternalId(request);
502
+ if (_.isNil(externalId)) return true;
503
+
504
+ let comment = await this.getLatestComment(request, values.serviceKey);
505
+ if (!comment)
506
+ comment = await this.getLatestComment(request, values.entityKey);
507
+
508
+ if (comment) {
509
+ const commentText = `${comment.User.displayName}:\n\n${
510
+ comment.Comment
511
+ }${!_.isEmpty(comment.Image) ? `\n\nImage: ${comment.Image}` : ""}}`;
512
+ const commentTime = moment(comment.Timestamp);
513
+ await this.addCommentToRequest(externalId, commentText, commentTime);
514
+ }
515
+
516
+ return true;
517
+ } catch (error) {
518
+ log("Archibus:OnCommentAdded", "Error", error.toString(), logId);
519
+ }
520
+ return false;
521
+ };
522
+
523
+ /**
524
+ * Perform actions when a note has been added to a task
525
+ *
526
+ * @param {Object} request - Request definition on Pluss
527
+ * @returns {Boolean} Represents whether the actions were successful
528
+ */
529
+ onNotesAdded = async (request) => {
530
+ const logId = log("Archibus:OnNotesAdded", "Start", { Id: request.id });
531
+
532
+ try {
533
+ const externalId = await this.getExternalId(request);
534
+ if (_.isNil(externalId)) return true;
535
+
536
+ const notes = _.orderBy(request.Notes ?? [], "Timestamp", "desc");
537
+ const latest = notes.length > 0 ? notes[0] : null;
538
+
539
+ if (latest) {
540
+ const promises = [];
541
+
542
+ const time = moment(Number.parseFloat(latest.Timestamp + "")).format(
543
+ "YYYY-MM-DD HH:mm:ss"
544
+ );
545
+ const user = latest.User ? latest.User.displayName : "Unknown User";
546
+ const note = latest.Note ? `Note: ${latest.Note}` : "No Note";
547
+ if (!_.isEmpty(latest.Attachments)) {
548
+ latest.Attachments.forEach((att) => {
549
+ promises.push(this.addFileToRequest(externalId, att.Source));
550
+ });
551
+ }
552
+ const attachments =
553
+ latest.Attachments && latest.Attachments.length > 0
554
+ ? `Attachments: ${latest.Attachments.map(
555
+ (att) => `${att.Title} (${att.Source})`
556
+ ).join(", ")}`
557
+ : "No Attachments";
558
+ if (!_.isEmpty(latest.Images)) {
559
+ latest.Images.forEach((image) => {
560
+ promises.push(this.addFileToRequest(externalId, image));
561
+ });
562
+ }
563
+ const images =
564
+ latest.Images && latest.Images.length > 0
565
+ ? `Images: ${latest.Images.map((image) => image).join(", ")}`
566
+ : "No Images";
567
+ const comment = `${time} by ${user}\n${note}\n${attachments}\n${images}`;
568
+ promises.push(this.addCommentToRequest(externalId, comment));
569
+
570
+ await Promise.all(promises);
571
+ }
572
+
573
+ return true;
574
+ } catch (error) {
575
+ log("Archibus:OnNotesAdded", "Error", error.toString(), logId);
576
+ }
577
+ return false;
578
+ };
579
+
580
+ /**
581
+ * Perform completion actions when a task is completed
582
+ *
583
+ * @param {Object} request - Request definition on Pluss
584
+ * @returns {Boolean} Represents whether the actions were successful
585
+ */
586
+ onCompleteRequest = async (request) => {
587
+ return true;
588
+ };
589
+ }
590
+
591
+ module.exports = ArchibusStrategy;