@plusscommunities/pluss-core-aws 2.0.26-auth.0 → 2.0.26-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.
Files changed (94) hide show
  1. package/aws/getDefaultEmailAddress.js +21 -21
  2. package/aws/getEmailService.js +16 -16
  3. package/aws/getEmailServiceInfo.js +26 -26
  4. package/aws/sendEmail.js +31 -31
  5. package/config.js +1 -1
  6. package/db/activity/publishActivity.js +22 -22
  7. package/db/analytics/checkActivityExists.js +15 -15
  8. package/db/analytics/logAnalyticsActivity.js +69 -37
  9. package/db/analytics/scheduleOldAggregation.js +14 -14
  10. package/db/auth/getSiteSetting.js +12 -12
  11. package/db/auth/getSiteUserTypes.js +16 -16
  12. package/db/auth/getUserAuth.js +13 -13
  13. package/db/automatedactions/getActionBySiteTrigger.js +9 -9
  14. package/db/common/deleteRef.js +21 -21
  15. package/db/common/editRef.js +36 -36
  16. package/db/common/getRef.js +23 -23
  17. package/db/common/getTableCount.js +18 -18
  18. package/db/common/indexQuery.js +17 -17
  19. package/db/common/indexQueryRecursive.js +20 -20
  20. package/db/common/scanRef.js +18 -18
  21. package/db/common/scanRefRecursive.js +20 -20
  22. package/db/common/updateAttribute.js +27 -27
  23. package/db/common/updateRef.js +20 -20
  24. package/db/linkedUsers/getLinkedBy.js +21 -21
  25. package/db/linkedUsers/getLinkedTo.js +21 -21
  26. package/db/notifications/deleteNotificationsByEntity.js +21 -21
  27. package/db/notifications/getNotificationSetting.js +14 -14
  28. package/db/notifications/publishNotifications.js +39 -39
  29. package/db/postgres/getKnex.js +214 -0
  30. package/db/postgres/safeError.js +40 -0
  31. package/db/property/Property.js +128 -0
  32. package/db/property/PropertyRepository.js +86 -0
  33. package/db/scheduledActions/deleteActionQueue.js +1 -1
  34. package/db/scheduledActions/getActionQueueByEntityId.js +10 -10
  35. package/db/scheduledActions/getActionQueueByEntityKey.js +9 -9
  36. package/db/scheduledActions/getActionQueueById.js +9 -9
  37. package/db/scheduledActions/getActionQueueByTriggerAt.js +14 -14
  38. package/db/scheduledActions/updateActionQueue.js +29 -29
  39. package/db/strings/getString.js +20 -20
  40. package/db/strings/logUpdate.js +18 -18
  41. package/db/templates/getTemplateById.js +1 -1
  42. package/db/templates/getTemplatesList.js +10 -10
  43. package/db/templates/updateTemplate.js +9 -9
  44. package/db/users/getRole.js +1 -1
  45. package/db/users/getUser.js +9 -9
  46. package/db/users/getUserByEmail.js +17 -17
  47. package/helper/audience/filterByAudienceType.js +27 -27
  48. package/helper/audience/filterOnAudienceType.js +26 -26
  49. package/helper/audience/getAudience.js +187 -187
  50. package/helper/audience/getMatchingAudienceTypes.js +21 -21
  51. package/helper/audience/getMatchingAudienceTypesFromPreview.js +60 -60
  52. package/helper/audience/getMatchingTags.js +15 -15
  53. package/helper/audience/isValidAudience.js +20 -20
  54. package/helper/auth/checkTokenBlacklist.js +17 -17
  55. package/helper/auth/getApiKeyFromReq.js +2 -2
  56. package/helper/auth/getSessionUser.js +70 -85
  57. package/helper/auth/getSessionUserFromReq.js +2 -2
  58. package/helper/auth/getSessionUserFromReqAuthKey.js +11 -11
  59. package/helper/auth/validateApiKey.js +32 -32
  60. package/helper/auth/validateMasterAuth.js +174 -174
  61. package/helper/auth/validateSiteAccess.js +12 -12
  62. package/helper/auth/validateSiteSetting.js +7 -7
  63. package/helper/auth/validateUserLoggedIn.js +19 -19
  64. package/helper/createGuid.js +5 -5
  65. package/helper/generateJsonResponse.js +27 -27
  66. package/helper/getUserPreview.js +57 -57
  67. package/helper/getUserPreviewFromHeader.js +17 -17
  68. package/helper/getUserPreviewFromReq.js +17 -17
  69. package/helper/hqPublishing.js +465 -0
  70. package/helper/index.js +28 -28
  71. package/helper/notifySiteConfigs.js +67 -52
  72. package/helper/opengraph/getOpenGraph.js +12 -12
  73. package/helper/rates/checkRateLimit.js +38 -38
  74. package/helper/requestToSource.js +10 -10
  75. package/helper/sendEmail.js +120 -120
  76. package/helper/templates/replacePlaceHolders.js +29 -29
  77. package/helper/time/getLocalTimestamp.js +18 -18
  78. package/helper/time/getSiteTimezone.js +11 -11
  79. package/helper/triggerAutomatedAction.js +25 -25
  80. package/helper/userToUserPreview.js +23 -23
  81. package/helper/users/getUserTypesByPermission.js +24 -24
  82. package/helper/users/getUsersByPermission.js +20 -20
  83. package/notification/prepNotification.js +144 -144
  84. package/notification/sendNotifications.js +166 -166
  85. package/package.json +37 -40
  86. package/templates/supportTicketEmails.js +8 -8
  87. package/helper/auth/context/AuthenticationContext.js +0 -50
  88. package/helper/auth/context/AuthenticationStrategy.js +0 -20
  89. package/helper/auth/context/auth0/Strategy.js +0 -12
  90. package/helper/auth/context/auth0/functions/decodeAccessToken.js +0 -102
  91. package/helper/auth/context/auth0/functions/getSessionUser.js +0 -21
  92. package/helper/auth/context/boltonclarke/Strategy.js +0 -10
  93. package/helper/auth/context/cognito/Strategy.js +0 -12
  94. 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
- if (val) {
7
- return val;
8
- }
9
- return def;
6
+ if (val) {
7
+ return val;
8
+ }
9
+ return def;
10
10
  };
11
11
 
12
12
  exports.getRowId = (site, id) => {
13
- if (_.isEmpty(site)) {
14
- return id;
15
- }
16
- return `${site}_${id}`;
13
+ if (_.isEmpty(site)) {
14
+ return id;
15
+ }
16
+ return `${site}_${id}`;
17
17
  };
18
18
 
19
19
  exports.getMultiRowId = (cols) => {
20
- let result = "";
21
- cols.forEach((col) => {
22
- if (!_.isEmpty(result)) {
23
- result += "_";
24
- }
25
- result += col;
26
- });
27
- return result;
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
- return typeof event.body === "string" ? JSON.parse(event.body) : event.body;
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
- 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;
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
- return uuid.v4().substring(30);
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
- 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
- }
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
- // 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`;
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
- const payload = {
67
- siteId,
68
- templateIds,
69
- logId,
70
- source: "notifySiteConfigs",
71
- };
66
+ const payload = {
67
+ siteId,
68
+ templateIds,
69
+ logId,
70
+ source: "notifySiteConfigs",
71
+ };
72
72
 
73
- log("notifySiteConfigs", "InvokingLambda", { functionName, siteId, templateCount: templateIds.length }, logId);
73
+ log(
74
+ "notifySiteConfigs",
75
+ "InvokingLambda",
76
+ { functionName, siteId, templateCount: templateIds.length },
77
+ logId,
78
+ );
74
79
 
75
- try {
76
- await lambda
77
- .invoke({
78
- FunctionName: functionName,
79
- InvocationType: "Event", // Async invocation
80
- Payload: JSON.stringify(payload),
81
- })
82
- .promise();
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
- log("notifySiteConfigs", "LambdaInvoked", { functionName, siteId }, logId);
85
- } catch (err) {
86
- log("notifySiteConfigs", "LambdaError", { functionName, siteId, error: err.message }, logId);
87
- // Don't throw - this is a non-critical operation
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
- if (!siteId) {
100
- return;
101
- }
109
+ if (!siteId) {
110
+ return;
111
+ }
102
112
 
103
- // Pre-filter: Check if this site is a source for any templates
104
- const templateIds = await getTemplatesForSourceSite(siteId);
113
+ // Pre-filter: Check if this site is a source for any templates
114
+ const templateIds = await getTemplatesForSourceSite(siteId);
105
115
 
106
- if (templateIds.length === 0) {
107
- // No Lambda invocation needed
108
- return;
109
- }
116
+ if (templateIds.length === 0) {
117
+ // No Lambda invocation needed
118
+ return;
119
+ }
110
120
 
111
- log("notifySiteConfigs", "TemplatesFound", { siteId, count: templateIds.length }, logId);
121
+ log(
122
+ "notifySiteConfigs",
123
+ "TemplatesFound",
124
+ { siteId, count: templateIds.length },
125
+ logId,
126
+ );
112
127
 
113
- // Invoke siteConfigs Lambda to handle republishing
114
- await invokeSiteConfigsLambda(siteId, templateIds, logId);
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
- 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
- };
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
- try {
12
- const response = await axios(request);
13
- return resolve(response.data);
14
- } catch (e) {
15
- return reject(e);
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
- const logId = log("checkRateLimit", "Input", {
16
- rateLimitId,
17
- timeframe,
18
- limit,
19
- });
15
+ const logId = log("checkRateLimit", "Input", {
16
+ rateLimitId,
17
+ timeframe,
18
+ limit,
19
+ });
20
20
 
21
- // get rate limit item
22
- const item = await getRef("ratelimit", "Id", rateLimitId);
23
- const now = moment().valueOf();
24
- const minTime = now - timeframe;
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
- const history = item && item.History ? item.History : [];
26
+ const history = item && item.History ? item.History : [];
27
27
 
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
- }
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
- // 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
- };
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
- 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
- });
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
  };
@@ -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
- 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
- }
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
- // 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
- });
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
- toEmail,
55
- subject,
56
- content,
57
- useTemplate,
58
- {
59
- fromEmail = null,
60
- excludeClientBranding = false,
61
- brandingImage = null,
62
- bcc = null,
63
- rateLimitId = null,
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
- const { communityConfig, serverlessConfig, emailConfig, accessConfig } =
67
- getConfig();
68
- const now = moment.utc();
69
- let rateLimitIdToUse;
66
+ const { communityConfig, serverlessConfig, emailConfig, accessConfig } =
67
+ getConfig();
68
+ const now = moment.utc();
69
+ let rateLimitIdToUse;
70
70
 
71
- const logId = log("sendEmail", "Email", {
72
- toEmail,
73
- subject,
74
- });
71
+ const logId = log("sendEmail", "Email", {
72
+ toEmail,
73
+ subject,
74
+ });
75
75
 
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
- }
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
- if (useTemplate) {
96
- content = `<div style="padding: 24px; padding-top: 0px; background-color: #f2f4f8;margin: 0px;">
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
- excludeClientBranding
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
- const sesInfo = await getEmailServiceInfo(
124
- serverlessConfig.key,
125
- serverlessConfig.secret
126
- );
123
+ const sesInfo = await getEmailServiceInfo(
124
+ serverlessConfig.key,
125
+ serverlessConfig.secret,
126
+ );
127
127
 
128
- const mailOptions = {
129
- from: fromEmail || `${communityConfig.name} <${sesInfo.sender}>`,
130
- to: toEmail,
131
- bcc,
132
- subject,
133
- text: content,
134
- html: content,
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
- 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
- }
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
- if (rateLimitIdToUse) {
158
- await updateRef("ratelimit", {
159
- Id: rateLimitIdToUse,
160
- LastSent: now.valueOf(),
161
- });
162
- }
157
+ if (rateLimitIdToUse) {
158
+ await updateRef("ratelimit", {
159
+ Id: rateLimitIdToUse,
160
+ LastSent: now.valueOf(),
161
+ });
162
+ }
163
163
  };