@bprotsyk/aso-core 2.1.114 → 2.1.116
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/README-keitaro-clo-geos.md +131 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +3 -1
- package/lib/keitaro/keitaro-clo-geos.d.ts +40 -0
- package/lib/keitaro/keitaro-clo-geos.js +303 -0
- package/lib/network/keitaro/traffle/traffle-keitaro-service.d.ts +95 -0
- package/lib/network/keitaro/traffle/traffle-keitaro-service.js +251 -22
- package/lib/offers/list.d.ts +18 -18
- package/lib/templates/words.txt +212 -0
- package/package.json +3 -2
- package/src/index.ts +2 -1
- package/src/keitaro/keitaro-clo-geos.ts +371 -0
- package/src/network/keitaro/traffle/traffle-keitaro-service.ts +282 -24
- package/src/templates/words.txt +212 -0
- package/test-keitaro-clo-geos.js +93 -0
- package/test-keitaro.js +24 -6
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Keitaro CLO Geos Sync Service
|
|
2
|
+
|
|
3
|
+
Сервіс для синхронізації гео-даних між Keitaro CLO потоками та додатками платформи.
|
|
4
|
+
|
|
5
|
+
## Опис
|
|
6
|
+
|
|
7
|
+
Цей сервіс автоматично:
|
|
8
|
+
1. Отримує всі кампанії з Keitaro
|
|
9
|
+
2. Ідентифікує кампанії, які належать нашим додаткам
|
|
10
|
+
3. Порівнює гео з CLO потоків Keitaro з гео в додатках
|
|
11
|
+
4. Повертає список додатків, які потребують оновлення гео
|
|
12
|
+
|
|
13
|
+
## Основні функції
|
|
14
|
+
|
|
15
|
+
### `syncKeitaroCLOGeosWithApps(apps: IApp[])`
|
|
16
|
+
Основна функція синхронізації. Повертає загальний результат з усіма додатками та їх статусом.
|
|
17
|
+
|
|
18
|
+
### `getAppGeoSyncDetails(appId: number, platform: string, apps: IApp[])`
|
|
19
|
+
Отримує детальну інформацію про синхронізацію для конкретного додатку та платформи.
|
|
20
|
+
|
|
21
|
+
### `getAppsNeedingGeoUpdate(apps: IApp[])`
|
|
22
|
+
Повертає тільки список додатків, які потребують оновлення гео.
|
|
23
|
+
|
|
24
|
+
## Інтерфейси
|
|
25
|
+
|
|
26
|
+
### `IGeoSyncResult`
|
|
27
|
+
```typescript
|
|
28
|
+
interface IGeoSyncResult {
|
|
29
|
+
appId: number; // ID додатку
|
|
30
|
+
platform: string; // Платформа (@, hw, sm, rs, xm, ap, tg, am)
|
|
31
|
+
keitaroGeos: string[]; // Гео з Keitaro CLO потоку
|
|
32
|
+
appGeos: string[]; // Поточні гео в додатку
|
|
33
|
+
missingGeos: string[]; // Гео, які відсутні в додатку
|
|
34
|
+
needsUpdate: boolean; // Чи потребує додаток оновлення
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### `IGeoUpdateData`
|
|
39
|
+
```typescript
|
|
40
|
+
interface IGeoUpdateData {
|
|
41
|
+
appId: number; // ID додатку
|
|
42
|
+
platform: string; // Платформа
|
|
43
|
+
newGeos: string[]; // Нові гео (поточні + відсутні)
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### `IGeoSyncSummary`
|
|
48
|
+
```typescript
|
|
49
|
+
interface IGeoSyncSummary {
|
|
50
|
+
totalApps: number; // Загальна кількість додатків
|
|
51
|
+
appsNeedingUpdate: number; // Кількість додатків, що потребують оновлення
|
|
52
|
+
updates: IGeoUpdateData[]; // Список оновлень
|
|
53
|
+
errors: string[]; // Список помилок
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Використання
|
|
58
|
+
|
|
59
|
+
### Базовий приклад
|
|
60
|
+
```typescript
|
|
61
|
+
import { KeitaroCLOGeosService } from './keitaro/keitaro-clo-geos';
|
|
62
|
+
|
|
63
|
+
// Список ваших додатків
|
|
64
|
+
const apps = [/* ваші додатки */];
|
|
65
|
+
|
|
66
|
+
// Синхронізація всіх додатків
|
|
67
|
+
const summary = await KeitaroCLOGeosService.syncKeitaroCLOGeosWithApps(apps);
|
|
68
|
+
|
|
69
|
+
console.log(`Потребують оновлення: ${summary.appsNeedingUpdate}`);
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Отримання конкретного додатку
|
|
73
|
+
```typescript
|
|
74
|
+
// Деталі для додатку 1628 на платформі @
|
|
75
|
+
const details = await KeitaroCLOGeosService.getAppGeoSyncDetails(1628, '@', apps);
|
|
76
|
+
|
|
77
|
+
if (details?.needsUpdate) {
|
|
78
|
+
console.log(`Додаток ${details.appId} потребує оновлення гео`);
|
|
79
|
+
console.log(`Відсутні гео: ${details.missingGeos.join(', ')}`);
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Тільки додатки, що потребують оновлення
|
|
84
|
+
```typescript
|
|
85
|
+
const updates = await KeitaroCLOGeosService.getAppsNeedingGeoUpdate(apps);
|
|
86
|
+
|
|
87
|
+
updates.forEach(update => {
|
|
88
|
+
console.log(`Додаток ${update.appId} (${update.platform}): ${update.newGeos.join(', ')}`);
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Логіка ідентифікації кампаній
|
|
93
|
+
|
|
94
|
+
Сервіс ідентифікує кампанії як "наші" за наступними критеріями:
|
|
95
|
+
|
|
96
|
+
1. **ID додатку** в назві кампанії (наприклад: `#1628`, `[1628]`)
|
|
97
|
+
2. **Bundle ID** або **Domain** в назві кампанії
|
|
98
|
+
3. **Платформа** визначається за суфіксами:
|
|
99
|
+
- `(hw)` або `huawei` → `hw`
|
|
100
|
+
- `(sm)` або `samsung` → `sm`
|
|
101
|
+
- `(rs)` або `rustore` → `rs`
|
|
102
|
+
- `(xm)` або `xiaomi` → `xm`
|
|
103
|
+
- `(ap)` або `apkpure` → `ap`
|
|
104
|
+
- `(tg)` або `telegram` → `tg`
|
|
105
|
+
- `(am)` або `amazon` → `am`
|
|
106
|
+
- Без суфіксу → `@` (General)
|
|
107
|
+
|
|
108
|
+
## CLO потоки
|
|
109
|
+
|
|
110
|
+
Сервіс шукає CLO потоки в кампаніях та аналізує їх фільтри за країною. Гео беруться з фільтра `country` в `payload`.
|
|
111
|
+
|
|
112
|
+
## Тестування
|
|
113
|
+
|
|
114
|
+
Для тестування використовуйте файл `test-keitaro-clo-geos.js`:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
node test-keitaro-clo-geos.js
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Залежності
|
|
121
|
+
|
|
122
|
+
- `axios` - для HTTP запитів до Keitaro API
|
|
123
|
+
- `../network/keitaro/http` - конфігурація Keitaro API
|
|
124
|
+
- `../app/app` - інтерфейси додатків та платформ
|
|
125
|
+
|
|
126
|
+
## Примітки
|
|
127
|
+
|
|
128
|
+
- Сервіс автоматично обробляє помилки та логує їх
|
|
129
|
+
- Гео порівнюються без урахування регістру
|
|
130
|
+
- Повертаються тільки додатки, де гео Keitaro не співпадає з гео додатку
|
|
131
|
+
- Для кожного додатку формується масив нових гео (поточні + відсутні)
|
package/lib/index.d.ts
CHANGED
|
@@ -25,3 +25,4 @@ export { IDomain, IDomainSetupResult, DomainStatus, DomainTarget, CONST_CLOUFLAR
|
|
|
25
25
|
export { INamecheapDomain, INamecheapBuyRequest, INamecheapContactInfo, NamecheapBuyRequestSchema, INamecheapGetDomainsResult, INamecheapBuyResult } from "./general/namecheap-domain";
|
|
26
26
|
export { NginxTemplate } from "./templates/nginx-template";
|
|
27
27
|
export { TraffleKeitaroService } from "./network/keitaro/traffle/traffle-keitaro-service";
|
|
28
|
+
export { KeitaroCLOGeosService } from "./keitaro/keitaro-clo-geos";
|
package/lib/index.js
CHANGED
|
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.TraffleKeitaroService = exports.NginxTemplate = exports.NamecheapBuyRequestSchema = exports.getDomainTargetByIp = exports.CONST_CLOUFLARE_STATUS_READY = exports.DomainTarget = exports.DomainStatus = exports.ICloudflareDomainType = exports.ICloudflareDomainStatus = exports.KeitaroUtils = exports.KeitaroService = exports.ShapeDiv = exports.PanelUserSchema = exports.PanelUserAccessScope = exports.AlternativeOnActivityResult = exports.AlternativeOnBackPressed = exports.AlternativeNavigation = exports.AlternativeStorageType = exports.AlternativeNetworkTool = exports.AlternativeLogicType = exports.AlternativeSourceType = exports.AlternativeLayoutType = exports.AppType = exports.AppStatus = exports.EPlatform = exports.PlugType = exports.AppSchema = exports.IntegrationVersion = exports.SectionsListSchema = exports.DefaultSectionId = exports.OffersSectionSchema = exports.IOfferType = void 0;
|
|
26
|
+
exports.KeitaroCLOGeosService = exports.TraffleKeitaroService = exports.NginxTemplate = exports.NamecheapBuyRequestSchema = exports.getDomainTargetByIp = exports.CONST_CLOUFLARE_STATUS_READY = exports.DomainTarget = exports.DomainStatus = exports.ICloudflareDomainType = exports.ICloudflareDomainStatus = exports.KeitaroUtils = exports.KeitaroService = exports.ShapeDiv = exports.PanelUserSchema = exports.PanelUserAccessScope = exports.AlternativeOnActivityResult = exports.AlternativeOnBackPressed = exports.AlternativeNavigation = exports.AlternativeStorageType = exports.AlternativeNetworkTool = exports.AlternativeLogicType = exports.AlternativeSourceType = exports.AlternativeLayoutType = exports.AppType = exports.AppStatus = exports.EPlatform = exports.PlugType = exports.AppSchema = exports.IntegrationVersion = exports.SectionsListSchema = exports.DefaultSectionId = exports.OffersSectionSchema = exports.IOfferType = void 0;
|
|
27
27
|
var offer_1 = require("./offers/offer");
|
|
28
28
|
Object.defineProperty(exports, "IOfferType", { enumerable: true, get: function () { return offer_1.IOfferType; } });
|
|
29
29
|
var section_1 = require("./offers/section");
|
|
@@ -70,3 +70,5 @@ var nginx_template_1 = require("./templates/nginx-template");
|
|
|
70
70
|
Object.defineProperty(exports, "NginxTemplate", { enumerable: true, get: function () { return nginx_template_1.NginxTemplate; } });
|
|
71
71
|
var traffle_keitaro_service_1 = require("./network/keitaro/traffle/traffle-keitaro-service");
|
|
72
72
|
Object.defineProperty(exports, "TraffleKeitaroService", { enumerable: true, get: function () { return traffle_keitaro_service_1.TraffleKeitaroService; } });
|
|
73
|
+
var keitaro_clo_geos_1 = require("./keitaro/keitaro-clo-geos");
|
|
74
|
+
Object.defineProperty(exports, "KeitaroCLOGeosService", { enumerable: true, get: function () { return keitaro_clo_geos_1.KeitaroCLOGeosService; } });
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { IApp } from "../app/app";
|
|
2
|
+
export interface IGeoSyncResult {
|
|
3
|
+
appId: number;
|
|
4
|
+
platform: string;
|
|
5
|
+
keitaroGeos: string[];
|
|
6
|
+
appGeos: string[];
|
|
7
|
+
missingGeos: string[];
|
|
8
|
+
needsUpdate: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface IGeoUpdateData {
|
|
11
|
+
appId: number;
|
|
12
|
+
platform: string;
|
|
13
|
+
newGeos: string[];
|
|
14
|
+
}
|
|
15
|
+
export interface IGeoSyncSummary {
|
|
16
|
+
totalApps: number;
|
|
17
|
+
appsNeedingUpdate: number;
|
|
18
|
+
updates: IGeoUpdateData[];
|
|
19
|
+
errors: string[];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Основна функція синхронізації гео між Keitaro та додатками
|
|
23
|
+
*/
|
|
24
|
+
export declare function syncKeitaroCLOGeosWithApps(apps: IApp[]): Promise<IGeoSyncSummary>;
|
|
25
|
+
/**
|
|
26
|
+
* Отримує детальну інформацію про синхронізацію для конкретного додатку
|
|
27
|
+
*/
|
|
28
|
+
export declare function getAppGeoSyncDetails(appId: number, platform: string, apps: IApp[]): Promise<IGeoSyncResult | null>;
|
|
29
|
+
/**
|
|
30
|
+
* Отримує всі додатки, які потребують оновлення гео
|
|
31
|
+
*/
|
|
32
|
+
export declare function getAppsNeedingGeoUpdate(apps: IApp[]): Promise<IGeoUpdateData[]>;
|
|
33
|
+
/**
|
|
34
|
+
* Експортуємо основні функції
|
|
35
|
+
*/
|
|
36
|
+
export declare const KeitaroCLOGeosService: {
|
|
37
|
+
syncKeitaroCLOGeosWithApps: typeof syncKeitaroCLOGeosWithApps;
|
|
38
|
+
getAppGeoSyncDetails: typeof getAppGeoSyncDetails;
|
|
39
|
+
getAppsNeedingGeoUpdate: typeof getAppsNeedingGeoUpdate;
|
|
40
|
+
};
|
|
@@ -0,0 +1,303 @@
|
|
|
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.KeitaroCLOGeosService = exports.getAppsNeedingGeoUpdate = exports.getAppGeoSyncDetails = exports.syncKeitaroCLOGeosWithApps = void 0;
|
|
7
|
+
const http_1 = __importDefault(require("../network/keitaro/traffle/http"));
|
|
8
|
+
/**
|
|
9
|
+
* Отримує всі кампанії з Keitaro
|
|
10
|
+
*/
|
|
11
|
+
async function getAllKeitaroCampaigns() {
|
|
12
|
+
try {
|
|
13
|
+
const { data: campaigns } = await http_1.default.get('campaigns');
|
|
14
|
+
return campaigns;
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
console.error('Помилка отримання кампаній з Keitaro:', error);
|
|
18
|
+
throw error;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Отримує всі потоки для конкретної кампанії
|
|
23
|
+
*/
|
|
24
|
+
async function getStreamsByCampaignId(campaignId) {
|
|
25
|
+
try {
|
|
26
|
+
const { data: streams } = await http_1.default.get(`campaigns/${campaignId}/streams`);
|
|
27
|
+
return streams;
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
console.error(`Помилка отримання потоків для кампанії ${campaignId}:`, error);
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Отримує гео з CLO потоку кампанії
|
|
36
|
+
*/
|
|
37
|
+
async function getCLOGeosFromCampaign(campaignId) {
|
|
38
|
+
try {
|
|
39
|
+
const streams = await getStreamsByCampaignId(campaignId);
|
|
40
|
+
console.log(`Отримано ${streams.length} потоків для кампанії ${campaignId}`);
|
|
41
|
+
const cloStream = streams.find(stream => stream.name === "CLO");
|
|
42
|
+
if (!cloStream) {
|
|
43
|
+
console.log(`CLO потік не знайдено для кампанії ${campaignId}`);
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
console.log(`Знайдено CLO потік:`, {
|
|
47
|
+
id: cloStream.id,
|
|
48
|
+
name: cloStream.name,
|
|
49
|
+
filters: cloStream.filters
|
|
50
|
+
});
|
|
51
|
+
if (!cloStream.filters || cloStream.filters.length === 0) {
|
|
52
|
+
console.log(`CLO потік не має фільтрів для кампанії ${campaignId}`);
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
55
|
+
// Шукаємо фільтр за країною в CLO потоці
|
|
56
|
+
const countryFilter = cloStream.filters.find(filter => filter.name === "country");
|
|
57
|
+
if (!countryFilter) {
|
|
58
|
+
console.log(`Фільтр country не знайдено в CLO потоці кампанії ${campaignId}`);
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
console.log(`Знайдено фільтр country:`, countryFilter);
|
|
62
|
+
if (!countryFilter.payload || !Array.isArray(countryFilter.payload)) {
|
|
63
|
+
console.log(`Фільтр country не має payload або payload не є масивом для кампанії ${campaignId}`);
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
console.log(`Гео з CLO потоку кампанії ${campaignId}:`, countryFilter.payload);
|
|
67
|
+
return countryFilter.payload;
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
console.error(`Помилка отримання CLO гео для кампанії ${campaignId}:`, error);
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Визначає платформу за назвою кампанії
|
|
76
|
+
*/
|
|
77
|
+
function detectPlatformFromCampaignName(campaignName) {
|
|
78
|
+
const name = campaignName.toLowerCase();
|
|
79
|
+
if (name.includes('(hw)') || name.includes('huawei')) {
|
|
80
|
+
return 'hw';
|
|
81
|
+
}
|
|
82
|
+
else if (name.includes('(sm)') || name.includes('samsung')) {
|
|
83
|
+
return 'sm';
|
|
84
|
+
}
|
|
85
|
+
else if (name.includes('(rs)') || name.includes('rustore')) {
|
|
86
|
+
return 'rs';
|
|
87
|
+
}
|
|
88
|
+
else if (name.includes('(xm)') || name.includes('xiaomi')) {
|
|
89
|
+
return 'xm';
|
|
90
|
+
}
|
|
91
|
+
else if (name.includes('(ap)') || name.includes('apkpure')) {
|
|
92
|
+
return 'ap';
|
|
93
|
+
}
|
|
94
|
+
else if (name.includes('(tg)') || name.includes('telegram')) {
|
|
95
|
+
return 'tg';
|
|
96
|
+
}
|
|
97
|
+
else if (name.includes('(am)') || name.includes('amazon')) {
|
|
98
|
+
return 'am';
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
return '@'; // General platform
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Знаходить додаток за group кампанії
|
|
106
|
+
*/
|
|
107
|
+
function findAppByGroup(group, apps) {
|
|
108
|
+
const groupId = parseInt(group);
|
|
109
|
+
if (isNaN(groupId))
|
|
110
|
+
return null;
|
|
111
|
+
return apps.find(app => app.id === groupId) || null;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Основна функція синхронізації гео між Keitaro та додатками
|
|
115
|
+
*/
|
|
116
|
+
async function syncKeitaroCLOGeosWithApps(apps) {
|
|
117
|
+
console.log(`Починаємо синхронізацію гео для ${apps.length} додатків...`);
|
|
118
|
+
const summary = {
|
|
119
|
+
totalApps: apps.length,
|
|
120
|
+
appsNeedingUpdate: 0,
|
|
121
|
+
updates: [],
|
|
122
|
+
errors: []
|
|
123
|
+
};
|
|
124
|
+
try {
|
|
125
|
+
// Отримуємо всі кампанії з Keitaro
|
|
126
|
+
const allCampaigns = await getAllKeitaroCampaigns();
|
|
127
|
+
console.log(`Отримано ${allCampaigns.length} кампаній з Keitaro`);
|
|
128
|
+
// Діагностика: виводимо всі кампанії з group
|
|
129
|
+
console.log('\n=== Діагностика кампаній ===');
|
|
130
|
+
const campaignsWithGroup = allCampaigns.filter(c => c.group);
|
|
131
|
+
console.log(`Кампанії з group: ${campaignsWithGroup.length}`);
|
|
132
|
+
// Виводимо перші 10 кампаній з group для діагностики
|
|
133
|
+
campaignsWithGroup.slice(0, 10).forEach(campaign => {
|
|
134
|
+
console.log(` ID: ${campaign.id}, Group: "${campaign.group}", Name: "${campaign.name}"`);
|
|
135
|
+
});
|
|
136
|
+
if (campaignsWithGroup.length > 10) {
|
|
137
|
+
console.log(` ... та ще ${campaignsWithGroup.length - 10} кампаній`);
|
|
138
|
+
}
|
|
139
|
+
// Діагностика: шукаємо кампанії з нашими bundle
|
|
140
|
+
console.log('\n=== Пошук кампаній за bundle ===');
|
|
141
|
+
apps.forEach(app => {
|
|
142
|
+
const campaignsWithBundle = allCampaigns.filter(c => c.name.toLowerCase().includes(app.bundle.toLowerCase()));
|
|
143
|
+
console.log(`Кампанії з bundle "${app.bundle}": ${campaignsWithBundle.length}`);
|
|
144
|
+
campaignsWithBundle.forEach(campaign => {
|
|
145
|
+
console.log(` ID: ${campaign.id}, Group: "${campaign.group}", Name: "${campaign.name}"`);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
// Створюємо мапу додатків за ID для швидкого пошуку
|
|
149
|
+
const appsMap = new Map();
|
|
150
|
+
apps.forEach(app => appsMap.set(app.id, app));
|
|
151
|
+
console.log(`\nШукаємо додатки з ID: ${Array.from(appsMap.keys()).join(', ')}`);
|
|
152
|
+
// Фільтруємо кампанії, які мають group відповідний до наших додатків
|
|
153
|
+
const ourCampaigns = allCampaigns.filter(campaign => {
|
|
154
|
+
const hasGroup = campaign.group && appsMap.has(parseInt(campaign.group));
|
|
155
|
+
if (hasGroup) {
|
|
156
|
+
console.log(`✅ Знайдено нашу кампанію за group: ID=${campaign.id}, name="${campaign.name}", group="${campaign.group}"`);
|
|
157
|
+
}
|
|
158
|
+
return hasGroup;
|
|
159
|
+
});
|
|
160
|
+
// Додатково шукаємо кампанії за bundle в назві
|
|
161
|
+
const campaignsByBundle = allCampaigns.filter(campaign => {
|
|
162
|
+
return apps.some(app => campaign.name.toLowerCase().includes(app.bundle.toLowerCase()));
|
|
163
|
+
});
|
|
164
|
+
console.log(`\nЗнайдено ${campaignsByBundle.length} кампаній за bundle`);
|
|
165
|
+
campaignsByBundle.forEach(campaign => {
|
|
166
|
+
const matchingApp = apps.find(app => campaign.name.toLowerCase().includes(app.bundle.toLowerCase()));
|
|
167
|
+
if (matchingApp) {
|
|
168
|
+
console.log(`✅ Знайдено кампанію за bundle: ID=${campaign.id}, name="${campaign.name}", bundle="${matchingApp.bundle}"`);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
// Об'єднуємо результати
|
|
172
|
+
const allOurCampaigns = [...ourCampaigns, ...campaignsByBundle];
|
|
173
|
+
const uniqueCampaigns = allOurCampaigns.filter((campaign, index, self) => index === self.findIndex(c => c.id === campaign.id));
|
|
174
|
+
console.log(`\nВсього знайдено ${uniqueCampaigns.length} унікальних кампаній наших додатків`);
|
|
175
|
+
// Обробляємо кожну кампанію
|
|
176
|
+
for (const campaign of uniqueCampaigns) {
|
|
177
|
+
try {
|
|
178
|
+
const group = campaign.group;
|
|
179
|
+
if (!group)
|
|
180
|
+
continue;
|
|
181
|
+
const app = appsMap.get(parseInt(group));
|
|
182
|
+
if (!app) {
|
|
183
|
+
console.warn(`Додаток з ID ${group} не знайдено в списку додатків`);
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
console.log(`\nОбробляємо кампанію ${campaign.id} для додатку ${group}:`);
|
|
187
|
+
console.log(` Назва: ${campaign.name}`);
|
|
188
|
+
console.log(` Group: ${campaign.group}`);
|
|
189
|
+
// Визначаємо платформу за назвою кампанії
|
|
190
|
+
const platform = detectPlatformFromCampaignName(campaign.name);
|
|
191
|
+
console.log(` Визначена платформа: ${platform}`);
|
|
192
|
+
// Отримуємо гео з CLO потоку кампанії
|
|
193
|
+
console.log(` Отримуємо гео з CLO потоку...`);
|
|
194
|
+
const keitaroGeos = await getCLOGeosFromCampaign(campaign.id);
|
|
195
|
+
console.log(` Keitaro CLO гео: ${keitaroGeos.join(', ')}`);
|
|
196
|
+
// Отримуємо гео з додатку для конкретної платформи
|
|
197
|
+
const platformData = app.platforms[platform];
|
|
198
|
+
const appGeos = platformData?.geo || [];
|
|
199
|
+
console.log(` App гео для платформи ${platform}: ${appGeos.join(', ')}`);
|
|
200
|
+
// Порівнюємо гео
|
|
201
|
+
const missingGeos = keitaroGeos.filter(geo => !appGeos.includes(geo));
|
|
202
|
+
const needsUpdate = missingGeos.length > 0;
|
|
203
|
+
console.log(` Відсутні гео: ${missingGeos.join(', ')}`);
|
|
204
|
+
console.log(` Потребує оновлення: ${needsUpdate}`);
|
|
205
|
+
if (needsUpdate) {
|
|
206
|
+
summary.appsNeedingUpdate++;
|
|
207
|
+
const updateData = {
|
|
208
|
+
appId: parseInt(group),
|
|
209
|
+
platform: platform,
|
|
210
|
+
newGeos: [...appGeos, ...missingGeos]
|
|
211
|
+
};
|
|
212
|
+
summary.updates.push(updateData);
|
|
213
|
+
console.log(`✅ Додаток ${group} (${platform}) потребує оновлення гео:`);
|
|
214
|
+
console.log(` Кампанія: ${campaign.name}`);
|
|
215
|
+
console.log(` Keitaro гео: ${keitaroGeos.join(', ')}`);
|
|
216
|
+
console.log(` App гео: ${appGeos.join(', ')}`);
|
|
217
|
+
console.log(` Відсутні гео: ${missingGeos.join(', ')}`);
|
|
218
|
+
console.log(` Нові гео: ${updateData.newGeos.join(', ')}`);
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
console.log(`✅ Додаток ${group} (${platform}) не потребує оновлення гео`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
const errorMsg = `Помилка обробки кампанії ${campaign.id} (${campaign.name}): ${error}`;
|
|
226
|
+
console.error(errorMsg);
|
|
227
|
+
summary.errors.push(errorMsg);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
console.log(`\nСинхронізація завершена. ${summary.appsNeedingUpdate} додатків потребують оновлення гео.`);
|
|
231
|
+
}
|
|
232
|
+
catch (error) {
|
|
233
|
+
const errorMsg = `Критична помилка синхронізації: ${error}`;
|
|
234
|
+
console.error(errorMsg);
|
|
235
|
+
summary.errors.push(errorMsg);
|
|
236
|
+
}
|
|
237
|
+
return summary;
|
|
238
|
+
}
|
|
239
|
+
exports.syncKeitaroCLOGeosWithApps = syncKeitaroCLOGeosWithApps;
|
|
240
|
+
/**
|
|
241
|
+
* Отримує детальну інформацію про синхронізацію для конкретного додатку
|
|
242
|
+
*/
|
|
243
|
+
async function getAppGeoSyncDetails(appId, platform, apps) {
|
|
244
|
+
try {
|
|
245
|
+
const app = apps.find(a => a.id === appId);
|
|
246
|
+
if (!app) {
|
|
247
|
+
console.error(`Додаток з ID ${appId} не знайдено`);
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
const platformData = app.platforms[platform];
|
|
251
|
+
if (!platformData) {
|
|
252
|
+
console.error(`Платформа ${platform} не знайдена для додатку ${appId}`);
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
// Отримуємо всі кампанії та шукаємо нашу за group
|
|
256
|
+
const allCampaigns = await getAllKeitaroCampaigns();
|
|
257
|
+
const ourCampaign = allCampaigns.find(campaign => campaign.group === appId.toString());
|
|
258
|
+
if (!ourCampaign) {
|
|
259
|
+
console.error(`Кампанія для додатку ${appId} (group: ${appId}) не знайдена в Keitaro`);
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
console.log(`Знайдено кампанію для додатку ${appId}:`, {
|
|
263
|
+
id: ourCampaign.id,
|
|
264
|
+
name: ourCampaign.name,
|
|
265
|
+
group: ourCampaign.group
|
|
266
|
+
});
|
|
267
|
+
// Отримуємо гео з CLO потоку
|
|
268
|
+
const keitaroGeos = await getCLOGeosFromCampaign(ourCampaign.id);
|
|
269
|
+
const appGeos = platformData.geo || [];
|
|
270
|
+
// Порівнюємо гео
|
|
271
|
+
const missingGeos = keitaroGeos.filter(geo => !appGeos.includes(geo));
|
|
272
|
+
const needsUpdate = missingGeos.length > 0;
|
|
273
|
+
return {
|
|
274
|
+
appId,
|
|
275
|
+
platform,
|
|
276
|
+
keitaroGeos,
|
|
277
|
+
appGeos,
|
|
278
|
+
missingGeos,
|
|
279
|
+
needsUpdate
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
catch (error) {
|
|
283
|
+
console.error(`Помилка отримання деталей синхронізації для додатку ${appId}:`, error);
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
exports.getAppGeoSyncDetails = getAppGeoSyncDetails;
|
|
288
|
+
/**
|
|
289
|
+
* Отримує всі додатки, які потребують оновлення гео
|
|
290
|
+
*/
|
|
291
|
+
async function getAppsNeedingGeoUpdate(apps) {
|
|
292
|
+
const summary = await syncKeitaroCLOGeosWithApps(apps);
|
|
293
|
+
return summary.updates;
|
|
294
|
+
}
|
|
295
|
+
exports.getAppsNeedingGeoUpdate = getAppsNeedingGeoUpdate;
|
|
296
|
+
/**
|
|
297
|
+
* Експортуємо основні функції
|
|
298
|
+
*/
|
|
299
|
+
exports.KeitaroCLOGeosService = {
|
|
300
|
+
syncKeitaroCLOGeosWithApps,
|
|
301
|
+
getAppGeoSyncDetails,
|
|
302
|
+
getAppsNeedingGeoUpdate
|
|
303
|
+
};
|
|
@@ -37,6 +37,100 @@ declare function getTraffleAffiliateNetworks(): Promise<IAffiliateNetwork[]>;
|
|
|
37
37
|
declare function deleteOfferById(id: number): Promise<any>;
|
|
38
38
|
declare function addOffersToTraffleKeitaro(offers: ITraffleOffer[]): Promise<void>;
|
|
39
39
|
declare function updateOfferLinkById(id: number, action_payload: string | object): Promise<any>;
|
|
40
|
+
declare function TrafleKeitaroParameters(parameters: any): Promise<{
|
|
41
|
+
parameters: {
|
|
42
|
+
keyword: {
|
|
43
|
+
name: string;
|
|
44
|
+
placeholder: string;
|
|
45
|
+
alias: string;
|
|
46
|
+
};
|
|
47
|
+
cost: {
|
|
48
|
+
name: string;
|
|
49
|
+
placeholder: string;
|
|
50
|
+
alias: string;
|
|
51
|
+
};
|
|
52
|
+
currency: {
|
|
53
|
+
name: string;
|
|
54
|
+
placeholder: string;
|
|
55
|
+
alias: string;
|
|
56
|
+
};
|
|
57
|
+
external_id: {
|
|
58
|
+
name: string;
|
|
59
|
+
placeholder: string;
|
|
60
|
+
alias: string;
|
|
61
|
+
};
|
|
62
|
+
creative_id: {
|
|
63
|
+
name: string;
|
|
64
|
+
placeholder: string;
|
|
65
|
+
alias: string;
|
|
66
|
+
};
|
|
67
|
+
ad_campaign_id: {
|
|
68
|
+
name: string;
|
|
69
|
+
placeholder: string;
|
|
70
|
+
alias: string;
|
|
71
|
+
};
|
|
72
|
+
source: {
|
|
73
|
+
name: string;
|
|
74
|
+
placeholder: string;
|
|
75
|
+
alias: string;
|
|
76
|
+
};
|
|
77
|
+
sub_id_1: {
|
|
78
|
+
name: string;
|
|
79
|
+
placeholder: string;
|
|
80
|
+
alias: string;
|
|
81
|
+
};
|
|
82
|
+
sub_id_2: {
|
|
83
|
+
name: string;
|
|
84
|
+
placeholder: string;
|
|
85
|
+
alias: string;
|
|
86
|
+
};
|
|
87
|
+
sub_id_3: {
|
|
88
|
+
name: string;
|
|
89
|
+
placeholder: string;
|
|
90
|
+
alias: string;
|
|
91
|
+
};
|
|
92
|
+
sub_id_4: {
|
|
93
|
+
name: string;
|
|
94
|
+
placeholder: string;
|
|
95
|
+
alias: string;
|
|
96
|
+
};
|
|
97
|
+
sub_id_5: {
|
|
98
|
+
name: string;
|
|
99
|
+
placeholder: string;
|
|
100
|
+
alias: string;
|
|
101
|
+
};
|
|
102
|
+
sub_id_10: {
|
|
103
|
+
name: string;
|
|
104
|
+
placeholder: string;
|
|
105
|
+
alias: string;
|
|
106
|
+
};
|
|
107
|
+
sub_id_15: {
|
|
108
|
+
name: string;
|
|
109
|
+
placeholder: string;
|
|
110
|
+
alias: string;
|
|
111
|
+
};
|
|
112
|
+
sub_id_16: {
|
|
113
|
+
name: string;
|
|
114
|
+
placeholder: any;
|
|
115
|
+
alias: string;
|
|
116
|
+
};
|
|
117
|
+
sub_id_17: {
|
|
118
|
+
name: string;
|
|
119
|
+
placeholder: string;
|
|
120
|
+
alias: string;
|
|
121
|
+
};
|
|
122
|
+
sub_id_18: {
|
|
123
|
+
name: string;
|
|
124
|
+
placeholder: string;
|
|
125
|
+
alias: string;
|
|
126
|
+
};
|
|
127
|
+
sub_id_19: {
|
|
128
|
+
name: string;
|
|
129
|
+
placeholder: any;
|
|
130
|
+
alias: string;
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
} | null>;
|
|
40
134
|
declare function cloneTraffleCampaign(app: IApp, platform: EPlatform, addDefaultStreams?: boolean): Promise<IKeitaroCampaign | any>;
|
|
41
135
|
export declare const TraffleKeitaroService: {
|
|
42
136
|
addOffersToTraffleKeitaro: typeof addOffersToTraffleKeitaro;
|
|
@@ -47,5 +141,6 @@ export declare const TraffleKeitaroService: {
|
|
|
47
141
|
getAllOffers: typeof getAllOffers;
|
|
48
142
|
updateOfferLinkById: typeof updateOfferLinkById;
|
|
49
143
|
cloneTraffleCampaign: typeof cloneTraffleCampaign;
|
|
144
|
+
TrafleKeitaroParameters: typeof TrafleKeitaroParameters;
|
|
50
145
|
};
|
|
51
146
|
export {};
|