@yrpri/api 9.0.220 → 9.0.222
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/agents/managers/subscriptionManager.js +2 -2
- package/app.js +11 -8
- package/controllers/communities.cjs +3 -1
- package/controllers/groups.cjs +1 -1
- package/controllers/images.cjs +12 -1
- package/models/domain.cjs +1 -1
- package/models/image.cjs +90 -24
- package/package.json +83 -63
- package/scripts/cloning/clearUsersForCommunitiesFromUrl.js +1 -1
- package/scripts/cloning/cloneFromUrlScript.js +1 -1
- package/scripts/cloning/cloneWBFromUrlScriptAndCreateLinks.js +1 -1
- package/scripts/cloning/cloneWBFromUrlScriptNoUsersOrPoints.js +1 -1
- package/scripts/cloning/cloneWBSerbianFromUrlScriptAndCreateLinks.js +1 -1
- package/scripts/cloning/copyCommunityConfigAndTranslationsFromURL.js +1 -1
- package/scripts/cloning/copyGroupConfigAndTranslationsFromURL.js +1 -1
- package/scripts/cloning/copyPostVideosFromURL.js +1 -1
- package/scripts/cloning/deepCloneSerbianWBFromUrlScriptAndCreateLinks.js +1 -1
- package/scripts/cloning/deepCloneWBFromUrlScriptAndCreateLinks.js +1 -1
- package/scripts/cloning/setAdminsFromURL.js +1 -1
- package/scripts/cloning/setExternalIdsFromURL.js +1 -1
- package/scripts/endorsementFraudDetection/bulkDeleteDuplicateEndorsmentsFromUrl.js +1 -1
- package/scripts/landUseGame/export3Ddata.js +1 -1
- package/scripts/movePostsToGroupsRecountGroupFromUrl.js +1 -1
- package/scripts/recountALLCommunityGroupCounts.js +1 -1
- package/scripts/recountCommunitesFromUrl.js +1 -1
- package/scripts/recountCommunity.js +1 -1
- package/scripts/setLanguageOnGroupCommunitesFromUrl.js +1 -1
- package/services/engine/allOurIdeas/aiHelper.d.ts +1 -2
- package/services/engine/analytics/manager.cjs +1 -1
- package/services/engine/analytics/plausible/manager.cjs +1 -1
- package/services/engine/analytics/utils.cjs +1 -1
- package/services/engine/notifications/emails_utils.cjs +10 -1
- package/services/engine/recommendations/events_manager.cjs +1 -1
- package/services/engine/reports/common_utils.cjs +1 -1
- package/services/llms/baseChatBot.d.ts +1 -2
- package/services/llms/imageGeneration/s3Service.js +72 -11
- package/services/scripts/translation_replace_text_from_url.js +1 -1
- package/services/utils/redisConnection.cjs +2 -3
- package/services/utils/translation_cloning.cjs +1 -1
- package/services/utils/translation_helpers.cjs +1 -1
- package/tests/emails_utils.test.cjs +130 -0
- package/tests/emails_utils.test.d.cts +1 -0
- package/tests/imageModel.test.cjs +373 -0
- package/tests/imageModel.test.d.cts +1 -0
- package/tests/multerSharpS3Compat.test.cjs +229 -0
- package/tests/multerSharpS3Compat.test.d.cts +1 -0
- package/tests/requestCompat.test.cjs +288 -0
- package/tests/requestCompat.test.d.cts +1 -0
- package/utils/multerSharpS3Compat.cjs +230 -0
- package/utils/multerSharpS3Compat.d.cts +22 -0
- package/utils/passportSsoCompat.cjs +15 -0
- package/utils/passportSsoCompat.d.cts +2 -0
- package/utils/recount_utils.cjs +1 -1
- package/utils/requestCompat.cjs +180 -0
- package/utils/requestCompat.d.cts +9 -0
|
@@ -2,7 +2,7 @@ const models = require('../../models/index.cjs');
|
|
|
2
2
|
const async = require('async');
|
|
3
3
|
const _ = require('lodash');
|
|
4
4
|
const fs = require('fs');
|
|
5
|
-
const request = require(
|
|
5
|
+
const request = require("../../utils/requestCompat.cjs");
|
|
6
6
|
const recountCommunity = require('../../utils/recount_utils.cjs').recountCommunity;
|
|
7
7
|
const recountPost = require('../../utils/recount_utils.cjs').recountPost;
|
|
8
8
|
const communityId = process.argv[2];
|
|
@@ -2,7 +2,7 @@ const models = require('../models/index.cjs');
|
|
|
2
2
|
const async = require('async');
|
|
3
3
|
const _ = require('lodash');
|
|
4
4
|
const fs = require('fs');
|
|
5
|
-
const request = require(
|
|
5
|
+
const request = require("../utils/requestCompat.cjs");
|
|
6
6
|
/*
|
|
7
7
|
const urlToConfig = "https://yrpri-eu-direct-assets.s3-eu-west-1.amazonaws.com/WBMoveIdeas160221.csv"//process.argv[1];
|
|
8
8
|
const urlToAddAddFront = "https://kyrgyz-aris.yrpri.org/"; // process.argv[2];
|
|
@@ -2,7 +2,7 @@ const models = require('../models/index.cjs');
|
|
|
2
2
|
const async = require('async');
|
|
3
3
|
const _ = require('lodash');
|
|
4
4
|
const fs = require('fs');
|
|
5
|
-
const request = require(
|
|
5
|
+
const request = require("../utils/requestCompat.cjs");
|
|
6
6
|
models.Community.findAll({
|
|
7
7
|
attributes: ['id', 'counter_groups']
|
|
8
8
|
}).then(allCommunities => {
|
|
@@ -2,7 +2,7 @@ const models = require('../models/index.cjs');
|
|
|
2
2
|
const async = require('async');
|
|
3
3
|
const _ = require('lodash');
|
|
4
4
|
const fs = require('fs');
|
|
5
|
-
const request = require(
|
|
5
|
+
const request = require("../utils/requestCompat.cjs");
|
|
6
6
|
const recountCommunity = require('../utils/recount_utils.cjs').recountCommunity;
|
|
7
7
|
/*
|
|
8
8
|
const urlToConfig = "https://yrpri-eu-direct-assets.s3-eu-west-1.amazonaws.com/WBMoveIdeas160221.csv"//process.argv[1];
|
|
@@ -2,7 +2,7 @@ const models = require('../models/index.cjs');
|
|
|
2
2
|
const async = require('async');
|
|
3
3
|
const _ = require('lodash');
|
|
4
4
|
const fs = require('fs');
|
|
5
|
-
const request = require(
|
|
5
|
+
const request = require("../utils/requestCompat.cjs");
|
|
6
6
|
const recountCommunity = require('../utils/recount_utils.cjs').recountCommunity;
|
|
7
7
|
/*
|
|
8
8
|
const urlToConfig = "https://yrpri-eu-direct-assets.s3-eu-west-1.amazonaws.com/WBMoveIdeas160221.csv"//process.argv[1];
|
|
@@ -2,7 +2,7 @@ const models = require('../models/index.cjs');
|
|
|
2
2
|
const async = require('async');
|
|
3
3
|
const _ = require('lodash');
|
|
4
4
|
const fs = require('fs');
|
|
5
|
-
const request = require(
|
|
5
|
+
const request = require("../utils/requestCompat.cjs");
|
|
6
6
|
/*
|
|
7
7
|
const urlToConfig = "https://yrpri-eu-direct-assets.s3-eu-west-1.amazonaws.com/WB_ResetLanguageOnCommuntiesList_16_02_21.csv"//process.argv[1];
|
|
8
8
|
const toLanguage = "ru"; // process.argv[2];
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { OpenAI } from "openai";
|
|
2
|
-
import { Stream } from "openai/streaming";
|
|
3
2
|
import { WebSocket } from "ws";
|
|
4
3
|
export declare class AiHelper {
|
|
5
4
|
openaiClient: OpenAI;
|
|
@@ -16,7 +15,7 @@ export declare class AiHelper {
|
|
|
16
15
|
getModerationResponse: (instructions: string, question: string, answerToModerate: string) => Promise<boolean>;
|
|
17
16
|
streamChatCompletions(messages: any[]): Promise<void>;
|
|
18
17
|
sendToClient(sender: string, message: string, type?: string): void;
|
|
19
|
-
streamWebSocketResponses(stream:
|
|
18
|
+
streamWebSocketResponses(stream: AsyncIterable<OpenAI.Chat.Completions.ChatCompletionChunk>): Promise<void>;
|
|
20
19
|
getAnswerIdeas(question: string, previousIdeas: string[] | null, firstMessage: string | null): Promise<string | null | undefined>;
|
|
21
20
|
getAiAnalysis(questionId: number, contextPrompt: string, answers: AoiChoiceData[], cacheKeyForFullResponse: string, redisClient: any, locale: string, topOrBottomIdeasText: string, typeOfAnalysisText: string): Promise<string | null | undefined>;
|
|
22
21
|
}
|
|
@@ -6,7 +6,7 @@ const importCommunity = require('./utils.cjs').importCommunity;
|
|
|
6
6
|
const importGroup = require('./utils.cjs').importGroup;
|
|
7
7
|
const importPost = require('./utils.cjs').importPost;
|
|
8
8
|
const importPoint = require('./utils.cjs').importPoint;
|
|
9
|
-
const request = require(
|
|
9
|
+
const request = require("../../../utils/requestCompat.cjs");
|
|
10
10
|
const updateDomain = (domainId, done) => {
|
|
11
11
|
log.info('updateDomain');
|
|
12
12
|
models.Domain.unscoped().findOne({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const models = require("../../../../models/index.cjs");
|
|
3
3
|
const log = require("../../../../utils/logger.cjs");
|
|
4
|
-
const request = require("
|
|
4
|
+
const request = require("../../../../utils/requestCompat.cjs");
|
|
5
5
|
const moment = require("moment");
|
|
6
6
|
// This SQL is needed to allow the site API
|
|
7
7
|
// UPDATE api_keys SET scopes = '{sites:provision:*}' WHERE name = 'Development';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const _ = require('lodash');
|
|
3
|
-
const request = require(
|
|
3
|
+
const request = require("../../../utils/requestCompat.cjs");
|
|
4
4
|
const models = require('../../../models/index.cjs');
|
|
5
5
|
const log = require('../../../utils/logger.cjs');
|
|
6
6
|
const convertToString = (integer, type) => {
|
|
@@ -242,7 +242,9 @@ const filterNotificationForDelivery = function (notification, user, template, su
|
|
|
242
242
|
}
|
|
243
243
|
else {
|
|
244
244
|
const redisKey = `${SUPPRESSION_KEYBASE}${user.id}`;
|
|
245
|
-
redisConnection
|
|
245
|
+
redisConnection
|
|
246
|
+
.get(redisKey)
|
|
247
|
+
.then((found) => {
|
|
246
248
|
if (found) {
|
|
247
249
|
log.info(`Suppressing emails for user ${user.email} settings ${LIMIT_EMAILS_FOR_SECONDS}`);
|
|
248
250
|
callback();
|
|
@@ -250,6 +252,13 @@ const filterNotificationForDelivery = function (notification, user, template, su
|
|
|
250
252
|
else {
|
|
251
253
|
processNotification(notification, user, template, subject, callback);
|
|
252
254
|
}
|
|
255
|
+
})
|
|
256
|
+
.catch((error) => {
|
|
257
|
+
log.warn("Redis suppression lookup failed, continuing delivery", {
|
|
258
|
+
err: error,
|
|
259
|
+
userId: user.id,
|
|
260
|
+
});
|
|
261
|
+
processNotification(notification, user, template, subject, callback);
|
|
253
262
|
});
|
|
254
263
|
}
|
|
255
264
|
});
|
|
@@ -3,7 +3,7 @@ const models = require('../../../models/index.cjs');
|
|
|
3
3
|
const _ = require('lodash');
|
|
4
4
|
const async = require('async');
|
|
5
5
|
const log = require('../../../utils/logger.cjs');
|
|
6
|
-
const request = require(
|
|
6
|
+
const request = require("../../../utils/requestCompat.cjs");
|
|
7
7
|
let airbrake = null;
|
|
8
8
|
if (process.env.AIRBRAKE_PROJECT_ID) {
|
|
9
9
|
airbrake = require('../../utils/airbrake.cjs');
|
|
@@ -6,7 +6,7 @@ const moment = require('moment');
|
|
|
6
6
|
const skipEmail = false;
|
|
7
7
|
const aws = require('aws-sdk');
|
|
8
8
|
const log = require('../../../utils/logger.cjs');
|
|
9
|
-
const request = require(
|
|
9
|
+
const request = require("../../../utils/requestCompat.cjs");
|
|
10
10
|
const fs = require('fs');
|
|
11
11
|
const downloadImage = (uri, filename, callback) => {
|
|
12
12
|
request.head(uri, (err, res, body) => {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { OpenAI } from "openai";
|
|
2
|
-
import { Stream } from "openai/streaming.js";
|
|
3
2
|
import WebSocket from "ws";
|
|
4
3
|
import ioredis from "ioredis";
|
|
5
4
|
export declare class YpBaseChatBot {
|
|
@@ -26,7 +25,7 @@ export declare class YpBaseChatBot {
|
|
|
26
25
|
sendAgentCompleted(name: string, lastAgent?: boolean, error?: string | undefined): void;
|
|
27
26
|
sendAgentUpdate(message: string): void;
|
|
28
27
|
sendToClient(sender: YpSenderType, message: string, type?: YpAssistantMessageType, uniqueToken?: string | undefined, hiddenContextMessage?: boolean): void;
|
|
29
|
-
streamWebSocketResponses(stream:
|
|
28
|
+
streamWebSocketResponses(stream: AsyncIterable<OpenAI.Chat.Completions.ChatCompletionChunk>): Promise<void>;
|
|
30
29
|
saveMemoryIfNeeded(): Promise<void>;
|
|
31
30
|
setChatLog(chatLog: YpSimpleChatLog[]): Promise<void>;
|
|
32
31
|
conversation(chatLog: YpSimpleChatLog[]): Promise<void>;
|
|
@@ -2,6 +2,49 @@ import AWS from "aws-sdk";
|
|
|
2
2
|
import fs from "fs";
|
|
3
3
|
import axios from "axios";
|
|
4
4
|
import log from "../../../utils/loggerTs.js";
|
|
5
|
+
const normalizeEndpointHost = (endpoint) => {
|
|
6
|
+
if (!endpoint) {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
try {
|
|
10
|
+
const normalizedUrl = new URL(endpoint.includes("://") ? endpoint : `https://${endpoint}`);
|
|
11
|
+
return {
|
|
12
|
+
host: normalizedUrl.host,
|
|
13
|
+
hostname: normalizedUrl.hostname,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return {
|
|
18
|
+
host: endpoint,
|
|
19
|
+
hostname: endpoint,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const getBucketFromVirtualHost = (parsedUrl, normalizedEndpoint) => {
|
|
24
|
+
if (!normalizedEndpoint) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
const hostSuffix = `.${normalizedEndpoint.host}`;
|
|
28
|
+
const hostnameSuffix = `.${normalizedEndpoint.hostname}`;
|
|
29
|
+
if (parsedUrl.host.endsWith(hostSuffix)) {
|
|
30
|
+
return parsedUrl.host.slice(0, -hostSuffix.length) || null;
|
|
31
|
+
}
|
|
32
|
+
if (parsedUrl.hostname.endsWith(hostnameSuffix)) {
|
|
33
|
+
return parsedUrl.hostname.slice(0, -hostnameSuffix.length) || null;
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
};
|
|
37
|
+
const getAwsBucketFromHostname = (hostname) => {
|
|
38
|
+
const s3MarkerIndex = hostname.indexOf(".s3.");
|
|
39
|
+
if (s3MarkerIndex > 0) {
|
|
40
|
+
return hostname.slice(0, s3MarkerIndex) || null;
|
|
41
|
+
}
|
|
42
|
+
const legacyS3MarkerIndex = hostname.indexOf(".s3-");
|
|
43
|
+
if (legacyS3MarkerIndex > 0) {
|
|
44
|
+
return hostname.slice(0, legacyS3MarkerIndex) || null;
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
};
|
|
5
48
|
export class S3Service {
|
|
6
49
|
constructor(cloudflareApiKey, cloudflareZoneId) {
|
|
7
50
|
this.cloudflareApiKey = cloudflareApiKey;
|
|
@@ -37,13 +80,17 @@ export class S3Service {
|
|
|
37
80
|
const params = {
|
|
38
81
|
Bucket: bucket,
|
|
39
82
|
Key: key,
|
|
40
|
-
ACL: "private",
|
|
41
83
|
};
|
|
42
84
|
log.info(`Disabling/Deleting Key from S3: ${JSON.stringify(params)}`);
|
|
43
85
|
return new Promise((resolve, reject) => {
|
|
44
|
-
s3.
|
|
86
|
+
s3.deleteObject(params, (err, data) => {
|
|
45
87
|
if (err) {
|
|
46
|
-
log.error(
|
|
88
|
+
log.error("Error deleting image from S3", {
|
|
89
|
+
imageUrl,
|
|
90
|
+
bucket,
|
|
91
|
+
key,
|
|
92
|
+
err,
|
|
93
|
+
});
|
|
47
94
|
reject(err);
|
|
48
95
|
}
|
|
49
96
|
else {
|
|
@@ -87,25 +134,39 @@ export class S3Service {
|
|
|
87
134
|
let bucket, key;
|
|
88
135
|
const cfImageProxyDomain = process.env.CLOUDFLARE_IMAGE_PROXY_DOMAIN;
|
|
89
136
|
const s3Bucket = process.env.S3_BUCKET;
|
|
137
|
+
const normalizedEndpoint = normalizeEndpointHost(process.env.S3_ENDPOINT);
|
|
138
|
+
const parsedUrl = new URL(imageUrl);
|
|
90
139
|
if (cfImageProxyDomain && imageUrl.includes(cfImageProxyDomain)) {
|
|
91
|
-
const
|
|
92
|
-
const [, ...pathParts] = urlPath.split("/");
|
|
140
|
+
const [, ...pathParts] = parsedUrl.pathname.split("/");
|
|
93
141
|
bucket = s3Bucket;
|
|
94
142
|
key = pathParts.join("/");
|
|
95
143
|
}
|
|
144
|
+
else if (normalizedEndpoint &&
|
|
145
|
+
(parsedUrl.hostname === normalizedEndpoint.hostname ||
|
|
146
|
+
parsedUrl.host === normalizedEndpoint.host)) {
|
|
147
|
+
const [, maybeBucket, ...pathParts] = parsedUrl.pathname.split("/");
|
|
148
|
+
bucket = process.env.MINIO_ROOT_USER ? maybeBucket || s3Bucket : s3Bucket;
|
|
149
|
+
key = process.env.MINIO_ROOT_USER ? pathParts.join("/") : parsedUrl.pathname.slice(1);
|
|
150
|
+
}
|
|
96
151
|
else {
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
152
|
+
const virtualHostBucket = getBucketFromVirtualHost(parsedUrl, normalizedEndpoint) ||
|
|
153
|
+
getAwsBucketFromHostname(parsedUrl.hostname);
|
|
154
|
+
if (virtualHostBucket) {
|
|
155
|
+
bucket = virtualHostBucket;
|
|
156
|
+
key = parsedUrl.pathname.replace(/^\/+/, "");
|
|
101
157
|
}
|
|
102
158
|
}
|
|
103
159
|
return { bucket, key };
|
|
104
160
|
}
|
|
105
161
|
async deleteMediaFormatsUrls(formats) {
|
|
106
162
|
for (const url of formats) {
|
|
107
|
-
|
|
108
|
-
|
|
163
|
+
try {
|
|
164
|
+
await this.deleteS3Url(url);
|
|
165
|
+
log.info(`Deleted image from S3: ${url}`);
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
log.warn("Best-effort image cleanup failed", { url, error });
|
|
169
|
+
}
|
|
109
170
|
}
|
|
110
171
|
}
|
|
111
172
|
}
|
|
@@ -2,7 +2,7 @@ const models = require('../../models/index.cjs');
|
|
|
2
2
|
const async = require('async');
|
|
3
3
|
const _ = require('lodash');
|
|
4
4
|
const fs = require('fs');
|
|
5
|
-
const request = require(
|
|
5
|
+
const request = require("../../utils/requestCompat.cjs");
|
|
6
6
|
const farmhash = require('farmhash');
|
|
7
7
|
//const communityId = "1264"; //process.argv[2];
|
|
8
8
|
//const communityId = "1402"; //process.argv[2];
|
|
@@ -9,18 +9,17 @@ if (process.env.REDIS_URL) {
|
|
|
9
9
|
}
|
|
10
10
|
if (redisUrl.includes("rediss://")) {
|
|
11
11
|
redisClient = redis.createClient({
|
|
12
|
-
legacyMode: false,
|
|
13
12
|
url: redisUrl,
|
|
14
13
|
pingInterval: 10000,
|
|
15
14
|
socket: { tls: true, rejectUnauthorized: false },
|
|
16
15
|
});
|
|
17
16
|
}
|
|
18
17
|
else {
|
|
19
|
-
redisClient = redis.createClient({
|
|
18
|
+
redisClient = redis.createClient({ url: redisUrl });
|
|
20
19
|
}
|
|
21
20
|
}
|
|
22
21
|
else {
|
|
23
|
-
redisClient = redis.createClient(
|
|
22
|
+
redisClient = redis.createClient();
|
|
24
23
|
}
|
|
25
24
|
redisClient.on("error", (err) => log.error("Backend Redis client error", err));
|
|
26
25
|
redisClient.on("connect", () => log.info("Backend Redis client is connect"));
|
|
@@ -3,7 +3,7 @@ const models = require('../../models/index.cjs');
|
|
|
3
3
|
const async = require('async');
|
|
4
4
|
const _ = require('lodash');
|
|
5
5
|
const fs = require('fs');
|
|
6
|
-
const request = require(
|
|
6
|
+
const request = require("../../utils/requestCompat.cjs");
|
|
7
7
|
const farmhash = require('farmhash');
|
|
8
8
|
const fixTargetLocale = require('./translation_helpers.cjs').fixTargetLocale;
|
|
9
9
|
// For post get translations in all locales (that exists)
|
|
@@ -3,7 +3,7 @@ const models = require("../../models/index.cjs");
|
|
|
3
3
|
const async = require("async");
|
|
4
4
|
const _ = require("lodash");
|
|
5
5
|
const fs = require("fs");
|
|
6
|
-
const request = require("
|
|
6
|
+
const request = require("../../utils/requestCompat.cjs");
|
|
7
7
|
const farmhash = require("farmhash");
|
|
8
8
|
const log = require('../../utils/logger.cjs');
|
|
9
9
|
const fixTargetLocale = (itemTargetLocale) => {
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const test = require("node:test");
|
|
3
|
+
const assert = require("node:assert/strict");
|
|
4
|
+
const fs = require("node:fs");
|
|
5
|
+
const path = require("node:path");
|
|
6
|
+
const vm = require("node:vm");
|
|
7
|
+
const Module = require("node:module");
|
|
8
|
+
const emailsUtilsPath = path.resolve(__dirname, "../services/engine/notifications/emails_utils.cjs");
|
|
9
|
+
const loadEmailsUtils = ({ logger, redisConnection, queue, models }) => {
|
|
10
|
+
const source = fs.readFileSync(emailsUtilsPath, "utf8");
|
|
11
|
+
const module = { exports: {} };
|
|
12
|
+
const baseRequire = Module.createRequire(emailsUtilsPath);
|
|
13
|
+
const mockedRequire = (request) => {
|
|
14
|
+
switch (request) {
|
|
15
|
+
case "../../../utils/logger.cjs":
|
|
16
|
+
return logger;
|
|
17
|
+
case "../../utils/redisConnection.cjs":
|
|
18
|
+
return redisConnection;
|
|
19
|
+
case "../../workers/queue.cjs":
|
|
20
|
+
return queue;
|
|
21
|
+
case "../../../models/index.cjs":
|
|
22
|
+
return models;
|
|
23
|
+
case "nodemailer":
|
|
24
|
+
return {
|
|
25
|
+
createTransport() {
|
|
26
|
+
return {
|
|
27
|
+
verify(callback) {
|
|
28
|
+
if (callback) {
|
|
29
|
+
callback(null, true);
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
case "../../utils/i18n.cjs":
|
|
36
|
+
return {
|
|
37
|
+
t(value) {
|
|
38
|
+
return value;
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
default:
|
|
42
|
+
return baseRequire(request);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
const wrapped = Module.wrap(source);
|
|
46
|
+
const compiled = vm.runInThisContext(wrapped, {
|
|
47
|
+
filename: emailsUtilsPath,
|
|
48
|
+
});
|
|
49
|
+
compiled(module.exports, mockedRequire, module, emailsUtilsPath, path.dirname(emailsUtilsPath));
|
|
50
|
+
return module.exports;
|
|
51
|
+
};
|
|
52
|
+
test("filterNotificationForDelivery falls back to delivery when Redis suppression lookup fails", async () => {
|
|
53
|
+
const queuedEmails = [];
|
|
54
|
+
const redisSetExCalls = [];
|
|
55
|
+
const warnings = [];
|
|
56
|
+
const emailsUtils = loadEmailsUtils({
|
|
57
|
+
logger: {
|
|
58
|
+
info() { },
|
|
59
|
+
error() { },
|
|
60
|
+
warn(message, metadata) {
|
|
61
|
+
warnings.push({ message, metadata });
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
redisConnection: {
|
|
65
|
+
async get() {
|
|
66
|
+
throw new Error("redis down");
|
|
67
|
+
},
|
|
68
|
+
setEx(...args) {
|
|
69
|
+
redisSetExCalls.push(args);
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
queue: {
|
|
73
|
+
add(...args) {
|
|
74
|
+
queuedEmails.push(args);
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
models: {
|
|
78
|
+
AcNotification: {
|
|
79
|
+
METHOD_MUTED: "muted",
|
|
80
|
+
FREQUENCY_AS_IT_HAPPENS: "as_it_happens",
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
const group = {
|
|
85
|
+
name: "visible-group",
|
|
86
|
+
async hasGroupAdmins() {
|
|
87
|
+
return false;
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
const user = {
|
|
91
|
+
id: 42,
|
|
92
|
+
email: "person@example.com",
|
|
93
|
+
notifications_settings: {
|
|
94
|
+
point_activity: {
|
|
95
|
+
method: "email",
|
|
96
|
+
frequency: "as_it_happens",
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
const notification = {
|
|
101
|
+
from_notification_setting: "point_activity",
|
|
102
|
+
AcActivities: [
|
|
103
|
+
{
|
|
104
|
+
Domain: { id: 1 },
|
|
105
|
+
Community: null,
|
|
106
|
+
Group: group,
|
|
107
|
+
Point: {
|
|
108
|
+
Group: group,
|
|
109
|
+
},
|
|
110
|
+
Post: null,
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
};
|
|
114
|
+
await new Promise((resolve, reject) => {
|
|
115
|
+
emailsUtils.filterNotificationForDelivery(notification, user, "point_activity", "A subject", (error) => {
|
|
116
|
+
if (error) {
|
|
117
|
+
reject(error);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
resolve();
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
assert.equal(warnings.length, 1);
|
|
125
|
+
assert.equal(warnings[0].message, "Redis suppression lookup failed, continuing delivery");
|
|
126
|
+
assert.equal(warnings[0].metadata.userId, 42);
|
|
127
|
+
assert.equal(queuedEmails.length, 1);
|
|
128
|
+
assert.equal(queuedEmails[0][0], "send-one-email");
|
|
129
|
+
assert.equal(redisSetExCalls.length, 1);
|
|
130
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|