@plusscommunities/pluss-core-aws 2.0.26-auth.0 → 2.0.26
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/aws/getDefaultEmailAddress.js +21 -21
- package/aws/getEmailService.js +16 -16
- package/aws/getEmailServiceInfo.js +26 -26
- package/aws/sendEmail.js +31 -31
- package/config.js +1 -1
- package/db/activity/publishActivity.js +22 -22
- package/db/analytics/checkActivityExists.js +15 -15
- package/db/analytics/logAnalyticsActivity.js +104 -40
- package/db/analytics/scheduleOldAggregation.js +14 -14
- package/db/auth/getSiteSetting.js +12 -12
- package/db/auth/getSiteUserTypes.js +16 -16
- package/db/auth/getUserAuth.js +13 -13
- package/db/automatedactions/getActionBySiteTrigger.js +9 -9
- package/db/common/deleteRef.js +21 -21
- package/db/common/editRef.js +36 -36
- package/db/common/getRef.js +23 -23
- package/db/common/getTableCount.js +18 -18
- package/db/common/indexQuery.js +17 -17
- package/db/common/indexQueryRecursive.js +20 -20
- package/db/common/scanRef.js +18 -18
- package/db/common/scanRefRecursive.js +20 -20
- package/db/common/updateAttribute.js +27 -27
- package/db/common/updateRef.js +20 -20
- package/db/linkedUsers/getLinkedBy.js +21 -21
- package/db/linkedUsers/getLinkedTo.js +21 -21
- package/db/notifications/deleteNotificationsByEntity.js +21 -21
- package/db/notifications/getNotificationSetting.js +14 -14
- package/db/notifications/publishNotifications.js +39 -39
- package/db/postgres/getKnex.js +214 -0
- package/db/postgres/safeError.js +40 -0
- package/db/property/Property.js +128 -0
- package/db/property/PropertyRepository.js +86 -0
- package/db/scheduledActions/deleteActionQueue.js +1 -1
- package/db/scheduledActions/getActionQueueByEntityId.js +10 -10
- package/db/scheduledActions/getActionQueueByEntityKey.js +9 -9
- package/db/scheduledActions/getActionQueueById.js +9 -9
- package/db/scheduledActions/getActionQueueByTriggerAt.js +14 -14
- package/db/scheduledActions/updateActionQueue.js +29 -29
- package/db/strings/getString.js +20 -20
- package/db/strings/logUpdate.js +18 -18
- package/db/templates/getTemplateById.js +1 -1
- package/db/templates/getTemplatesList.js +10 -10
- package/db/templates/updateTemplate.js +9 -9
- package/db/users/getRole.js +1 -1
- package/db/users/getUser.js +9 -9
- package/db/users/getUserByEmail.js +17 -17
- package/helper/audience/filterByAudienceType.js +27 -27
- package/helper/audience/filterOnAudienceType.js +26 -26
- package/helper/audience/getAudience.js +187 -187
- package/helper/audience/getMatchingAudienceTypes.js +21 -21
- package/helper/audience/getMatchingAudienceTypesFromPreview.js +60 -60
- package/helper/audience/getMatchingTags.js +15 -15
- package/helper/audience/isValidAudience.js +20 -20
- package/helper/auth/checkTokenBlacklist.js +17 -17
- package/helper/auth/getApiKeyFromReq.js +2 -2
- package/helper/auth/getSessionUser.js +70 -85
- package/helper/auth/getSessionUserFromReq.js +2 -2
- package/helper/auth/getSessionUserFromReqAuthKey.js +11 -11
- package/helper/auth/validateApiKey.js +32 -32
- package/helper/auth/validateMasterAuth.js +174 -174
- package/helper/auth/validateSiteAccess.js +12 -12
- package/helper/auth/validateSiteSetting.js +7 -7
- package/helper/auth/validateUserLoggedIn.js +19 -19
- package/helper/createGuid.js +5 -5
- package/helper/generateJsonResponse.js +27 -27
- package/helper/getUserPreview.js +57 -57
- package/helper/getUserPreviewFromHeader.js +17 -17
- package/helper/getUserPreviewFromReq.js +17 -17
- package/helper/hqPublishing.js +465 -0
- package/helper/index.js +28 -28
- package/helper/notifySiteConfigs.js +67 -52
- package/helper/opengraph/getOpenGraph.js +12 -12
- package/helper/rates/checkRateLimit.js +38 -38
- package/helper/requestToSource.js +10 -10
- package/helper/sendEmail.js +120 -120
- package/helper/templates/replacePlaceHolders.js +29 -29
- package/helper/time/getLocalTimestamp.js +18 -18
- package/helper/time/getSiteTimezone.js +11 -11
- package/helper/triggerAutomatedAction.js +25 -25
- package/helper/userToUserPreview.js +23 -23
- package/helper/users/getUserTypesByPermission.js +24 -24
- package/helper/users/getUsersByPermission.js +20 -20
- package/notification/prepNotification.js +144 -144
- package/notification/sendNotifications.js +166 -166
- package/package.json +37 -40
- package/templates/supportTicketEmails.js +8 -8
- package/helper/auth/context/AuthenticationContext.js +0 -50
- package/helper/auth/context/AuthenticationStrategy.js +0 -20
- package/helper/auth/context/auth0/Strategy.js +0 -12
- package/helper/auth/context/auth0/functions/decodeAccessToken.js +0 -102
- package/helper/auth/context/auth0/functions/getSessionUser.js +0 -21
- package/helper/auth/context/boltonclarke/Strategy.js +0 -10
- package/helper/auth/context/cognito/Strategy.js +0 -12
- package/helper/auth/context/cognito/functions/getSessionUser.js +0 -76
package/helper/index.js
CHANGED
|
@@ -3,28 +3,28 @@ const uuid = require("uuid");
|
|
|
3
3
|
const { encode, decode } = require("html-entities");
|
|
4
4
|
|
|
5
5
|
exports.thisOrDefault = (val, def) => {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
if (val) {
|
|
7
|
+
return val;
|
|
8
|
+
}
|
|
9
|
+
return def;
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
exports.getRowId = (site, id) => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
if (_.isEmpty(site)) {
|
|
14
|
+
return id;
|
|
15
|
+
}
|
|
16
|
+
return `${site}_${id}`;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
exports.getMultiRowId = (cols) => {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
let result = "";
|
|
21
|
+
cols.forEach((col) => {
|
|
22
|
+
if (!_.isEmpty(result)) {
|
|
23
|
+
result += "_";
|
|
24
|
+
}
|
|
25
|
+
result += col;
|
|
26
|
+
});
|
|
27
|
+
return result;
|
|
28
28
|
};
|
|
29
29
|
|
|
30
30
|
// exports.getExtension = (filename) => {
|
|
@@ -36,7 +36,7 @@ exports.getMultiRowId = (cols) => {
|
|
|
36
36
|
// };
|
|
37
37
|
|
|
38
38
|
exports.getBody = (event) => {
|
|
39
|
-
|
|
39
|
+
return typeof event.body === "string" ? JSON.parse(event.body) : event.body;
|
|
40
40
|
};
|
|
41
41
|
|
|
42
42
|
// exports.generatePassword = () => {
|
|
@@ -47,20 +47,20 @@ exports.getBody = (event) => {
|
|
|
47
47
|
// };
|
|
48
48
|
|
|
49
49
|
exports.log = (action, logKey, data, logId) => {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
50
|
+
if (!logId) {
|
|
51
|
+
logId = this.generateLogId();
|
|
52
|
+
}
|
|
53
|
+
console.log(
|
|
54
|
+
`[${action}]:[${logId}]:[${logKey}]`,
|
|
55
|
+
typeof data === "string" || typeof data === "number"
|
|
56
|
+
? data
|
|
57
|
+
: JSON.stringify(data),
|
|
58
|
+
);
|
|
59
|
+
return logId;
|
|
60
60
|
};
|
|
61
61
|
|
|
62
62
|
exports.generateLogId = () => {
|
|
63
|
-
|
|
63
|
+
return uuid.v4().substring(30);
|
|
64
64
|
};
|
|
65
65
|
|
|
66
66
|
exports.encodeHtml = (html) => encode(html);
|
|
@@ -33,21 +33,21 @@ const TABLE_NAME = "siteconfigs";
|
|
|
33
33
|
* @returns {Promise<Array>} Array of template IDs (empty if none)
|
|
34
34
|
*/
|
|
35
35
|
const getTemplatesForSourceSite = async (siteId) => {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
36
|
+
try {
|
|
37
|
+
const result = await indexQuery(TABLE_NAME, {
|
|
38
|
+
IndexName: "SourceSiteIdIndex",
|
|
39
|
+
KeyConditionExpression: "SourceSiteId = :sourceSiteId",
|
|
40
|
+
ExpressionAttributeValues: {
|
|
41
|
+
":sourceSiteId": siteId,
|
|
42
|
+
},
|
|
43
|
+
ProjectionExpression: "Id", // Only need IDs for pre-filter
|
|
44
|
+
});
|
|
45
|
+
return (result.Items || []).map((item) => item.Id);
|
|
46
|
+
} catch (err) {
|
|
47
|
+
// Table or index might not exist in all deployments
|
|
48
|
+
log("notifySiteConfigs", "QueryError", { siteId, error: err.message });
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
51
|
};
|
|
52
52
|
|
|
53
53
|
/**
|
|
@@ -57,35 +57,45 @@ const getTemplatesForSourceSite = async (siteId) => {
|
|
|
57
57
|
* @param {string} logId - Log ID for tracing
|
|
58
58
|
*/
|
|
59
59
|
const invokeSiteConfigsLambda = async (siteId, templateIds, logId) => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
60
|
+
// Build function name from environment
|
|
61
|
+
// Format: {client}-siteConfigs-{stage}-operationalDataChanged
|
|
62
|
+
const client = process.env.client || "dev";
|
|
63
|
+
const stage = process.env.stage || "dev";
|
|
64
|
+
const functionName = `${client}-siteConfigs-${stage}-operationalDataChanged`;
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
66
|
+
const payload = {
|
|
67
|
+
siteId,
|
|
68
|
+
templateIds,
|
|
69
|
+
logId,
|
|
70
|
+
source: "notifySiteConfigs",
|
|
71
|
+
};
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
log(
|
|
74
|
+
"notifySiteConfigs",
|
|
75
|
+
"InvokingLambda",
|
|
76
|
+
{ functionName, siteId, templateCount: templateIds.length },
|
|
77
|
+
logId,
|
|
78
|
+
);
|
|
74
79
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
try {
|
|
81
|
+
await lambda
|
|
82
|
+
.invoke({
|
|
83
|
+
FunctionName: functionName,
|
|
84
|
+
InvocationType: "Event", // Async invocation
|
|
85
|
+
Payload: JSON.stringify(payload),
|
|
86
|
+
})
|
|
87
|
+
.promise();
|
|
83
88
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
+
log("notifySiteConfigs", "LambdaInvoked", { functionName, siteId }, logId);
|
|
90
|
+
} catch (err) {
|
|
91
|
+
log(
|
|
92
|
+
"notifySiteConfigs",
|
|
93
|
+
"LambdaError",
|
|
94
|
+
{ functionName, siteId, error: err.message },
|
|
95
|
+
logId,
|
|
96
|
+
);
|
|
97
|
+
// Don't throw - this is a non-critical operation
|
|
98
|
+
}
|
|
89
99
|
};
|
|
90
100
|
|
|
91
101
|
/**
|
|
@@ -96,22 +106,27 @@ const invokeSiteConfigsLambda = async (siteId, templateIds, logId) => {
|
|
|
96
106
|
* @param {string} logId - Optional log ID for tracing
|
|
97
107
|
*/
|
|
98
108
|
const notifySiteConfigs = async (siteId, logId) => {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
109
|
+
if (!siteId) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
102
112
|
|
|
103
|
-
|
|
104
|
-
|
|
113
|
+
// Pre-filter: Check if this site is a source for any templates
|
|
114
|
+
const templateIds = await getTemplatesForSourceSite(siteId);
|
|
105
115
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
116
|
+
if (templateIds.length === 0) {
|
|
117
|
+
// No Lambda invocation needed
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
110
120
|
|
|
111
|
-
|
|
121
|
+
log(
|
|
122
|
+
"notifySiteConfigs",
|
|
123
|
+
"TemplatesFound",
|
|
124
|
+
{ siteId, count: templateIds.length },
|
|
125
|
+
logId,
|
|
126
|
+
);
|
|
112
127
|
|
|
113
|
-
|
|
114
|
-
|
|
128
|
+
// Invoke siteConfigs Lambda to handle republishing
|
|
129
|
+
await invokeSiteConfigsLambda(siteId, templateIds, logId);
|
|
115
130
|
};
|
|
116
131
|
|
|
117
132
|
module.exports = notifySiteConfigs;
|
|
@@ -2,17 +2,17 @@ const axios = require("axios");
|
|
|
2
2
|
const { getConfig } = require("../../config");
|
|
3
3
|
|
|
4
4
|
module.exports = async (url) => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
return new Promise(async (resolve, reject) => {
|
|
6
|
+
const request = {
|
|
7
|
+
method: "GET",
|
|
8
|
+
url: `https://opengraph.io/api/1.1/site/${encodeURIComponent(url)}?app_id=${getConfig().thirdPartyAPIKeys.openGraph}`,
|
|
9
|
+
};
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
11
|
+
try {
|
|
12
|
+
const response = await axios(request);
|
|
13
|
+
return resolve(response.data);
|
|
14
|
+
} catch (e) {
|
|
15
|
+
return reject(e);
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
18
|
};
|
|
@@ -12,45 +12,45 @@ const updateRef = require("../../db/common/updateRef");
|
|
|
12
12
|
* @returns {Boolean} true if this call is fine. false if the call should be restricted due to rate limits.
|
|
13
13
|
*/
|
|
14
14
|
module.exports = async (rateLimitId, timeframe, limit, noSave) => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
const logId = log("checkRateLimit", "Input", {
|
|
16
|
+
rateLimitId,
|
|
17
|
+
timeframe,
|
|
18
|
+
limit,
|
|
19
|
+
});
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
// get rate limit item
|
|
22
|
+
const item = await getRef("ratelimit", "Id", rateLimitId);
|
|
23
|
+
const now = moment().valueOf();
|
|
24
|
+
const minTime = now - timeframe;
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
const history = item && item.History ? item.History : [];
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
28
|
+
if (history) {
|
|
29
|
+
// check history for entries to determine whether limit is surpassed
|
|
30
|
+
const entriesInTimeLimit = history.filter((e) => e > minTime);
|
|
31
|
+
log(
|
|
32
|
+
"checkRateLimit",
|
|
33
|
+
"entriesInTimeLimit",
|
|
34
|
+
entriesInTimeLimit.length,
|
|
35
|
+
logId,
|
|
36
|
+
);
|
|
37
|
+
if (entriesInTimeLimit.length >= limit) {
|
|
38
|
+
// Limit surpassed
|
|
39
|
+
log("checkRateLimit", "Return", false, logId);
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
};
|
|
44
|
+
// check whether to save the current entry - used for when checking multiple timeframes such as X calls in a minute and X calls in a day
|
|
45
|
+
if (!noSave) {
|
|
46
|
+
history.push(now);
|
|
47
|
+
updateRef("ratelimit", {
|
|
48
|
+
Id: rateLimitId,
|
|
49
|
+
LastSent: now,
|
|
50
|
+
History: history,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
// Limit is fine
|
|
54
|
+
log("checkRateLimit", "Return", true, logId);
|
|
55
|
+
return true;
|
|
56
|
+
};
|
|
@@ -3,14 +3,14 @@ const _ = require("lodash");
|
|
|
3
3
|
|
|
4
4
|
// sends a request to the Pluss Source API
|
|
5
5
|
module.exports = (method, service, endpoint, query, data) => {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
6
|
+
return axios({
|
|
7
|
+
method,
|
|
8
|
+
url: `https://pluss60.pluss60-api.com/${service}-demo/${endpoint}${
|
|
9
|
+
!_.isEmpty(query) ? query : ""
|
|
10
|
+
}`,
|
|
11
|
+
data,
|
|
12
|
+
headers: {
|
|
13
|
+
Authorization: "SmartCommunities",
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
16
|
};
|
package/helper/sendEmail.js
CHANGED
|
@@ -8,98 +8,98 @@ const getRef = require("../db/common/getRef");
|
|
|
8
8
|
const updateRef = require("../db/common/updateRef");
|
|
9
9
|
|
|
10
10
|
const sendFallback = (mailOptions, emailConfig, accessConfig) => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
const logId = log("sendFallback", "Email", mailOptions);
|
|
13
|
+
if (emailConfig.isFallback) {
|
|
14
|
+
log(
|
|
15
|
+
"sendFallback",
|
|
16
|
+
"isFallback",
|
|
17
|
+
"Not allowed to use this account as it is the fallback itself",
|
|
18
|
+
logId,
|
|
19
|
+
);
|
|
20
|
+
return reject(
|
|
21
|
+
new Error(
|
|
22
|
+
"Not allowed to use this account as it is the fallback itself",
|
|
23
|
+
),
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
27
|
+
// Calling organisation account as the fallback
|
|
28
|
+
log("sendFallback", "Fallback", emailConfig.fallbackUrl, logId);
|
|
29
|
+
axios({
|
|
30
|
+
method: "POST",
|
|
31
|
+
url: emailConfig.fallbackUrl,
|
|
32
|
+
headers: {
|
|
33
|
+
Authorization: accessConfig.authSecret,
|
|
34
|
+
},
|
|
35
|
+
data: {
|
|
36
|
+
to: mailOptions.to,
|
|
37
|
+
subject: mailOptions.subject,
|
|
38
|
+
body: mailOptions.html,
|
|
39
|
+
from: mailOptions.from,
|
|
40
|
+
},
|
|
41
|
+
})
|
|
42
|
+
.then((response) => {
|
|
43
|
+
log("sendFallback", "response", response.data, logId);
|
|
44
|
+
resolve(response.data);
|
|
45
|
+
})
|
|
46
|
+
.catch((error) => {
|
|
47
|
+
log("sendFallback", "error", error, logId);
|
|
48
|
+
reject(error);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
51
|
};
|
|
52
52
|
|
|
53
53
|
module.exports = async (
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
54
|
+
toEmail,
|
|
55
|
+
subject,
|
|
56
|
+
content,
|
|
57
|
+
useTemplate,
|
|
58
|
+
{
|
|
59
|
+
fromEmail = null,
|
|
60
|
+
excludeClientBranding = false,
|
|
61
|
+
brandingImage = null,
|
|
62
|
+
bcc = null,
|
|
63
|
+
rateLimitId = null,
|
|
64
|
+
} = {},
|
|
65
65
|
) => {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
const { communityConfig, serverlessConfig, emailConfig, accessConfig } =
|
|
67
|
+
getConfig();
|
|
68
|
+
const now = moment.utc();
|
|
69
|
+
let rateLimitIdToUse;
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
const logId = log("sendEmail", "Email", {
|
|
72
|
+
toEmail,
|
|
73
|
+
subject,
|
|
74
|
+
});
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
76
|
+
if (rateLimitId) {
|
|
77
|
+
try {
|
|
78
|
+
rateLimitIdToUse = `email_${rateLimitId}`;
|
|
79
|
+
const item = await getRef("ratelimit", "Id", rateLimitIdToUse);
|
|
80
|
+
const dayAgo = moment(now).add(-1, "d");
|
|
81
|
+
if (item && item.LastSent && item.LastSent > dayAgo.valueOf()) {
|
|
82
|
+
log(
|
|
83
|
+
"sendEmail",
|
|
84
|
+
"RateLimit",
|
|
85
|
+
`Rate limit reached for ${rateLimitIdToUse}`,
|
|
86
|
+
logId,
|
|
87
|
+
);
|
|
88
|
+
return { RateLimited: true };
|
|
89
|
+
}
|
|
90
|
+
} catch (e) {
|
|
91
|
+
// continue
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
if (useTemplate) {
|
|
96
|
+
content = `<div style="padding: 24px; padding-top: 0px; background-color: #f2f4f8;margin: 0px;">
|
|
97
97
|
<div style="background-color: #fff; padding: 48px; padding-top: 65px; padding-bottom: 24px;">
|
|
98
98
|
${content}
|
|
99
99
|
${
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
excludeClientBranding
|
|
101
|
+
? ""
|
|
102
|
+
: `
|
|
103
103
|
<div style='margin-top: 32px; border-top: 2px solid #e0e0e0;'></div>
|
|
104
104
|
<div style='padding-top: 24px; display: block;'>
|
|
105
105
|
<div style='clear: both; height: 30px;'>
|
|
@@ -107,7 +107,7 @@ module.exports = async (
|
|
|
107
107
|
</div>
|
|
108
108
|
</div>
|
|
109
109
|
`
|
|
110
|
-
|
|
110
|
+
}
|
|
111
111
|
</div>
|
|
112
112
|
<div style='margin-top: 30px;'>
|
|
113
113
|
<div style='margin: 0 auto; width: fit-content;'>
|
|
@@ -118,46 +118,46 @@ module.exports = async (
|
|
|
118
118
|
</div>
|
|
119
119
|
</div>
|
|
120
120
|
</div>`;
|
|
121
|
-
|
|
121
|
+
}
|
|
122
122
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
123
|
+
const sesInfo = await getEmailServiceInfo(
|
|
124
|
+
serverlessConfig.key,
|
|
125
|
+
serverlessConfig.secret,
|
|
126
|
+
);
|
|
127
127
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
128
|
+
const mailOptions = {
|
|
129
|
+
from: fromEmail || `${communityConfig.name} <${sesInfo.sender}>`,
|
|
130
|
+
to: toEmail,
|
|
131
|
+
bcc,
|
|
132
|
+
subject,
|
|
133
|
+
text: content,
|
|
134
|
+
html: content,
|
|
135
|
+
};
|
|
136
136
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
137
|
+
if (sesInfo.enabled) {
|
|
138
|
+
try {
|
|
139
|
+
log("sendEmail", "SES", { toEmail, subject }, logId);
|
|
140
|
+
const result = await sendEmail(
|
|
141
|
+
mailOptions.from,
|
|
142
|
+
mailOptions.to,
|
|
143
|
+
mailOptions.subject,
|
|
144
|
+
mailOptions.html,
|
|
145
|
+
serverlessConfig,
|
|
146
|
+
mailOptions.bcc,
|
|
147
|
+
);
|
|
148
|
+
log("sendEmail", "Success", { toEmail, subject }, logId);
|
|
149
|
+
} catch (error) {
|
|
150
|
+
log("sendEmail", "Error:SES", { toEmail, subject, error }, logId);
|
|
151
|
+
await sendFallback(mailOptions, emailConfig, accessConfig);
|
|
152
|
+
}
|
|
153
|
+
} else {
|
|
154
|
+
await sendFallback(mailOptions, emailConfig, accessConfig);
|
|
155
|
+
}
|
|
156
156
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
157
|
+
if (rateLimitIdToUse) {
|
|
158
|
+
await updateRef("ratelimit", {
|
|
159
|
+
Id: rateLimitIdToUse,
|
|
160
|
+
LastSent: now.valueOf(),
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
163
|
};
|