@bprotsyk/aso-core 2.1.58 → 2.1.60

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.
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Додає всі унікальні потоки з усіх кампаній до кампанії з ID 888
3
+ */
4
+ export declare function addAllStreamsToTestCampaign(): Promise<void>;
5
+ /**
6
+ * Додає всі унікальні потоки з усіх кампаній до вказаної кампанії
7
+ */
8
+ export declare function addAllStreamsToCampaign(targetCampaignId: number): Promise<void>;
9
+ /**
10
+ * Синхронізує потоки між усіма кампаніями з символом ◈ в назві
11
+ */
12
+ export declare function synchronizeStreamsAcrossAllCampaigns(): Promise<void>;
13
+ /**
14
+ * Додає всі потоки з усіх кампаній до кампанії з назвою "888" з символом [◈]
15
+ */
16
+ export declare function addAllStreamsToMarkedCampaign(): Promise<void>;
17
+ /**
18
+ * Вирівнює потоки між усіма кампаніями.
19
+ * Збирає всі унікальні потоки з усіх кампаній та додає відсутні потоки в кожну кампанію.
20
+ */
21
+ export declare function equalizeStreamsBetweenAllCampaigns(): Promise<void>;
22
+ export declare const KeitaroStreamsService: {
23
+ addAllStreamsToTestCampaign: typeof addAllStreamsToTestCampaign;
24
+ addAllStreamsToCampaign: typeof addAllStreamsToCampaign;
25
+ synchronizeStreamsAcrossAllCampaigns: typeof synchronizeStreamsAcrossAllCampaigns;
26
+ addAllStreamsToMarkedCampaign: typeof addAllStreamsToMarkedCampaign;
27
+ equalizeStreamsBetweenAllCampaigns: typeof equalizeStreamsBetweenAllCampaigns;
28
+ };
@@ -0,0 +1,510 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.KeitaroStreamsService = exports.equalizeStreamsBetweenAllCampaigns = exports.addAllStreamsToMarkedCampaign = exports.synchronizeStreamsAcrossAllCampaigns = exports.addAllStreamsToCampaign = exports.addAllStreamsToTestCampaign = void 0;
7
+ const http_1 = __importDefault(require("../network/keitaro/http"));
8
+ /**
9
+ * Отримує всі кампанії з Keitaro
10
+ */
11
+ async function getAllCampaigns() {
12
+ const { data: campaigns } = await http_1.default.get('campaigns');
13
+ return campaigns;
14
+ }
15
+ /**
16
+ * Отримує всі потоки для конкретної кампанії
17
+ */
18
+ async function getStreamsByCampaignId(campaignId) {
19
+ const { data: streams } = await http_1.default.get(`campaigns/${campaignId}/streams`);
20
+ return streams;
21
+ }
22
+ /**
23
+ * Додає всі унікальні потоки з усіх кампаній до кампанії з ID 888
24
+ */
25
+ async function addAllStreamsToTestCampaign() {
26
+ const TARGET_CAMPAIGN_ID = 888; // ID цільової кампанії для тесту
27
+ // Перевіряємо, чи існує цільова кампанія
28
+ try {
29
+ await http_1.default.get(`campaigns/${TARGET_CAMPAIGN_ID}`);
30
+ }
31
+ catch (error) {
32
+ console.error(`Кампанія з ID ${TARGET_CAMPAIGN_ID} не знайдена`);
33
+ return;
34
+ }
35
+ console.log(`Починаємо збір усіх унікальних потоків...`);
36
+ // Отримуємо всі кампанії
37
+ const allCampaigns = await getAllCampaigns();
38
+ console.log(`Знайдено ${allCampaigns.length} кампаній`);
39
+ // Створюємо мапу для зберігання всіх унікальних потоків
40
+ const allUniqueStreams = new Map();
41
+ // Збираємо всі унікальні потоки з усіх кампаній
42
+ for (const campaign of allCampaigns) {
43
+ if (campaign.id === TARGET_CAMPAIGN_ID)
44
+ continue; // Пропускаємо цільову кампанію
45
+ console.log(`Обробка кампанії ${campaign.id} (${campaign.name})...`);
46
+ const streams = await getStreamsByCampaignId(campaign.id);
47
+ for (const stream of streams) {
48
+ // Визначаємо унікальний ключ для потоку
49
+ // Використовуємо filter payload, якщо він є, інакше використовуємо назву потоку
50
+ const streamKey = stream.filters && stream.filters.length > 0 &&
51
+ stream.filters[0].payload && stream.filters[0].payload.length > 0
52
+ ? `filter:${stream.filters[0].name}:${stream.filters[0].payload[0]}`
53
+ : `name:${stream.name}`;
54
+ if (!allUniqueStreams.has(streamKey)) {
55
+ allUniqueStreams.set(streamKey, stream);
56
+ console.log(`Додано унікальний потік: ${stream.name} (ключ: ${streamKey})`);
57
+ }
58
+ }
59
+ }
60
+ console.log(`Знайдено ${allUniqueStreams.size} унікальних потоків`);
61
+ // Отримуємо існуючі потоки цільової кампанії
62
+ const existingStreams = await getStreamsByCampaignId(TARGET_CAMPAIGN_ID);
63
+ // Створюємо множину існуючих ключів потоків
64
+ const existingStreamKeys = new Set();
65
+ for (const stream of existingStreams) {
66
+ const streamKey = stream.filters && stream.filters.length > 0 &&
67
+ stream.filters[0].payload && stream.filters[0].payload.length > 0
68
+ ? `filter:${stream.filters[0].name}:${stream.filters[0].payload[0]}`
69
+ : `name:${stream.name}`;
70
+ existingStreamKeys.add(streamKey);
71
+ }
72
+ console.log(`Кампанія ${TARGET_CAMPAIGN_ID} вже має ${existingStreamKeys.size} потоків`);
73
+ // Додаємо відсутні потоки до цільової кампанії
74
+ let addedStreamsCount = 0;
75
+ let errorCount = 0;
76
+ for (const [streamKey, sourceStream] of allUniqueStreams.entries()) {
77
+ if (!existingStreamKeys.has(streamKey)) {
78
+ try {
79
+ await http_1.default.post('streams', {
80
+ name: sourceStream.name,
81
+ campaign_id: TARGET_CAMPAIGN_ID,
82
+ schema: sourceStream.schema,
83
+ type: sourceStream.type,
84
+ action_type: sourceStream.action_type,
85
+ weight: sourceStream.weight,
86
+ offers: sourceStream.offers.map((offer) => ({
87
+ offer_id: offer.offer_id,
88
+ share: offer.share,
89
+ state: offer.state
90
+ })),
91
+ filters: sourceStream.filters.map((filter) => ({
92
+ name: filter.name,
93
+ mode: filter.mode,
94
+ payload: filter.payload
95
+ })),
96
+ position: sourceStream.position,
97
+ state: sourceStream.state
98
+ });
99
+ addedStreamsCount++;
100
+ console.log(`Додано потік ${addedStreamsCount}: ${sourceStream.name}`);
101
+ }
102
+ catch (error) {
103
+ errorCount++;
104
+ console.error(`Помилка при додаванні потоку "${sourceStream.name}":`, error);
105
+ }
106
+ }
107
+ }
108
+ console.log(`Результат: додано ${addedStreamsCount} потоків, помилок: ${errorCount}`);
109
+ console.log(`Всього потоків у кампанії ${TARGET_CAMPAIGN_ID} тепер: ${existingStreamKeys.size + addedStreamsCount}`);
110
+ }
111
+ exports.addAllStreamsToTestCampaign = addAllStreamsToTestCampaign;
112
+ /**
113
+ * Додає всі унікальні потоки з усіх кампаній до вказаної кампанії
114
+ */
115
+ async function addAllStreamsToCampaign(targetCampaignId) {
116
+ // Перевіряємо, чи існує цільова кампанія
117
+ try {
118
+ await http_1.default.get(`campaigns/${targetCampaignId}`);
119
+ }
120
+ catch (error) {
121
+ console.error(`Кампанія з ID ${targetCampaignId} не знайдена`);
122
+ return;
123
+ }
124
+ console.log(`Починаємо збір усіх унікальних потоків...`);
125
+ // Отримуємо всі кампанії
126
+ const allCampaigns = await getAllCampaigns();
127
+ console.log(`Знайдено ${allCampaigns.length} кампаній`);
128
+ // Створюємо мапу для зберігання всіх унікальних потоків
129
+ const allUniqueStreams = new Map();
130
+ // Збираємо всі унікальні потоки з усіх кампаній
131
+ for (const campaign of allCampaigns) {
132
+ if (campaign.id === targetCampaignId)
133
+ continue; // Пропускаємо цільову кампанію
134
+ console.log(`Обробка кампанії ${campaign.id} (${campaign.name})...`);
135
+ const streams = await getStreamsByCampaignId(campaign.id);
136
+ for (const stream of streams) {
137
+ // Пропускаємо потоки, які мають фільтр за країною, крім "Bot Protection"
138
+ if (stream.name !== "Bot Protection" &&
139
+ stream.filters && stream.filters.length > 0 &&
140
+ stream.filters.some(filter => filter.name === 'country')) {
141
+ console.log(`Пропущено потік: ${stream.name} (фільтр за країною)`);
142
+ continue;
143
+ }
144
+ // Визначаємо унікальний ключ для потоку
145
+ const streamKey = stream.filters && stream.filters.length > 0 &&
146
+ stream.filters[0].payload && stream.filters[0].payload.length > 0
147
+ ? `filter:${stream.filters[0].name}:${stream.filters[0].payload[0]}`
148
+ : `name:${stream.name}`;
149
+ if (!allUniqueStreams.has(streamKey)) {
150
+ allUniqueStreams.set(streamKey, stream);
151
+ console.log(`Знайдено унікальний потік: ${stream.name} (ключ: ${streamKey})`);
152
+ }
153
+ }
154
+ }
155
+ console.log(`Знайдено ${allUniqueStreams.size} унікальних потоків`);
156
+ // Отримуємо існуючі потоки цільової кампанії
157
+ const existingStreams = await getStreamsByCampaignId(targetCampaignId);
158
+ // Створюємо множину існуючих ключів потоків
159
+ const existingStreamKeys = new Set();
160
+ for (const stream of existingStreams) {
161
+ const streamKey = stream.filters && stream.filters.length > 0 &&
162
+ stream.filters[0].payload && stream.filters[0].payload.length > 0
163
+ ? `filter:${stream.filters[0].name}:${stream.filters[0].payload[0]}`
164
+ : `name:${stream.name}`;
165
+ existingStreamKeys.add(streamKey);
166
+ }
167
+ console.log(`Кампанія ${targetCampaignId} вже має ${existingStreamKeys.size} потоків`);
168
+ // Додаємо відсутні потоки до цільової кампанії
169
+ let addedStreamsCount = 0;
170
+ let errorCount = 0;
171
+ for (const [streamKey, sourceStream] of allUniqueStreams.entries()) {
172
+ if (!existingStreamKeys.has(streamKey)) {
173
+ try {
174
+ await http_1.default.post('streams', {
175
+ name: sourceStream.name,
176
+ campaign_id: targetCampaignId,
177
+ schema: sourceStream.schema,
178
+ type: sourceStream.type,
179
+ action_type: sourceStream.action_type,
180
+ weight: sourceStream.weight,
181
+ offers: sourceStream.offers.map((offer) => ({
182
+ offer_id: offer.offer_id,
183
+ share: offer.share,
184
+ state: offer.state
185
+ })),
186
+ filters: sourceStream.filters.map((filter) => ({
187
+ name: filter.name,
188
+ mode: filter.mode,
189
+ payload: filter.payload
190
+ })),
191
+ position: sourceStream.position,
192
+ state: sourceStream.state
193
+ });
194
+ addedStreamsCount++;
195
+ console.log(`Додано потік ${addedStreamsCount}: ${sourceStream.name}`);
196
+ }
197
+ catch (error) {
198
+ errorCount++;
199
+ console.error(`Помилка при додаванні потоку "${sourceStream.name}":`, error);
200
+ }
201
+ }
202
+ }
203
+ console.log(`Результат: додано ${addedStreamsCount} потоків, помилок: ${errorCount}`);
204
+ console.log(`Всього потоків у кампанії ${targetCampaignId} тепер: ${existingStreamKeys.size + addedStreamsCount}`);
205
+ }
206
+ exports.addAllStreamsToCampaign = addAllStreamsToCampaign;
207
+ /**
208
+ * Синхронізує потоки між усіма кампаніями з символом ◈ в назві
209
+ */
210
+ async function synchronizeStreamsAcrossAllCampaigns() {
211
+ // Отримуємо всі кампанії з символом ◈
212
+ const allCampaigns = await getAllCampaigns();
213
+ const targetCampaigns = allCampaigns.filter(campaign => /◈/.test(campaign.name));
214
+ console.log(`Знайдено ${targetCampaigns.length} кампаній з символом ◈`);
215
+ // Створюємо мапу для зберігання всіх унікальних потоків
216
+ const allUniqueStreams = new Map();
217
+ // Збираємо всі унікальні потоки з усіх кампаній
218
+ for (const campaign of targetCampaigns) {
219
+ const streams = await getStreamsByCampaignId(campaign.id);
220
+ for (const stream of streams) {
221
+ // Визначаємо унікальний ключ для потоку
222
+ const streamKey = stream.filters && stream.filters.length > 0 &&
223
+ stream.filters[0].payload && stream.filters[0].payload.length > 0
224
+ ? `filter:${stream.filters[0].name}:${stream.filters[0].payload[0]}`
225
+ : `name:${stream.name}`;
226
+ if (!allUniqueStreams.has(streamKey)) {
227
+ allUniqueStreams.set(streamKey, stream);
228
+ }
229
+ }
230
+ }
231
+ console.log(`Знайдено ${allUniqueStreams.size} унікальних потоків`);
232
+ // Додаємо відсутні потоки до кожної кампанії
233
+ for (const campaign of targetCampaigns) {
234
+ const existingStreams = await getStreamsByCampaignId(campaign.id);
235
+ // Створюємо множину існуючих ключів потоків
236
+ const existingStreamKeys = new Set();
237
+ for (const stream of existingStreams) {
238
+ const streamKey = stream.filters && stream.filters.length > 0 &&
239
+ stream.filters[0].payload && stream.filters[0].payload.length > 0
240
+ ? `filter:${stream.filters[0].name}:${stream.filters[0].payload[0]}`
241
+ : `name:${stream.name}`;
242
+ existingStreamKeys.add(streamKey);
243
+ }
244
+ // Додаємо відсутні потоки
245
+ let addedStreamsCount = 0;
246
+ let errorCount = 0;
247
+ for (const [streamKey, sourceStream] of allUniqueStreams.entries()) {
248
+ if (!existingStreamKeys.has(streamKey)) {
249
+ try {
250
+ await http_1.default.post('streams', {
251
+ name: sourceStream.name,
252
+ campaign_id: campaign.id,
253
+ schema: sourceStream.schema,
254
+ type: sourceStream.type,
255
+ action_type: sourceStream.action_type,
256
+ weight: sourceStream.weight,
257
+ offers: sourceStream.offers.map((offer) => ({
258
+ offer_id: offer.offer_id,
259
+ share: offer.share,
260
+ state: offer.state
261
+ })),
262
+ filters: sourceStream.filters.map((filter) => ({
263
+ name: filter.name,
264
+ mode: filter.mode,
265
+ payload: filter.payload
266
+ })),
267
+ position: sourceStream.position,
268
+ state: sourceStream.state
269
+ });
270
+ addedStreamsCount++;
271
+ }
272
+ catch (error) {
273
+ errorCount++;
274
+ console.error(`Помилка при додаванні потоку "${sourceStream.name}" до кампанії ${campaign.id} (${campaign.name}):`, error);
275
+ }
276
+ }
277
+ }
278
+ console.log(`Додано ${addedStreamsCount} потоків до кампанії ${campaign.id} (${campaign.name}), помилок: ${errorCount}`);
279
+ }
280
+ console.log("Синхронізація потоків завершена");
281
+ }
282
+ exports.synchronizeStreamsAcrossAllCampaigns = synchronizeStreamsAcrossAllCampaigns;
283
+ /**
284
+ * Додає всі потоки з усіх кампаній до кампанії з назвою "888" з символом [◈]
285
+ */
286
+ async function addAllStreamsToMarkedCampaign() {
287
+ const TARGET_CAMPAIGN_NAME = "888"; // Назва цільової кампанії
288
+ console.log(`Починаємо додавання всіх потоків до кампанії з назвою "${TARGET_CAMPAIGN_NAME}" [◈]...`);
289
+ // Отримуємо всі кампанії
290
+ const allCampaigns = await getAllCampaigns();
291
+ console.log(`Знайдено ${allCampaigns.length} кампаній`);
292
+ // Шукаємо кампанію за назвою
293
+ const targetCampaign = allCampaigns.find(campaign => campaign.name.includes(TARGET_CAMPAIGN_NAME));
294
+ if (!targetCampaign) {
295
+ console.error(`Кампанія з назвою "${TARGET_CAMPAIGN_NAME}" не знайдена`);
296
+ return;
297
+ }
298
+ const TARGET_CAMPAIGN_ID = targetCampaign.id;
299
+ console.log(`Знайдено кампанію "${targetCampaign.name}" з ID ${TARGET_CAMPAIGN_ID}`);
300
+ // Перевіряємо, чи містить назва кампанії символ [◈]
301
+ if (!targetCampaign.name.includes('[◈]')) {
302
+ console.error(`Кампанія "${targetCampaign.name}" не містить символ [◈] у назві`);
303
+ // Оновлюємо назву кампанії, додаючи [◈]
304
+ const updatedName = `${targetCampaign.name} [◈]`;
305
+ await http_1.default.post(`campaigns/${TARGET_CAMPAIGN_ID}`, {
306
+ name: updatedName
307
+ });
308
+ console.log(`Назву кампанії оновлено на: ${updatedName}`);
309
+ }
310
+ // Створюємо мапу для зберігання всіх унікальних потоків
311
+ const allUniqueStreams = new Map();
312
+ // Збираємо всі потоки з усіх кампаній
313
+ for (const campaign of allCampaigns) {
314
+ if (campaign.id === TARGET_CAMPAIGN_ID)
315
+ continue; // Пропускаємо цільову кампанію
316
+ console.log(`Обробка кампанії ${campaign.id} (${campaign.name})...`);
317
+ const streams = await getStreamsByCampaignId(campaign.id);
318
+ for (const stream of streams) {
319
+ // Пропускаємо потоки, які мають фільтр за країною, крім "Bot Protection"
320
+ if (stream.name !== "Bot Protection" &&
321
+ stream.filters && stream.filters.length > 0 &&
322
+ stream.filters.some(filter => filter.name === 'country')) {
323
+ console.log(`Пропущено потік: ${stream.name} (фільтр за країною)`);
324
+ continue;
325
+ }
326
+ // Визначаємо унікальний ключ для потоку
327
+ const streamKey = stream.filters && stream.filters.length > 0 &&
328
+ stream.filters[0].payload && stream.filters[0].payload.length > 0
329
+ ? `filter:${stream.filters[0].name}:${stream.filters[0].payload[0]}`
330
+ : `name:${stream.name}`;
331
+ if (!allUniqueStreams.has(streamKey)) {
332
+ allUniqueStreams.set(streamKey, stream);
333
+ console.log(`Знайдено унікальний потік: ${stream.name} (ключ: ${streamKey})`);
334
+ }
335
+ }
336
+ }
337
+ console.log(`Знайдено ${allUniqueStreams.size} унікальних потоків`);
338
+ // Отримуємо існуючі потоки цільової кампанії
339
+ const existingStreams = await getStreamsByCampaignId(TARGET_CAMPAIGN_ID);
340
+ // Створюємо множину існуючих ключів потоків
341
+ const existingStreamKeys = new Set();
342
+ for (const stream of existingStreams) {
343
+ const streamKey = stream.filters && stream.filters.length > 0 &&
344
+ stream.filters[0].payload && stream.filters[0].payload.length > 0
345
+ ? `filter:${stream.filters[0].name}:${stream.filters[0].payload[0]}`
346
+ : `name:${stream.name}`;
347
+ existingStreamKeys.add(streamKey);
348
+ }
349
+ console.log(`Кампанія "${targetCampaign.name}" вже має ${existingStreamKeys.size} потоків`);
350
+ // Додаємо відсутні потоки до цільової кампанії
351
+ let addedStreamsCount = 0;
352
+ let errorCount = 0;
353
+ let skippedCount = 0;
354
+ for (const [streamKey, sourceStream] of allUniqueStreams.entries()) {
355
+ if (!existingStreamKeys.has(streamKey)) {
356
+ try {
357
+ await http_1.default.post('streams', {
358
+ name: sourceStream.name,
359
+ campaign_id: TARGET_CAMPAIGN_ID,
360
+ schema: sourceStream.schema,
361
+ type: sourceStream.type,
362
+ action_type: sourceStream.action_type,
363
+ weight: sourceStream.weight,
364
+ offers: sourceStream.offers.map((offer) => ({
365
+ offer_id: offer.offer_id,
366
+ share: offer.share,
367
+ state: offer.state
368
+ })),
369
+ filters: sourceStream.filters.map((filter) => ({
370
+ name: filter.name,
371
+ mode: filter.mode,
372
+ payload: filter.payload
373
+ })),
374
+ position: sourceStream.position,
375
+ state: sourceStream.state
376
+ });
377
+ addedStreamsCount++;
378
+ console.log(`Додано потік ${addedStreamsCount}: ${sourceStream.name}`);
379
+ }
380
+ catch (error) {
381
+ errorCount++;
382
+ console.error(`Помилка при додаванні потоку "${sourceStream.name}":`, error);
383
+ }
384
+ }
385
+ else {
386
+ skippedCount++;
387
+ }
388
+ }
389
+ console.log(`Результат: додано ${addedStreamsCount} потоків, пропущено ${skippedCount}, помилок: ${errorCount}`);
390
+ console.log(`Всього потоків у кампанії "${targetCampaign.name}" тепер: ${existingStreamKeys.size + addedStreamsCount}`);
391
+ }
392
+ exports.addAllStreamsToMarkedCampaign = addAllStreamsToMarkedCampaign;
393
+ /**
394
+ * Вирівнює потоки між усіма кампаніями.
395
+ * Збирає всі унікальні потоки з усіх кампаній та додає відсутні потоки в кожну кампанію.
396
+ */
397
+ async function equalizeStreamsBetweenAllCampaigns() {
398
+ console.log(`Починаємо вирівнювання потоків між усіма кампаніями...`);
399
+ // Отримуємо всі кампанії
400
+ const allCampaigns = await getAllCampaigns();
401
+ console.log(`Знайдено ${allCampaigns.length} кампаній`);
402
+ // Створюємо мапу для зберігання всіх унікальних потоків з усіх кампаній
403
+ const allUniqueStreams = new Map();
404
+ // Збираємо всі унікальні потоки з усіх кампаній
405
+ console.log(`Збираємо всі унікальні потоки...`);
406
+ for (const campaign of allCampaigns) {
407
+ console.log(`Обробка кампанії ${campaign.id} (${campaign.name})...`);
408
+ const streams = await getStreamsByCampaignId(campaign.id);
409
+ for (const stream of streams) {
410
+ // Пропускаємо потоки, які мають фільтр за країною, крім "Bot Protection"
411
+ if (stream.name !== "Bot Protection" &&
412
+ stream.filters && stream.filters.length > 0 &&
413
+ stream.filters.some(filter => filter.name === 'country')) {
414
+ continue;
415
+ }
416
+ // Визначаємо унікальний ключ для потоку
417
+ const streamKey = stream.filters && stream.filters.length > 0 &&
418
+ stream.filters[0].payload && stream.filters[0].payload.length > 0
419
+ ? `filter:${stream.filters[0].name}:${stream.filters[0].payload[0]}`
420
+ : `name:${stream.name}`;
421
+ if (!allUniqueStreams.has(streamKey)) {
422
+ allUniqueStreams.set(streamKey, stream);
423
+ console.log(`Знайдено унікальний потік: ${stream.name} (ключ: ${streamKey})`);
424
+ }
425
+ }
426
+ }
427
+ console.log(`Знайдено всього ${allUniqueStreams.size} унікальних потоків`);
428
+ // Тепер вирівнюємо потоки для кожної кампанії
429
+ let totalAddedStreams = 0;
430
+ let totalErrorsCount = 0;
431
+ for (const targetCampaign of allCampaigns) {
432
+ console.log(`\nСинхронізація кампанії ${targetCampaign.id} (${targetCampaign.name})...`);
433
+ // Отримуємо потоки цільової кампанії
434
+ const existingStreams = await getStreamsByCampaignId(targetCampaign.id);
435
+ // Створюємо множину існуючих ключів потоків
436
+ const existingStreamKeys = new Set();
437
+ for (const stream of existingStreams) {
438
+ // Пропускаємо потоки, які мають фільтр за країною, крім "Bot Protection"
439
+ if (stream.name !== "Bot Protection" &&
440
+ stream.filters && stream.filters.length > 0 &&
441
+ stream.filters.some(filter => filter.name === 'country')) {
442
+ continue;
443
+ }
444
+ const streamKey = stream.filters && stream.filters.length > 0 &&
445
+ stream.filters[0].payload && stream.filters[0].payload.length > 0
446
+ ? `filter:${stream.filters[0].name}:${stream.filters[0].payload[0]}`
447
+ : `name:${stream.name}`;
448
+ existingStreamKeys.add(streamKey);
449
+ }
450
+ console.log(`Кампанія ${targetCampaign.id} (${targetCampaign.name}) має ${existingStreamKeys.size} потоків (без країн)`);
451
+ // Додаємо відсутні потоки до цільової кампанії
452
+ let addedStreamsCount = 0;
453
+ let errorCount = 0;
454
+ for (const [streamKey, sourceStream] of allUniqueStreams.entries()) {
455
+ if (!existingStreamKeys.has(streamKey)) {
456
+ try {
457
+ await http_1.default.post('streams', {
458
+ name: sourceStream.name,
459
+ campaign_id: targetCampaign.id,
460
+ schema: sourceStream.schema,
461
+ type: sourceStream.type,
462
+ action_type: sourceStream.action_type,
463
+ weight: sourceStream.weight,
464
+ offers: sourceStream.offers.map((offer) => ({
465
+ offer_id: offer.offer_id,
466
+ share: offer.share,
467
+ state: offer.state
468
+ })),
469
+ filters: sourceStream.filters.map((filter) => ({
470
+ name: filter.name,
471
+ mode: filter.mode,
472
+ payload: filter.payload
473
+ })),
474
+ position: sourceStream.position,
475
+ state: sourceStream.state
476
+ });
477
+ addedStreamsCount++;
478
+ totalAddedStreams++;
479
+ console.log(`Додано потік ${addedStreamsCount}: ${sourceStream.name}`);
480
+ }
481
+ catch (error) {
482
+ errorCount++;
483
+ totalErrorsCount++;
484
+ console.error(`Помилка при додаванні потоку "${sourceStream.name}" до кампанії ${targetCampaign.id} (${targetCampaign.name}):`, error);
485
+ }
486
+ }
487
+ }
488
+ console.log(`Додано ${addedStreamsCount} потоків до кампанії ${targetCampaign.id} (${targetCampaign.name}), помилок: ${errorCount}`);
489
+ }
490
+ console.log(`\nВирівнювання потоків завершено!`);
491
+ console.log(`Всього додано ${totalAddedStreams} потоків, помилок: ${totalErrorsCount}`);
492
+ }
493
+ exports.equalizeStreamsBetweenAllCampaigns = equalizeStreamsBetweenAllCampaigns;
494
+ // Експортуємо функції для використання в інших модулях
495
+ exports.KeitaroStreamsService = {
496
+ addAllStreamsToTestCampaign,
497
+ addAllStreamsToCampaign,
498
+ synchronizeStreamsAcrossAllCampaigns,
499
+ addAllStreamsToMarkedCampaign,
500
+ equalizeStreamsBetweenAllCampaigns
501
+ };
502
+ // Викликаємо функцію для тестування
503
+ // Цей код буде виконано при імпорті цього модуля
504
+ // addAllStreamsToMarkedCampaign()
505
+ // .then(() => console.log('Функцію addAllStreamsToMarkedCampaign успішно виконано'))
506
+ // .catch(err => console.error('Помилка при виконанні addAllStreamsToMarkedCampaign:', err));
507
+ // Запускаємо вирівнювання потоків між усіма кампаніями
508
+ equalizeStreamsBetweenAllCampaigns()
509
+ .then(() => console.log('Вирівнювання потоків між усіма кампаніями успішно завершено'))
510
+ .catch(err => console.error('Помилка при вирівнюванні потоків:', err));
@@ -23,6 +23,7 @@ declare function createCampaign(campaignData: Partial<IKeitaroCampaign>): Promis
23
23
  declare function getCampaignById(id: number): Promise<IKeitaroCampaign>;
24
24
  export declare function upsertStreamToCampaign(campaign: IKeitaroCampaign, stream: Partial<IKeitaroStream>): Promise<void>;
25
25
  declare function cloneOWCampaign(app: IApp, platform?: EPlatform): Promise<IKeitaroCampaign | any>;
26
+ declare function cloneDirectCampaign(app: IApp, platform?: EPlatform): Promise<IKeitaroCampaign | any>;
26
27
  declare function cloneDCampaign(app: IApp): Promise<IKeitaroCampaign>;
27
28
  declare function changeCampaignsGroup(fromId: number, toId: number, exceptForCampaignIds: number[], onlyForCampaignIds?: number[]): Promise<void>;
28
29
  declare function getDomains(onlyActive?: boolean): Promise<IKeitaroDomain[]>;
@@ -49,5 +50,6 @@ export declare const KeitaroService: {
49
50
  cloneDCampaign: typeof cloneDCampaign;
50
51
  findKeitaroOffers: typeof findKeitaroOffers;
51
52
  fixBrokenClickCosts: typeof fixBrokenClickCosts;
53
+ cloneDirectCampaign: typeof cloneDirectCampaign;
52
54
  };
53
55
  export {};
@@ -272,6 +272,90 @@ async function cloneOWCampaign(app, platform) {
272
272
  const updatedCampaign = await getCampaignById(newCampaign.id);
273
273
  return updatedCampaign;
274
274
  }
275
+ async function cloneDirectCampaign(app, platform) {
276
+ let name = `#${app.id} [✦]`;
277
+ let platformName = platform ? (0, app_1.getPlatformName)(platform) : null;
278
+ const platformCampaignName = `#${app.id} [✦] (${platformName})`;
279
+ const generateAlias = () => {
280
+ const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
281
+ return Array.from({ length: 8 }, () => chars.charAt(Math.floor(Math.random() * chars.length))).join('');
282
+ };
283
+ let allCampaigns = await getAllCampaigns();
284
+ let matchingCampaign = [];
285
+ if (platform && platform !== app_1.EPlatform.GENERAL) {
286
+ // Шукаємо кампанію з платформою
287
+ matchingCampaign = allCampaigns.filter((c) => c.name.includes(`#${app.id}`) &&
288
+ c.name.includes(`[✦]`) &&
289
+ c.name.includes(`(${platformName})`));
290
+ }
291
+ else {
292
+ // Шукаємо кампанію без платформи або з суфіксом
293
+ matchingCampaign = allCampaigns.filter((c) => c.name.includes(`#${app.id}`) &&
294
+ c.name.includes(`[✦]`) &&
295
+ !c.name.includes('('));
296
+ }
297
+ if (matchingCampaign.length > 0)
298
+ return matchingCampaign[0];
299
+ const originalCampaign = await getCampaignById(3175);
300
+ const maxPosition = Math.max(...allCampaigns.map(c => c.position || 0));
301
+ const originalStreams = await getStreamsByCampaignId(3175);
302
+ let allDomains = await exports.KeitaroService.getDomains(true);
303
+ if (!allDomains) {
304
+ throw Error(`Failed to get all domains list`);
305
+ }
306
+ const domain = allDomains[Math.floor(Math.random() * allDomains.length)];
307
+ const maxGroupId = Math.max(...allCampaigns.map(c => c.group_id || 0));
308
+ let alias = generateAlias();
309
+ let payload = {
310
+ // Унікальні поля
311
+ name: platformName ? platformCampaignName : name,
312
+ alias: alias,
313
+ domain_id: domain.id,
314
+ position: [maxPosition + 100],
315
+ group_id: maxGroupId + 1,
316
+ traffic_source_id: keitaro_utils_1.TRAFFIC_SOURCE_ID_FLASH_AI,
317
+ parameters: (0, keitaro_utils_1.prepareOWCampaignParameters)(app),
318
+ // Неунікальні поля з оригінальної кампанії
319
+ type: originalCampaign.type,
320
+ state: originalCampaign.state,
321
+ cost_type: originalCampaign.cost_type,
322
+ cost_value: originalCampaign.cost_value,
323
+ cost_currency: originalCampaign.cost_currency,
324
+ uniqueness_period: originalCampaign.uniqueness_period,
325
+ cookies_ttl: originalCampaign.cookies_ttl,
326
+ notes: originalCampaign.notes,
327
+ collect_clicks: originalCampaign.collect_clicks,
328
+ uniqueness_type: originalCampaign.uniqueness_type,
329
+ };
330
+ const newCampaign = await createCampaign(payload);
331
+ for (const stream of originalStreams) {
332
+ await http_1.default.post('streams', {
333
+ name: stream.name,
334
+ campaign_id: newCampaign.id,
335
+ schema: stream.schema,
336
+ type: stream.type,
337
+ action_type: stream.action_type,
338
+ weight: stream.weight,
339
+ offers: stream.offers.map((offer) => ({
340
+ offer_id: offer.offer_id,
341
+ share: offer.share,
342
+ state: offer.state
343
+ })),
344
+ filters: stream.filters.map((filter) => ({
345
+ name: filter.name,
346
+ mode: filter.mode,
347
+ payload: filter.payload
348
+ })),
349
+ position: stream.position,
350
+ state: stream.state
351
+ });
352
+ }
353
+ await http_1.default.put(`/campaigns/${newCampaign.id}`, {
354
+ group_id: originalCampaign.group_id
355
+ });
356
+ const updatedCampaign = await getCampaignById(newCampaign.id);
357
+ return updatedCampaign;
358
+ }
275
359
  async function cloneDCampaign(app) {
276
360
  let name = `D #${app.id} (${app.bundle})`;
277
361
  let allCampaigns = await getAllCampaigns();
@@ -364,5 +448,5 @@ exports.KeitaroService = {
364
448
  getStreamsByCampaignId, updateCampaign, getAllCampaigns, getAllOffers, cloneStreams, addOffersToKeitaro, getOfferByKeitaroId, getDomains, createCampaign, getCampaignById, upsertStreamToCampaign, cloneOWCampaign,
365
449
  updateOffer, changeCampaignsGroup, getProfitForTimeRange, getClicks,
366
450
  // getProfitForTodayAndYesterday,
367
- cloneDCampaign, findKeitaroOffers, fixBrokenClickCosts
451
+ cloneDCampaign, findKeitaroOffers, fixBrokenClickCosts, cloneDirectCampaign
368
452
  };
@@ -33,7 +33,8 @@ export declare enum PanelUserAccessScope {
33
33
  OFFERS_RW = 5,
34
34
  OFFERWALL_RO = 6,
35
35
  OFFERWALL_RW = 7,
36
- ASO_LOGS = 8
36
+ ASO_LOGS = 8,
37
+ MANAGER = 9
37
38
  }
38
39
  export interface IPanelUser extends Document {
39
40
  username: string;