@plusscommunities/pluss-core-aws 2.0.25-auth.0 → 2.0.25-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.
Files changed (90) 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/scheduledActions/deleteActionQueue.js +1 -1
  30. package/db/scheduledActions/getActionQueueByEntityId.js +10 -10
  31. package/db/scheduledActions/getActionQueueByEntityKey.js +9 -9
  32. package/db/scheduledActions/getActionQueueById.js +9 -9
  33. package/db/scheduledActions/getActionQueueByTriggerAt.js +14 -14
  34. package/db/scheduledActions/updateActionQueue.js +29 -29
  35. package/db/strings/getString.js +20 -20
  36. package/db/strings/logUpdate.js +18 -18
  37. package/db/templates/getTemplateById.js +1 -1
  38. package/db/templates/getTemplatesList.js +10 -10
  39. package/db/templates/updateTemplate.js +9 -9
  40. package/db/users/getRole.js +1 -1
  41. package/db/users/getUser.js +9 -9
  42. package/db/users/getUserByEmail.js +17 -17
  43. package/helper/audience/filterByAudienceType.js +27 -27
  44. package/helper/audience/filterOnAudienceType.js +26 -26
  45. package/helper/audience/getAudience.js +187 -187
  46. package/helper/audience/getMatchingAudienceTypes.js +21 -21
  47. package/helper/audience/getMatchingAudienceTypesFromPreview.js +60 -60
  48. package/helper/audience/getMatchingTags.js +15 -15
  49. package/helper/audience/isValidAudience.js +20 -20
  50. package/helper/auth/checkTokenBlacklist.js +17 -17
  51. package/helper/auth/getApiKeyFromReq.js +2 -2
  52. package/helper/auth/getSessionUser.js +70 -85
  53. package/helper/auth/getSessionUserFromReq.js +2 -2
  54. package/helper/auth/getSessionUserFromReqAuthKey.js +11 -11
  55. package/helper/auth/validateApiKey.js +32 -32
  56. package/helper/auth/validateMasterAuth.js +174 -174
  57. package/helper/auth/validateSiteAccess.js +12 -12
  58. package/helper/auth/validateSiteSetting.js +7 -7
  59. package/helper/auth/validateUserLoggedIn.js +19 -19
  60. package/helper/createGuid.js +5 -5
  61. package/helper/generateJsonResponse.js +27 -27
  62. package/helper/getUserPreview.js +57 -57
  63. package/helper/getUserPreviewFromHeader.js +17 -17
  64. package/helper/getUserPreviewFromReq.js +17 -17
  65. package/helper/hqPublishing.js +337 -0
  66. package/helper/index.js +28 -28
  67. package/helper/notifySiteConfigs.js +132 -0
  68. package/helper/opengraph/getOpenGraph.js +12 -12
  69. package/helper/rates/checkRateLimit.js +38 -38
  70. package/helper/requestToSource.js +10 -10
  71. package/helper/sendEmail.js +120 -120
  72. package/helper/templates/replacePlaceHolders.js +29 -29
  73. package/helper/time/getLocalTimestamp.js +18 -18
  74. package/helper/time/getSiteTimezone.js +11 -11
  75. package/helper/triggerAutomatedAction.js +25 -25
  76. package/helper/userToUserPreview.js +23 -23
  77. package/helper/users/getUserTypesByPermission.js +24 -24
  78. package/helper/users/getUsersByPermission.js +20 -20
  79. package/notification/prepNotification.js +144 -144
  80. package/notification/sendNotifications.js +166 -166
  81. package/package.json +35 -40
  82. package/templates/supportTicketEmails.js +8 -8
  83. package/helper/auth/context/AuthenticationContext.js +0 -50
  84. package/helper/auth/context/AuthenticationStrategy.js +0 -20
  85. package/helper/auth/context/auth0/Strategy.js +0 -12
  86. package/helper/auth/context/auth0/functions/decodeAccessToken.js +0 -102
  87. package/helper/auth/context/auth0/functions/getSessionUser.js +0 -21
  88. package/helper/auth/context/boltonclarke/Strategy.js +0 -10
  89. package/helper/auth/context/cognito/Strategy.js +0 -12
  90. package/helper/auth/context/cognito/functions/getSessionUser.js +0 -76
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Notify SiteConfigs Service of Operational Data Changes
3
+ *
4
+ * This helper provides a pre-filtering mechanism for auto-propagation.
5
+ * When operational data changes (sites, usertypes, interfaces, strings, jobTypes),
6
+ * this function:
7
+ *
8
+ * 1. Queries SourceSiteIdIndex to check if any templates use this site as source
9
+ * 2. If none found → early return (no Lambda invoke, 99% of cases)
10
+ * 3. If templates found → invokes siteConfigs Lambda to handle republishing
11
+ *
12
+ * This hybrid approach ensures:
13
+ * - No Lambda latency for most sites (pre-filter catches non-source sites)
14
+ * - Publishing logic stays encapsulated in siteConfigs service
15
+ * - Minimal cross-service coupling
16
+ *
17
+ * Usage:
18
+ * const notifySiteConfigs = require("@plusscommunities/pluss-core-aws/helper/notifySiteConfigs");
19
+ * await notifySiteConfigs(siteId, logId);
20
+ */
21
+
22
+ const AWS = require("aws-sdk");
23
+ const indexQuery = require("../db/common/indexQuery");
24
+ const { log } = require("./index");
25
+
26
+ const lambda = new AWS.Lambda();
27
+
28
+ const TABLE_NAME = "siteconfigs";
29
+
30
+ /**
31
+ * Check if a site has any templates using it as a source
32
+ * @param {string} siteId - The site ID to check
33
+ * @returns {Promise<Array>} Array of template IDs (empty if none)
34
+ */
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
+ }
51
+ };
52
+
53
+ /**
54
+ * Invoke the siteConfigs operationalDataChanged Lambda
55
+ * @param {string} siteId - The source site that changed
56
+ * @param {Array<string>} templateIds - List of template IDs to republish
57
+ * @param {string} logId - Log ID for tracing
58
+ */
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`;
65
+
66
+ const payload = {
67
+ siteId,
68
+ templateIds,
69
+ logId,
70
+ source: "notifySiteConfigs",
71
+ };
72
+
73
+ log(
74
+ "notifySiteConfigs",
75
+ "InvokingLambda",
76
+ { functionName, siteId, templateCount: templateIds.length },
77
+ logId,
78
+ );
79
+
80
+ try {
81
+ await lambda
82
+ .invoke({
83
+ FunctionName: functionName,
84
+ InvocationType: "Event", // Async invocation
85
+ Payload: JSON.stringify(payload),
86
+ })
87
+ .promise();
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
+ }
99
+ };
100
+
101
+ /**
102
+ * Notify siteConfigs service that operational data has changed for a site.
103
+ * Performs pre-filtering to avoid unnecessary Lambda invocations.
104
+ *
105
+ * @param {string} siteId - The site ID where operational data changed
106
+ * @param {string} logId - Optional log ID for tracing
107
+ */
108
+ const notifySiteConfigs = async (siteId, logId) => {
109
+ if (!siteId) {
110
+ return;
111
+ }
112
+
113
+ // Pre-filter: Check if this site is a source for any templates
114
+ const templateIds = await getTemplatesForSourceSite(siteId);
115
+
116
+ if (templateIds.length === 0) {
117
+ // No Lambda invocation needed
118
+ return;
119
+ }
120
+
121
+ log(
122
+ "notifySiteConfigs",
123
+ "TemplatesFound",
124
+ { siteId, count: templateIds.length },
125
+ logId,
126
+ );
127
+
128
+ // Invoke siteConfigs Lambda to handle republishing
129
+ await invokeSiteConfigsLambda(siteId, templateIds, logId);
130
+ };
131
+
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
  };
@@ -1,32 +1,32 @@
1
1
  module.exports = (template, toReplace = null, user = null) => {
2
- let replaced = template;
3
- if (toReplace) {
4
- Object.keys(toReplace).forEach((key) => {
5
- replaced = replaced.replace(
6
- new RegExp(`{{${key}}}`, "g"),
7
- toReplace[key] || ""
8
- );
9
- });
10
- }
11
- if (user) {
12
- const nameReplace =
13
- (toReplace?.names && toReplace?.names[user.Id]) || user.displayName;
14
- const phoneReplace =
15
- (toReplace?.phoneNumbers && toReplace?.phoneNumbers[user.Id]) ||
16
- user.phoneNumber;
17
- // Remove surname
18
- const firstname = nameReplace
19
- ? nameReplace.split(" ").map((n) => n.trim())[0]
20
- : null;
21
- replaced = replaced
22
- .replace(new RegExp("{{name}}", "g"), firstname || "{{name}}")
23
- .replace(new RegExp("{{fullname}}", "g"), nameReplace || "{{fullname}}")
24
- .replace(
25
- new RegExp("{{phoneNumber}}", "g"),
26
- phoneReplace || "{{phoneNumber}}"
27
- )
28
- .replace(new RegExp("{{email}}", "g"), user.email || "{{email}}");
29
- }
2
+ let replaced = template;
3
+ if (toReplace) {
4
+ Object.keys(toReplace).forEach((key) => {
5
+ replaced = replaced.replace(
6
+ new RegExp(`{{${key}}}`, "g"),
7
+ toReplace[key] || "",
8
+ );
9
+ });
10
+ }
11
+ if (user) {
12
+ const nameReplace =
13
+ (toReplace?.names && toReplace?.names[user.Id]) || user.displayName;
14
+ const phoneReplace =
15
+ (toReplace?.phoneNumbers && toReplace?.phoneNumbers[user.Id]) ||
16
+ user.phoneNumber;
17
+ // Remove surname
18
+ const firstname = nameReplace
19
+ ? nameReplace.split(" ").map((n) => n.trim())[0]
20
+ : null;
21
+ replaced = replaced
22
+ .replace(new RegExp("{{name}}", "g"), firstname || "{{name}}")
23
+ .replace(new RegExp("{{fullname}}", "g"), nameReplace || "{{fullname}}")
24
+ .replace(
25
+ new RegExp("{{phoneNumber}}", "g"),
26
+ phoneReplace || "{{phoneNumber}}",
27
+ )
28
+ .replace(new RegExp("{{email}}", "g"), user.email || "{{email}}");
29
+ }
30
30
 
31
- return replaced;
31
+ return replaced;
32
32
  };
@@ -1,25 +1,25 @@
1
1
  const moment = require("moment-timezone");
2
2
 
3
3
  module.exports = (dateString, timeOfDay, timezone, resultFormat = "value") => {
4
- // Parse the date string into a moment object in the given timezone
5
- const dateMoment = moment.tz(dateString, "DD-MM-YYYY", timezone);
4
+ // Parse the date string into a moment object in the given timezone
5
+ const dateMoment = moment.tz(dateString, "DD-MM-YYYY", timezone);
6
6
 
7
- // Calculate the hours and minutes from the timeOfDay in minutes
8
- const hours = Math.floor(timeOfDay / 60);
9
- const minutes = timeOfDay % 60;
7
+ // Calculate the hours and minutes from the timeOfDay in minutes
8
+ const hours = Math.floor(timeOfDay / 60);
9
+ const minutes = timeOfDay % 60;
10
10
 
11
- // Set the hours and minutes to the dateMoment
12
- dateMoment.hours(hours).minutes(minutes).seconds(0).milliseconds(0);
11
+ // Set the hours and minutes to the dateMoment
12
+ dateMoment.hours(hours).minutes(minutes).seconds(0).milliseconds(0);
13
13
 
14
- switch (resultFormat) {
15
- case "string":
16
- // return the timestamp in string format
17
- return dateMoment.format();
18
- case "value":
19
- // Return the timestamp in milliseconds
20
- return dateMoment.valueOf();
21
- default:
22
- // return the timestamp in a formatted string
23
- return dateMoment.format(resultFormat);
24
- }
14
+ switch (resultFormat) {
15
+ case "string":
16
+ // return the timestamp in string format
17
+ return dateMoment.format();
18
+ case "value":
19
+ // Return the timestamp in milliseconds
20
+ return dateMoment.valueOf();
21
+ default:
22
+ // return the timestamp in a formatted string
23
+ return dateMoment.format(resultFormat);
24
+ }
25
25
  };