@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/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@plusscommunities/pluss-maintenance-aws-forms",
|
|
3
|
+
"version": "2.1.7-beta.0",
|
|
4
|
+
"description": "Extension package to enable maintenance on Pluss Communities Platform",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"gc": "node ../../tools/gc ./",
|
|
7
|
+
"gs": "node ../../tools/gs ./ ../../activity/serverless.yml",
|
|
8
|
+
"betapatch": "npm version prepatch --preid=beta",
|
|
9
|
+
"patch": "npm version patch",
|
|
10
|
+
"deploy": "npm run gc && npm run gs && serverless deploy",
|
|
11
|
+
"betaupload": "rm -rf .serverless && npm i && npm publish --access public --tag beta",
|
|
12
|
+
"betaupload:p": "npm run betapatch && npm run betaupload",
|
|
13
|
+
"upload": "rm -rf .serverless && npm i && npm publish --access public",
|
|
14
|
+
"upload:p": "npm run patch && npm run upload",
|
|
15
|
+
"copy:add": "run(){ ext=${1:-default}; test -f values.config.$ext.js || cp values.config.default.js values.config.$ext.js; }; run",
|
|
16
|
+
"copy:get": "echo $npm_package_name",
|
|
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
|
+
"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 betapatch; 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;",
|
|
21
|
+
"test": "jest tests -i"
|
|
22
|
+
},
|
|
23
|
+
"author": "Thorbjorn Kappel Davis",
|
|
24
|
+
"license": "ISC",
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@aws/dynamodb-auto-marshaller": "^0.7.1",
|
|
27
|
+
"@plusscommunities/pluss-core-aws": "2.0.16-beta.0",
|
|
28
|
+
"amazon-cognito-identity-js": "^2.0.19",
|
|
29
|
+
"aws-sdk": "^2.1591.0",
|
|
30
|
+
"axios": "^1.6.8",
|
|
31
|
+
"base64-arraybuffer": "^1.0.2",
|
|
32
|
+
"expo-server-sdk": "^3.0.1",
|
|
33
|
+
"https": "^1.0.0",
|
|
34
|
+
"lodash": "^4.17.10",
|
|
35
|
+
"moment": "^2.30.1",
|
|
36
|
+
"node-fetch": "^2.2.0",
|
|
37
|
+
"node-jose": "^1.0.0",
|
|
38
|
+
"nodemailer": "^6.9.12",
|
|
39
|
+
"twilio": "^3.18.0",
|
|
40
|
+
"uuid": "^2.0.3"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/jest": "^26.0.23",
|
|
44
|
+
"eslint-config-rallycoding": "^3.2.0",
|
|
45
|
+
"jest": "^29.0.0",
|
|
46
|
+
"jest-aws-sdk-mock": "^1.0.2",
|
|
47
|
+
"serverless-domain-manager": "^3.3.1",
|
|
48
|
+
"serverless-prune-plugin": "^1.4.1"
|
|
49
|
+
},
|
|
50
|
+
"files": [
|
|
51
|
+
"db/*",
|
|
52
|
+
"integration/*",
|
|
53
|
+
"requests/*",
|
|
54
|
+
"ticketing/*",
|
|
55
|
+
"*.js",
|
|
56
|
+
"package*.json"
|
|
57
|
+
],
|
|
58
|
+
"jest": {
|
|
59
|
+
"rootDir": "./",
|
|
60
|
+
"moduleNameMapper": {
|
|
61
|
+
"^./testing/(.*)$": "<rootDir>/testing/$1"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
const moment = require("moment");
|
|
2
|
+
const editRef = require("@plusscommunities/pluss-core-aws/db/common/editRef");
|
|
3
|
+
const validateMasterAuth = require("@plusscommunities/pluss-core-aws/helper/auth/validateMasterAuth");
|
|
4
|
+
const getUserPreviewFromReq = require("@plusscommunities/pluss-core-aws/helper/getUserPreviewFromReq");
|
|
5
|
+
const getRef = require("@plusscommunities/pluss-core-aws/db/common/getRef");
|
|
6
|
+
const isValidAssignee = require("./helper/isValidAssignee");
|
|
7
|
+
const getUserPreview = require("@plusscommunities/pluss-core-aws/helper/getUserPreview");
|
|
8
|
+
const { log } = require("@plusscommunities/pluss-core-aws/helper");
|
|
9
|
+
const publishNotifications = require("@plusscommunities/pluss-core-aws/db/notifications/publishNotifications");
|
|
10
|
+
const { values } = require("../values.config");
|
|
11
|
+
|
|
12
|
+
module.exports = async (event, data) => {
|
|
13
|
+
const logId = log("assignRequest", "data", data);
|
|
14
|
+
// check required data
|
|
15
|
+
const requiredKeys = ["id", "userId"];
|
|
16
|
+
if (!data || requiredKeys.some((prop) => !data.hasOwnProperty(prop))) {
|
|
17
|
+
log("assignRequest", "InsufficientInput", 422, logId);
|
|
18
|
+
return { status: 422, data: { error: "Insufficient input" } };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const request = await getRef(values.tableNameMaintenance, "id", data.id);
|
|
22
|
+
log("assignRequest", "request", request, logId);
|
|
23
|
+
log("assignRequest", "site", request.site, logId);
|
|
24
|
+
|
|
25
|
+
// validate authorisation
|
|
26
|
+
const valid = await validateMasterAuth(
|
|
27
|
+
event,
|
|
28
|
+
values.permissionMaintenanceTracking,
|
|
29
|
+
request.site
|
|
30
|
+
);
|
|
31
|
+
log("assignRequest", "valid", valid, logId);
|
|
32
|
+
if (!valid) {
|
|
33
|
+
const validAssignee = await isValidAssignee(
|
|
34
|
+
event,
|
|
35
|
+
request.site,
|
|
36
|
+
request.AssigneeId
|
|
37
|
+
);
|
|
38
|
+
log("assignRequest", "validAssignee", validAssignee, logId);
|
|
39
|
+
if (!validAssignee) {
|
|
40
|
+
log("assignRequest", "NotAuthorised", 403, logId);
|
|
41
|
+
return { status: 403, data: { error: "Not authorised" } };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const user = await getUserPreviewFromReq(event);
|
|
46
|
+
log("assignRequest", "user", user, logId);
|
|
47
|
+
const assignedUser = await getUserPreview(data.userId);
|
|
48
|
+
log("assignRequest", "assignedUser", assignedUser, logId);
|
|
49
|
+
|
|
50
|
+
const changes = {
|
|
51
|
+
history: request.history || [],
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// Update history
|
|
55
|
+
changes.history.push({
|
|
56
|
+
timestamp: moment.utc().valueOf(),
|
|
57
|
+
EntryType: "assignment",
|
|
58
|
+
user,
|
|
59
|
+
assignedUser,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
changes.AssigneeId = data.userId;
|
|
63
|
+
changes.Assignee = assignedUser;
|
|
64
|
+
|
|
65
|
+
log("assignRequest", "changes", changes, logId);
|
|
66
|
+
|
|
67
|
+
const result = await editRef(
|
|
68
|
+
values.tableNameMaintenance,
|
|
69
|
+
"id",
|
|
70
|
+
data.id,
|
|
71
|
+
changes
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
log("assignRequest", "result", result, logId);
|
|
75
|
+
|
|
76
|
+
// send notification to assigned user
|
|
77
|
+
if (user.id !== assignedUser.id) {
|
|
78
|
+
await publishNotifications(
|
|
79
|
+
[assignedUser.id],
|
|
80
|
+
values.notificationMaintenanceJobAssigned,
|
|
81
|
+
result.site,
|
|
82
|
+
result.id,
|
|
83
|
+
result,
|
|
84
|
+
true
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// send notification to previous assignee
|
|
89
|
+
if (request.AssigneeId && result.AssigneeId !== request.AssigneeId) {
|
|
90
|
+
await publishNotifications(
|
|
91
|
+
[request.AssigneeId],
|
|
92
|
+
values.notificationMaintenanceJobUnassigned,
|
|
93
|
+
result.site,
|
|
94
|
+
result.id,
|
|
95
|
+
result,
|
|
96
|
+
true
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
status: 200,
|
|
102
|
+
data: {
|
|
103
|
+
job: result,
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const { log } = require("@plusscommunities/pluss-core-aws/helper");
|
|
2
|
+
const getUsersByPermission = require("@plusscommunities/pluss-core-aws/helper/users/getUsersByPermission");
|
|
3
|
+
const validateMasterAuth = require("@plusscommunities/pluss-core-aws/helper/auth/validateMasterAuth");
|
|
4
|
+
const { values } = require("../values.config");
|
|
5
|
+
|
|
6
|
+
// Define the new function to get assignees
|
|
7
|
+
module.exports = async (event) => {
|
|
8
|
+
const qParams = event.queryStringParameters || {};
|
|
9
|
+
const logId = log("getAssignees", "Input", qParams);
|
|
10
|
+
|
|
11
|
+
const isAdmin = await validateMasterAuth(
|
|
12
|
+
event,
|
|
13
|
+
values.permissionMaintenanceTracking,
|
|
14
|
+
qParams.site
|
|
15
|
+
);
|
|
16
|
+
const isAssignee = await validateMasterAuth(
|
|
17
|
+
event,
|
|
18
|
+
values.permissionMaintenanceAssignment,
|
|
19
|
+
qParams.site
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
const valid = isAdmin || isAssignee;
|
|
23
|
+
log("getRequests", "valid", valid, logId);
|
|
24
|
+
if (!valid) {
|
|
25
|
+
return { status: 403, data: { error: "Not authorised" } };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// get assignees
|
|
29
|
+
const assignees = await getUsersByPermission(qParams.site, [
|
|
30
|
+
values.permissionMaintenanceTracking,
|
|
31
|
+
values.permissionMaintenanceAssignment,
|
|
32
|
+
]);
|
|
33
|
+
|
|
34
|
+
log("getAssignees", "AssigneesLength", assignees.length, logId);
|
|
35
|
+
|
|
36
|
+
// compile results
|
|
37
|
+
const results = { Users: assignees };
|
|
38
|
+
log("getAssignees", "Done", true, logId);
|
|
39
|
+
return { status: 200, data: results };
|
|
40
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
const { log, getRowId } = require("@plusscommunities/pluss-core-aws/helper");
|
|
2
|
+
const getRef = require("@plusscommunities/pluss-core-aws/db/common/getRef");
|
|
3
|
+
const indexQuery = require("@plusscommunities/pluss-core-aws/db/common/indexQuery");
|
|
4
|
+
const validateMasterAuth = require("@plusscommunities/pluss-core-aws/helper/auth/validateMasterAuth");
|
|
5
|
+
const isValidAssignee = require("./helper/isValidAssignee");
|
|
6
|
+
const getSessionUserFromReqAuthKey = require("@plusscommunities/pluss-core-aws/helper/auth/getSessionUserFromReqAuthKey");
|
|
7
|
+
const { values } = require("../values.config");
|
|
8
|
+
|
|
9
|
+
module.exports = async (event, params) => {
|
|
10
|
+
const data = params || event.queryStringParameters;
|
|
11
|
+
const logId = log("getRequest", "Params", data);
|
|
12
|
+
if (!data.id && (!data.site || !data.jobId)) {
|
|
13
|
+
return {
|
|
14
|
+
status: 422,
|
|
15
|
+
data: {
|
|
16
|
+
error: "Insufficient input",
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
let result = null;
|
|
23
|
+
if (data.jobId) {
|
|
24
|
+
const query = {
|
|
25
|
+
IndexName: "MaintenanceSiteJobIdIndex",
|
|
26
|
+
KeyConditionExpression: "site = :site and jobId = :jobId",
|
|
27
|
+
ExpressionAttributeValues: {
|
|
28
|
+
":site": data.site,
|
|
29
|
+
":jobId": data.jobId,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
const { Items } = await indexQuery(values.tableNameMaintenance, query);
|
|
33
|
+
result = Items[0];
|
|
34
|
+
}
|
|
35
|
+
if (!result) {
|
|
36
|
+
result = await getRef(
|
|
37
|
+
values.tableNameMaintenance,
|
|
38
|
+
"id",
|
|
39
|
+
data.id || data.jobId
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const authorised = await validateMasterAuth(
|
|
44
|
+
event,
|
|
45
|
+
values.permissionMaintenanceTracking,
|
|
46
|
+
result.site
|
|
47
|
+
);
|
|
48
|
+
const assignAuthorised = await isValidAssignee(
|
|
49
|
+
event,
|
|
50
|
+
result.site,
|
|
51
|
+
result.AssigneeId
|
|
52
|
+
);
|
|
53
|
+
if (!authorised && !assignAuthorised) {
|
|
54
|
+
// Check if the job belongs to the user
|
|
55
|
+
const userId = await getSessionUserFromReqAuthKey(event);
|
|
56
|
+
if (userId !== result.userID) {
|
|
57
|
+
return {
|
|
58
|
+
status: 403,
|
|
59
|
+
data: {
|
|
60
|
+
error: "Not authorised",
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (data.includeComments) {
|
|
66
|
+
const commentsQuery = {
|
|
67
|
+
IndexName: "CommentsEntityIdIndex",
|
|
68
|
+
KeyConditionExpression: "EntityId = :groupId",
|
|
69
|
+
ExpressionAttributeValues: {
|
|
70
|
+
":groupId": getRowId(result.id, values.entityKey),
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
const commentsData = await indexQuery("comments", commentsQuery);
|
|
74
|
+
result.Comments = commentsData.Items;
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
status: 200,
|
|
78
|
+
data: result,
|
|
79
|
+
};
|
|
80
|
+
} catch (error) {
|
|
81
|
+
log("getRequest", "Error", error.toString(), logId);
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
status: 500,
|
|
85
|
+
data: {
|
|
86
|
+
error: "Internal error",
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
const { log } = require("@plusscommunities/pluss-core-aws/helper");
|
|
2
|
+
const getSessionUserFromReqAuthKey = require("@plusscommunities/pluss-core-aws/helper/auth/getSessionUserFromReqAuthKey");
|
|
3
|
+
const validateMasterAuth = require("@plusscommunities/pluss-core-aws/helper/auth/validateMasterAuth");
|
|
4
|
+
const validateSiteAccess = require("@plusscommunities/pluss-core-aws/helper/auth/validateSiteAccess");
|
|
5
|
+
const indexQuery = require("@plusscommunities/pluss-core-aws/db/common/indexQuery");
|
|
6
|
+
const { values } = require("../values.config");
|
|
7
|
+
|
|
8
|
+
module.exports = async (event) => {
|
|
9
|
+
const qParams = event.queryStringParameters;
|
|
10
|
+
const logId = log("getRequests", "Params", qParams);
|
|
11
|
+
|
|
12
|
+
// insufficient input
|
|
13
|
+
if (!qParams.site) {
|
|
14
|
+
return { status: 422, data: { error: "Insufficient input" } };
|
|
15
|
+
}
|
|
16
|
+
log("getRequests", "SufficientInput", true, logId);
|
|
17
|
+
|
|
18
|
+
// no access to site
|
|
19
|
+
const valid = await validateSiteAccess(event, qParams.site);
|
|
20
|
+
log("getRequests", "valid", valid, logId);
|
|
21
|
+
if (!valid) {
|
|
22
|
+
return { status: 403, data: { error: "Not authorised" } };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// check auth level to determine whether to fetch all requests or only matching requests
|
|
26
|
+
const authorised = await validateMasterAuth(
|
|
27
|
+
event,
|
|
28
|
+
values.permissionMaintenanceTracking,
|
|
29
|
+
qParams.site
|
|
30
|
+
);
|
|
31
|
+
let assigneeTracking = false;
|
|
32
|
+
if (!authorised) {
|
|
33
|
+
assigneeTracking = await validateMasterAuth(
|
|
34
|
+
event,
|
|
35
|
+
values.permissionMaintenanceAssignment,
|
|
36
|
+
qParams.site
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
log("getRequests", "authorised", authorised, logId);
|
|
41
|
+
const userId = authorised ? null : await getSessionUserFromReqAuthKey(event);
|
|
42
|
+
|
|
43
|
+
log("getRequests", "userId", userId, logId);
|
|
44
|
+
|
|
45
|
+
const query =
|
|
46
|
+
authorised || assigneeTracking
|
|
47
|
+
? {
|
|
48
|
+
IndexName: "MaintenanceSiteIndex",
|
|
49
|
+
KeyConditionExpression: "site = :site",
|
|
50
|
+
ExpressionAttributeValues: {
|
|
51
|
+
":site": qParams.site,
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
: {
|
|
55
|
+
IndexName: "MaintenanceSiteUserIdIndex",
|
|
56
|
+
KeyConditionExpression: "site = :site AND userID = :userId",
|
|
57
|
+
ExpressionAttributeValues: {
|
|
58
|
+
":site": qParams.site,
|
|
59
|
+
":userId": userId,
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
log("getRequests", "query", query, logId);
|
|
63
|
+
|
|
64
|
+
// check whether pagination is applied
|
|
65
|
+
if (qParams.lastKey) {
|
|
66
|
+
try {
|
|
67
|
+
query.ExclusiveStartKey = JSON.parse(qParams.lastKey);
|
|
68
|
+
} catch (e) {}
|
|
69
|
+
}
|
|
70
|
+
|
|
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 type
|
|
85
|
+
if (qParams.type) {
|
|
86
|
+
jobs = jobs.filter((j) => qParams.type.includes(j.type));
|
|
87
|
+
log("getRequests", "FilteredOnType", jobs.length, logId);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// filter to assigned jobs
|
|
91
|
+
if (!authorised && assigneeTracking) {
|
|
92
|
+
jobs = jobs.filter((j) => j.AssigneeId === userId || j.userID === userId);
|
|
93
|
+
log("getRequests", "FilteredOnAssignee", jobs.length, logId);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// compile results
|
|
97
|
+
const results = { Items: jobs, LastKey: result.LastEvaluatedKey };
|
|
98
|
+
log("getRequests", "Done", true, logId);
|
|
99
|
+
return { status: 200, data: results };
|
|
100
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if the request has permission.
|
|
3
|
+
*
|
|
4
|
+
* @param {Object} event - The api request object.
|
|
5
|
+
* @param {Object} job - The job object.
|
|
6
|
+
* @returns {Promise<boolean>} - A promise that resolves to a boolean indicating if the request has permission.
|
|
7
|
+
*/
|
|
8
|
+
const validateMasterAuth = require("@plusscommunities/pluss-core-aws/helper/auth/validateMasterAuth");
|
|
9
|
+
const isValidAssignee = require("./isValidAssignee");
|
|
10
|
+
const { values } = require("../../values.config");
|
|
11
|
+
|
|
12
|
+
module.exports = async (event, job) => {
|
|
13
|
+
const valid = await validateMasterAuth(
|
|
14
|
+
event,
|
|
15
|
+
values.permissionMaintenanceTracking,
|
|
16
|
+
job.site
|
|
17
|
+
);
|
|
18
|
+
if (valid) {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
if (!job.AssigneeId) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
return await isValidAssignee(event, job.site, job.AssigneeId);
|
|
25
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const getSessionUserFromReqAuthKey = require("@plusscommunities/pluss-core-aws/helper/auth/getSessionUserFromReqAuthKey");
|
|
2
|
+
const validateMasterAuth = require("@plusscommunities/pluss-core-aws/helper/auth/validateMasterAuth");
|
|
3
|
+
const { values } = require("../../values.config");
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Checks whether the logged in user is the assignee as has the assignment permission for that site
|
|
7
|
+
* @param {*} event A request including headers
|
|
8
|
+
* @param {String} site A site id
|
|
9
|
+
* @param {String} userId A user id to check for
|
|
10
|
+
* @returns {Boolean} true if valid
|
|
11
|
+
*/
|
|
12
|
+
module.exports = async (event, site, userId) => {
|
|
13
|
+
const valid = await validateMasterAuth(
|
|
14
|
+
event,
|
|
15
|
+
values.permissionMaintenanceAssignment,
|
|
16
|
+
site
|
|
17
|
+
);
|
|
18
|
+
if (!valid) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
const loggedInUser = await getSessionUserFromReqAuthKey(event);
|
|
22
|
+
return loggedInUser === userId;
|
|
23
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
const indexQuery = require("@plusscommunities/pluss-core-aws/db/common/indexQuery");
|
|
2
|
+
const editRef = require("@plusscommunities/pluss-core-aws/db/common/editRef");
|
|
3
|
+
const moment = require("moment");
|
|
4
|
+
const { getStrategy } = require("./integration");
|
|
5
|
+
const { log } = require("@plusscommunities/pluss-core-aws/helper");
|
|
6
|
+
|
|
7
|
+
const processSingle = async (strategy, item) => {
|
|
8
|
+
// use IDs to refresh request data
|
|
9
|
+
const logId = log("processSingle", "RefreshFromSource", item.ExternalId);
|
|
10
|
+
|
|
11
|
+
// refresh from external source
|
|
12
|
+
await strategy.refreshFromSource(
|
|
13
|
+
item.InternalId,
|
|
14
|
+
item.ExternalId,
|
|
15
|
+
item.TrackedData
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
// save updated timestamp
|
|
19
|
+
await editRef("externalentities", "RowId", item.RowId, {
|
|
20
|
+
LastUpdated: moment().valueOf(),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
log("processBatch", "Refreshed", item.ExternalId, logId);
|
|
24
|
+
return true;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const processBatch = async (strategy, startTime) => {
|
|
28
|
+
const logId = log("processBatch", "StartTime", moment().valueOf());
|
|
29
|
+
|
|
30
|
+
// use index query to fetch IDs of requests
|
|
31
|
+
const query = {
|
|
32
|
+
IndexName: "EntityTypeIndex",
|
|
33
|
+
KeyConditionExpression:
|
|
34
|
+
"EntityType = :entityType AND LastUpdated < :lastUpdate", // only fetch items that haven't been updated in this scan
|
|
35
|
+
ExpressionAttributeValues: {
|
|
36
|
+
":entityType": strategy.getEntityType(),
|
|
37
|
+
":lastUpdate": startTime - strategy.getRefreshInterval(),
|
|
38
|
+
},
|
|
39
|
+
Limit: 10,
|
|
40
|
+
ScanIndexForward: false,
|
|
41
|
+
};
|
|
42
|
+
const { Items } = await indexQuery("externalentities", query);
|
|
43
|
+
|
|
44
|
+
const promises = [];
|
|
45
|
+
|
|
46
|
+
Items.forEach((item) => {
|
|
47
|
+
log("processBatch", "ProcessSingle", JSON.stringify(item), logId);
|
|
48
|
+
promises.push(processSingle(strategy, JSON.parse(JSON.stringify(item))));
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
await Promise.all(promises);
|
|
52
|
+
log("processBatch", "EndOfBatch", Items.length, logId);
|
|
53
|
+
return Items.length;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
module.exports.scheduleJobImport = async (event, context, callback) => {
|
|
57
|
+
const logId = log("scheduleJobImport", "Start", true);
|
|
58
|
+
// get active integration
|
|
59
|
+
const integrationStrategy = await getStrategy("plussSpace");
|
|
60
|
+
if (!integrationStrategy.isValidIntegration()) {
|
|
61
|
+
log("scheduleJobImport", "Exit", "No valid integration", logId);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const startTime = moment().valueOf();
|
|
66
|
+
const timeout = 3 * 60 * 1000; // 3 minutes
|
|
67
|
+
let noneToProcess = false;
|
|
68
|
+
log("scheduleJobImport", "StartTime", startTime, logId);
|
|
69
|
+
|
|
70
|
+
while (!noneToProcess && moment().valueOf() < startTime + timeout) {
|
|
71
|
+
const logId = log("scheduleJobImport", "StartLoop", moment().valueOf());
|
|
72
|
+
const count = await processBatch(integrationStrategy, startTime);
|
|
73
|
+
log("scheduleJobImport", "Count", count, logId);
|
|
74
|
+
if (!count) {
|
|
75
|
+
log("scheduleJobImport", "noneToProcess", true, logId);
|
|
76
|
+
noneToProcess = true;
|
|
77
|
+
}
|
|
78
|
+
log("scheduleJobImport", "EndLoop", moment().valueOf(), logId);
|
|
79
|
+
}
|
|
80
|
+
log("scheduleJobImport", "End", moment().valueOf(), logId);
|
|
81
|
+
};
|
package/sendJobEmail.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
const _ = require("lodash");
|
|
2
|
+
const moment = require("moment");
|
|
3
|
+
const getJobEmail = require("./db/maintenance/getJobEmail");
|
|
4
|
+
const sendEmail = require("@plusscommunities/pluss-core-aws/helper/sendEmail");
|
|
5
|
+
const getRef = require("@plusscommunities/pluss-core-aws/db/common/getRef");
|
|
6
|
+
const { values } = require("./values.config");
|
|
7
|
+
|
|
8
|
+
module.exports = function (job, updated) {
|
|
9
|
+
const whenEvs = job.isHome
|
|
10
|
+
? "Yes - I would like to be present"
|
|
11
|
+
: "No - Work may be done while I am not home.";
|
|
12
|
+
|
|
13
|
+
getRef("sites", "Id", job.site || job.location)
|
|
14
|
+
.then((site) => {
|
|
15
|
+
const siteToUse = site ? site.siteName : job.site || job.location;
|
|
16
|
+
const { customFields } = job;
|
|
17
|
+
const hasCustomFields = customFields && customFields.length > 0;
|
|
18
|
+
|
|
19
|
+
const renderCommon = () => `
|
|
20
|
+
<p>
|
|
21
|
+
<b>${values.textJobEmailTitle} ${job.id != null ? `#${job.id}` : ""}${
|
|
22
|
+
updated ? "-DETAILS EDITED- " : " "
|
|
23
|
+
}(${job.type}):</b> ${job.room}
|
|
24
|
+
</p>
|
|
25
|
+
<div>
|
|
26
|
+
<b>Title: </b>${job.title}
|
|
27
|
+
</div>
|
|
28
|
+
<p>Client Details:</p>
|
|
29
|
+
<div>
|
|
30
|
+
<b>Name: </b>${job.userName}
|
|
31
|
+
</div>
|
|
32
|
+
<div>
|
|
33
|
+
<b>Phone: </b>${job.phone || ""}
|
|
34
|
+
</div>
|
|
35
|
+
<div>
|
|
36
|
+
<b>Location: </b>${siteToUse} <br /><br />
|
|
37
|
+
</div>
|
|
38
|
+
<div>
|
|
39
|
+
<b>Address: </b>${job.room} <br /><br />
|
|
40
|
+
</div>
|
|
41
|
+
`;
|
|
42
|
+
const renderImages = () => {
|
|
43
|
+
let inner = "";
|
|
44
|
+
if (!_.isNil(job.images)) {
|
|
45
|
+
inner = job.images.map(
|
|
46
|
+
(image) => `<img style="max-height: 400px" src="${image}" />`
|
|
47
|
+
);
|
|
48
|
+
} else if (!_.isNil(job.image)) {
|
|
49
|
+
inner = `<img style="max-height: 400px" src="${job.image}" />`;
|
|
50
|
+
}
|
|
51
|
+
return _.isEmpty(inner) ? "" : `<div>${inner}</div>`;
|
|
52
|
+
};
|
|
53
|
+
const renderNonCustom = () => `
|
|
54
|
+
<div>
|
|
55
|
+
<b>Person Present During Service: </b>${whenEvs}
|
|
56
|
+
<div>
|
|
57
|
+
${job.isHome ? job.homeText : ""}
|
|
58
|
+
<br /><br />
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
<div>
|
|
62
|
+
<b>${job.type} Description: </b>
|
|
63
|
+
</div>
|
|
64
|
+
<div>
|
|
65
|
+
${job.description || ""}
|
|
66
|
+
</div>
|
|
67
|
+
${renderImages()}
|
|
68
|
+
`;
|
|
69
|
+
const renderCustom = () => {
|
|
70
|
+
const renderAnswer = (field) => {
|
|
71
|
+
switch (field.type) {
|
|
72
|
+
case "date":
|
|
73
|
+
return field.answer
|
|
74
|
+
? moment(field.answer, "YYYY-MM-DD").format("DD MMM YYYY")
|
|
75
|
+
: "";
|
|
76
|
+
case "time":
|
|
77
|
+
return field.answer
|
|
78
|
+
? moment(field.answer, "HH:mm").format("h:mm a")
|
|
79
|
+
: "";
|
|
80
|
+
case "yn":
|
|
81
|
+
return field.answer ? "Yes" : "No";
|
|
82
|
+
case "checkbox":
|
|
83
|
+
return field.answer && Array.isArray(field.answer)
|
|
84
|
+
? field.answer.join(", ")
|
|
85
|
+
: "";
|
|
86
|
+
case "image":
|
|
87
|
+
return field.answer && Array.isArray(field.answer)
|
|
88
|
+
? `<br>${field.answer.map(
|
|
89
|
+
(image) =>
|
|
90
|
+
`<img style="max-height: 400px" src="${image}" />`
|
|
91
|
+
)}`
|
|
92
|
+
: "";
|
|
93
|
+
default:
|
|
94
|
+
return field.answer;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
return customFields
|
|
99
|
+
.filter((f) => !["staticTitle", "staticText"].includes(f.type))
|
|
100
|
+
.map((field) => {
|
|
101
|
+
return `
|
|
102
|
+
<div>
|
|
103
|
+
<b>${field.label}: </b>${renderAnswer(field)}
|
|
104
|
+
</div>
|
|
105
|
+
`;
|
|
106
|
+
})
|
|
107
|
+
.join("\n");
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const htmlString = `
|
|
111
|
+
<div>
|
|
112
|
+
${renderCommon()}
|
|
113
|
+
${hasCustomFields ? renderCustom() : renderNonCustom()}
|
|
114
|
+
</div>
|
|
115
|
+
`;
|
|
116
|
+
|
|
117
|
+
getJobEmail(job.site || job.location, job.type)
|
|
118
|
+
.then((obj) => {
|
|
119
|
+
const email = obj.email;
|
|
120
|
+
if (_.isEmpty(email)) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
sendEmail(
|
|
125
|
+
email,
|
|
126
|
+
`${values.textJobEmailTitle} #${job.id}${
|
|
127
|
+
updated ? " -DETAILS EDITED" : ""
|
|
128
|
+
}- (${job.type}) - ${job.room}`,
|
|
129
|
+
htmlString
|
|
130
|
+
)
|
|
131
|
+
.then((result) => {
|
|
132
|
+
console.log(
|
|
133
|
+
`SUCCESS - Maintenance email --> ${job.type}, ${job.userName}`
|
|
134
|
+
);
|
|
135
|
+
})
|
|
136
|
+
.catch((error) => {
|
|
137
|
+
console.log(
|
|
138
|
+
`FAIL - Maintenance email --> ${job.type}, ${job.userName}`
|
|
139
|
+
);
|
|
140
|
+
});
|
|
141
|
+
})
|
|
142
|
+
.catch(() => {
|
|
143
|
+
console.log(
|
|
144
|
+
`FAIL - Maintenance email - fetch email address --> ${job.type}, ${job.userName}`
|
|
145
|
+
);
|
|
146
|
+
});
|
|
147
|
+
})
|
|
148
|
+
.catch(() => {
|
|
149
|
+
console.log(
|
|
150
|
+
`FAIL - Maintenance email - fetch site --> ${job.site || job.location}`
|
|
151
|
+
);
|
|
152
|
+
});
|
|
153
|
+
};
|