@bprotsyk/aso-core 2.1.223 → 2.1.225
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/lib/app/app.d.ts +237 -362
- package/lib/app/app.js +93 -175
- package/lib/general/cloudflare-domain.d.ts +1 -0
- package/lib/general/domain.d.ts +82 -0
- package/lib/general/domain.js +5 -0
- package/lib/index.d.ts +5 -2
- package/lib/index.js +21 -17
- package/lib/keitaro/keitaro-campaign.d.ts +0 -1
- package/lib/keitaro/keitaro-offer.d.ts +3 -14
- package/lib/network/keitaro/http.js +1 -1
- package/lib/network/keitaro/keitaro-service.d.ts +37 -51
- package/lib/network/keitaro/keitaro-service.js +442 -192
- package/lib/offers/list.d.ts +18 -18
- package/lib/offers/offer.d.ts +4 -0
- package/lib/offers/offer.js +1 -0
- package/lib/panel/app/upsert-flash-app-request.d.ts +14 -14
- package/lib/server/server.d.ts +140 -0
- package/lib/server/server.js +36 -0
- package/lib/utils/keitaro-utils.d.ts +1 -1
- package/lib/utils/keitaro-utils.js +9 -722
- package/package.json +1 -1
- package/src/app/app.ts +316 -307
- package/src/general/cloudflare-domain.ts +1 -0
- package/src/general/domain.ts +8 -0
- package/src/index.ts +27 -30
- package/src/keitaro/keitaro-campaign.ts +0 -1
- package/src/keitaro/keitaro-offer.ts +3 -14
- package/src/network/keitaro/http.ts +1 -1
- package/src/network/keitaro/keitaro-service.ts +533 -232
- package/src/offers/offer.ts +2 -0
- package/src/panel/app/upsert-flash-app-request.ts +48 -0
- package/src/server/server.ts +57 -0
- package/src/utils/keitaro-utils.ts +24 -0
|
@@ -3,13 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.KeitaroService = void 0;
|
|
6
|
+
exports.KeitaroService = exports.upsertStreamToCampaign = void 0;
|
|
7
7
|
const http_1 = __importDefault(require("./http"));
|
|
8
8
|
const app_1 = require("../../app/app");
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
const DEFAULT_CAMPAIGNS_GROUP_ID = 106;
|
|
12
|
-
// Basic campaign operations
|
|
9
|
+
const keitaro_utils_1 = require("../../utils/keitaro-utils");
|
|
10
|
+
const general_1 = require("../../utils/general");
|
|
13
11
|
async function getStreamsByCampaignId(campaignId) {
|
|
14
12
|
const { data: streams } = await http_1.default.get(`campaigns/${campaignId}/streams`);
|
|
15
13
|
return streams;
|
|
@@ -18,175 +16,239 @@ async function getAllCampaigns() {
|
|
|
18
16
|
const { data: campaigns } = await http_1.default.get('campaigns');
|
|
19
17
|
return campaigns;
|
|
20
18
|
}
|
|
21
|
-
async function
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
async function cloneStreams(originalCampaignId, streamPositionsToClone, campaignRegExp) {
|
|
20
|
+
// Get the original campaign's streams
|
|
21
|
+
const originalStreams = await getStreamsByCampaignId(originalCampaignId);
|
|
22
|
+
// Filter the original streams by the given stream positions to clone
|
|
23
|
+
const streamsToClone = originalStreams.filter(stream => streamPositionsToClone.includes(stream.position));
|
|
24
|
+
// Get a list of all campaigns
|
|
25
|
+
const allCampaigns = await getAllCampaigns();
|
|
26
|
+
// Filter the campaigns by the given RegExp
|
|
27
|
+
const matchingCampaigns = allCampaigns.filter(campaign => campaignRegExp.exec(campaign.name) && campaign.id != originalCampaignId);
|
|
28
|
+
// console.log(matchingCampaigns)
|
|
29
|
+
// For each matching campaign, clone the streams
|
|
30
|
+
for (const matchingCampaign of matchingCampaigns) {
|
|
31
|
+
for (const streamToClone of streamsToClone) {
|
|
32
|
+
await http_1.default.post('streams', {
|
|
33
|
+
name: streamToClone.name,
|
|
34
|
+
campaign_id: matchingCampaign.id,
|
|
35
|
+
schema: streamToClone.schema,
|
|
36
|
+
type: streamToClone.type,
|
|
37
|
+
action_type: streamToClone.action_type,
|
|
38
|
+
weight: 100,
|
|
39
|
+
offers: streamToClone.offers.map((offer) => {
|
|
40
|
+
return {
|
|
41
|
+
offer_id: offer.offer_id,
|
|
42
|
+
share: 100
|
|
43
|
+
};
|
|
44
|
+
}),
|
|
45
|
+
filters: streamToClone.filters.map((filter) => {
|
|
46
|
+
return {
|
|
47
|
+
name: filter.name,
|
|
48
|
+
mode: filter.mode,
|
|
49
|
+
payload: filter.payload
|
|
50
|
+
};
|
|
51
|
+
}),
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
24
55
|
}
|
|
25
56
|
async function updateCampaign(id, payload) {
|
|
26
57
|
await http_1.default.put(`campaigns/${id}`, payload);
|
|
27
58
|
}
|
|
28
|
-
async function
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const
|
|
35
|
-
|
|
59
|
+
async function createStreamForMatchingCampaigns(streamPayloads, campaignRegExp, avoidGroup) {
|
|
60
|
+
// Get all campaigns once
|
|
61
|
+
const allCampaigns = await getAllCampaigns();
|
|
62
|
+
const matchingCampaigns = allCampaigns.filter(campaign => (avoidGroup ? campaign.group_id != avoidGroup : true) &&
|
|
63
|
+
campaignRegExp.exec(campaign.name));
|
|
64
|
+
// Get all streams for matching campaigns once
|
|
65
|
+
const campaignStreams = new Map();
|
|
66
|
+
for (const campaign of matchingCampaigns) {
|
|
67
|
+
campaignStreams.set(campaign.id, await getStreamsByCampaignId(campaign.id));
|
|
68
|
+
}
|
|
69
|
+
// Process each campaign
|
|
70
|
+
for (const matchingCampaign of matchingCampaigns) {
|
|
71
|
+
const streams = campaignStreams.get(matchingCampaign.id) || [];
|
|
72
|
+
// Process each stream payload
|
|
73
|
+
for (const { payload, offerId } of streamPayloads) {
|
|
74
|
+
const identicalStream = streams.find(stream => stream.name.includes(offerId));
|
|
75
|
+
try {
|
|
76
|
+
if (identicalStream) {
|
|
77
|
+
await http_1.default.put(`streams/${identicalStream.id}`, {
|
|
78
|
+
campaign_id: matchingCampaign.id,
|
|
79
|
+
...payload
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
await http_1.default.post('streams', {
|
|
84
|
+
campaign_id: matchingCampaign.id,
|
|
85
|
+
...payload
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
console.error(`Error updating stream ${offerId} (${payload.name}) in campaign ${matchingCampaign.id} (${matchingCampaign.name}):`, error);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
36
94
|
}
|
|
37
|
-
// Offer operations
|
|
38
95
|
async function getAllOffers() {
|
|
39
96
|
const { data: offers } = await http_1.default.get('offers');
|
|
40
97
|
return offers;
|
|
41
98
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
action_type: 'http',
|
|
52
|
-
action_payload: offer.link,
|
|
53
|
-
affiliate_network_id: 0,
|
|
54
|
-
payout_value: 0,
|
|
55
|
-
payout_currency: 'USD',
|
|
56
|
-
payout_type: 'CPA',
|
|
57
|
-
state: offer.hidden ? 'disabled' : 'active',
|
|
58
|
-
country: [offer.geo],
|
|
59
|
-
offer_type: 'external',
|
|
60
|
-
payout_auto: true,
|
|
61
|
-
payout_upsell: true,
|
|
62
|
-
};
|
|
63
|
-
const { data: keitaroOffer } = await http_1.default.post('offers', payload);
|
|
64
|
-
return keitaroOffer;
|
|
99
|
+
async function findKeitaroOffers(filter) {
|
|
100
|
+
let offers = await getAllOffers();
|
|
101
|
+
if (filter.caption)
|
|
102
|
+
offers = offers.filter((o) => o.name.includes(filter.caption));
|
|
103
|
+
if (filter.keitaroId)
|
|
104
|
+
offers = offers.filter((o) => o.id == filter.keitaroId);
|
|
105
|
+
if (filter.name)
|
|
106
|
+
offers = offers.filter((o) => o.name.includes(filter.name));
|
|
107
|
+
return offers;
|
|
65
108
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
...streamData,
|
|
70
|
-
campaign_id: campaignId
|
|
71
|
-
});
|
|
72
|
-
return stream;
|
|
109
|
+
async function getOfferByKeitaroId(id) {
|
|
110
|
+
const { data: offer } = await http_1.default.get(`offers/${id}`);
|
|
111
|
+
return offer;
|
|
73
112
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
async function getOfferwallCampaigns() {
|
|
78
|
-
const allCampaigns = await getAllCampaigns();
|
|
79
|
-
// Offerwall campaigns have [◈] in their name and are in group 106
|
|
80
|
-
return allCampaigns.filter(c => c.name.includes('[◈]') && c.group_id === DEFAULT_CAMPAIGNS_GROUP_ID);
|
|
113
|
+
async function updateOffer(offer) {
|
|
114
|
+
const { data: o } = await http_1.default.put(`offers/${offer.id}`, offer);
|
|
115
|
+
return o;
|
|
81
116
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
state: offer.hidden ? 'disabled' : 'active',
|
|
112
|
-
offers: [{
|
|
113
|
-
offer_id: keitaroOffer.id,
|
|
114
|
-
share: 100,
|
|
115
|
-
state: 'active'
|
|
116
|
-
}],
|
|
117
|
-
filters: [{
|
|
118
|
-
name: 'country',
|
|
119
|
-
mode: 'accept',
|
|
120
|
-
payload: [offer.geo]
|
|
121
|
-
}]
|
|
122
|
-
});
|
|
123
|
-
success++;
|
|
124
|
-
campaignNames.push(campaign.name);
|
|
117
|
+
function createStreamPartialPayload(keitaroOfferId, offerName, offerId, offerGeo) {
|
|
118
|
+
return {
|
|
119
|
+
name: `${offerName} ${offerGeo} (${offerId})`,
|
|
120
|
+
schema: "landings",
|
|
121
|
+
type: "regular",
|
|
122
|
+
action_type: "http",
|
|
123
|
+
weight: 100,
|
|
124
|
+
offers: [{
|
|
125
|
+
offer_id: keitaroOfferId,
|
|
126
|
+
share: 100,
|
|
127
|
+
state: "active"
|
|
128
|
+
}],
|
|
129
|
+
filters: [{
|
|
130
|
+
name: "sub_id_15",
|
|
131
|
+
mode: "accept",
|
|
132
|
+
payload: [offerId]
|
|
133
|
+
}],
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
async function addOffersToKeitaro(offers, affiliateId, links, avoidGroup, groupId) {
|
|
137
|
+
const allOffers = await getAllOffers();
|
|
138
|
+
const streamPayloads = [];
|
|
139
|
+
for (let i = 0; i < offers.length; i++) {
|
|
140
|
+
const offer = offers[i];
|
|
141
|
+
const link = links[i];
|
|
142
|
+
const identicalOffer = allOffers.find(o => o.name.includes(offer.name));
|
|
143
|
+
let keitaroOfferId;
|
|
144
|
+
if (identicalOffer) {
|
|
145
|
+
keitaroOfferId = identicalOffer.id;
|
|
125
146
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
147
|
+
else {
|
|
148
|
+
const offerPayload = {
|
|
149
|
+
name: `${offer.caption} ${offer.geo} (${offer.name})`,
|
|
150
|
+
group_id: groupId || 1,
|
|
151
|
+
action_payload: link,
|
|
152
|
+
affiliate_network_id: affiliateId,
|
|
153
|
+
country: [offer.geo],
|
|
154
|
+
action_type: "http",
|
|
155
|
+
offer_type: "external",
|
|
156
|
+
payout_auto: true,
|
|
157
|
+
payout_upsell: true,
|
|
158
|
+
};
|
|
159
|
+
const { data: keitaroOffer } = await http_1.default.post('offers', offerPayload);
|
|
160
|
+
keitaroOfferId = keitaroOffer.id;
|
|
129
161
|
}
|
|
162
|
+
streamPayloads.push({
|
|
163
|
+
payload: createStreamPartialPayload(keitaroOfferId, offer.caption, offer.name, offer.geo),
|
|
164
|
+
offerId: offer.name
|
|
165
|
+
});
|
|
130
166
|
}
|
|
131
|
-
|
|
167
|
+
await createStreamForMatchingCampaigns(streamPayloads, /◈/, avoidGroup);
|
|
168
|
+
}
|
|
169
|
+
async function createCampaign(campaignData) {
|
|
170
|
+
let { data: campaign } = await http_1.default.post(`/campaigns`, campaignData);
|
|
171
|
+
return campaign;
|
|
132
172
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
return Array.from({ length: 8 }, () => chars.charAt(Math.floor(Math.random() * chars.length))).join('');
|
|
173
|
+
async function getCampaignById(id) {
|
|
174
|
+
const { data: campaign } = await http_1.default.get(`/campaigns/${id}`);
|
|
175
|
+
return campaign;
|
|
137
176
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
: app_1.DIRECT_TEMPLATE_CAMPAIGN_ID;
|
|
148
|
-
const campaignPrefix = integrationType === app_1.IntegrationType.OFFERWALL ? '[◈]' : '[➥]';
|
|
149
|
-
const campaignName = `#${app.id} ${campaignPrefix} ${app.name || app.bundle}`;
|
|
150
|
-
// Check if campaign already exists
|
|
151
|
-
const allCampaigns = await getAllCampaigns();
|
|
152
|
-
const existingCampaign = allCampaigns.find(c => c.name.includes(`#${app.id}`) && c.name.includes(campaignPrefix));
|
|
153
|
-
if (existingCampaign) {
|
|
154
|
-
return campaignToKeitaroData(existingCampaign);
|
|
177
|
+
async function upsertStreamToCampaign(campaign, stream) {
|
|
178
|
+
let streams = await getStreamsByCampaignId(campaign.id);
|
|
179
|
+
let identicalStream = streams.find((s) => stream.name == s.name);
|
|
180
|
+
if (identicalStream) {
|
|
181
|
+
console.log(`Found identical! Name: ${stream.name}`);
|
|
182
|
+
await http_1.default.put(`streams/${identicalStream.id}`, {
|
|
183
|
+
campaign_id: campaign.id,
|
|
184
|
+
...stream
|
|
185
|
+
});
|
|
155
186
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
if (!allDomains || allDomains.length === 0) {
|
|
162
|
-
throw new Error('No active domains available');
|
|
187
|
+
else {
|
|
188
|
+
await http_1.default.post('streams', {
|
|
189
|
+
campaign_id: campaign.id,
|
|
190
|
+
...stream
|
|
191
|
+
});
|
|
163
192
|
}
|
|
164
|
-
|
|
165
|
-
|
|
193
|
+
}
|
|
194
|
+
exports.upsertStreamToCampaign = upsertStreamToCampaign;
|
|
195
|
+
async function cloneOWCampaign(app, platform) {
|
|
196
|
+
let name = `#${app.id} [◈]`;
|
|
197
|
+
let platformName = platform ? (0, app_1.getPlatformName)(platform) : null;
|
|
198
|
+
const platformCampaignName = `#${app.id} [◈] (${platformName})`;
|
|
199
|
+
const generateAlias = () => {
|
|
200
|
+
const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
|
201
|
+
return Array.from({ length: 8 }, () => chars.charAt(Math.floor(Math.random() * chars.length))).join('');
|
|
202
|
+
};
|
|
203
|
+
let allCampaigns = await getAllCampaigns();
|
|
204
|
+
let matchingCampaign = [];
|
|
205
|
+
if (platform && platform !== app_1.EPlatform.GENERAL) {
|
|
206
|
+
// Шукаємо кампанію з платформою
|
|
207
|
+
matchingCampaign = allCampaigns.filter((c) => c.name.includes(`#${app.id}`) &&
|
|
208
|
+
c.name.includes(`[◈]`) &&
|
|
209
|
+
c.name.includes(`(${platformName})`));
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
// Шукаємо кампанію без платформи або з суфіксом
|
|
213
|
+
matchingCampaign = allCampaigns.filter((c) => c.name.includes(`#${app.id}`) &&
|
|
214
|
+
c.name.includes(`[◈]`) &&
|
|
215
|
+
!c.name.includes('('));
|
|
216
|
+
}
|
|
217
|
+
if (matchingCampaign.length > 0)
|
|
218
|
+
return matchingCampaign[0];
|
|
219
|
+
const originalCampaign = await getCampaignById(2673);
|
|
166
220
|
const maxPosition = Math.max(...allCampaigns.map(c => c.position || 0));
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
221
|
+
const originalStreams = await getStreamsByCampaignId(2673);
|
|
222
|
+
let allDomains = await exports.KeitaroService.getDomains(true);
|
|
223
|
+
if (!allDomains) {
|
|
224
|
+
throw Error(`Failed to get all domains list`);
|
|
225
|
+
}
|
|
226
|
+
const domain = allDomains[Math.floor(Math.random() * allDomains.length)];
|
|
227
|
+
const maxGroupId = Math.max(...allCampaigns.map(c => c.group_id || 0));
|
|
228
|
+
let alias = generateAlias();
|
|
229
|
+
let payload = {
|
|
230
|
+
// Унікальні поля
|
|
231
|
+
name: platformName ? platformCampaignName : name,
|
|
170
232
|
alias: alias,
|
|
171
233
|
domain_id: domain.id,
|
|
172
234
|
position: [maxPosition + 100],
|
|
173
|
-
group_id:
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
235
|
+
group_id: maxGroupId + 1,
|
|
236
|
+
traffic_source_id: keitaro_utils_1.TRAFFIC_SOURCE_ID_FLASH_AI,
|
|
237
|
+
parameters: (0, keitaro_utils_1.prepareOWCampaignParameters)(app),
|
|
238
|
+
// Неунікальні поля з оригінальної кампанії
|
|
239
|
+
type: originalCampaign.type,
|
|
240
|
+
state: originalCampaign.state,
|
|
241
|
+
cost_type: originalCampaign.cost_type,
|
|
242
|
+
cost_value: originalCampaign.cost_value,
|
|
243
|
+
cost_currency: originalCampaign.cost_currency,
|
|
244
|
+
uniqueness_period: originalCampaign.uniqueness_period,
|
|
245
|
+
cookies_ttl: originalCampaign.cookies_ttl,
|
|
246
|
+
notes: originalCampaign.notes,
|
|
247
|
+
collect_clicks: originalCampaign.collect_clicks,
|
|
248
|
+
uniqueness_type: originalCampaign.uniqueness_type,
|
|
185
249
|
};
|
|
186
|
-
// Create the new campaign
|
|
187
250
|
const newCampaign = await createCampaign(payload);
|
|
188
|
-
|
|
189
|
-
for (const stream of templateStreams) {
|
|
251
|
+
for (const stream of originalStreams) {
|
|
190
252
|
await http_1.default.post('streams', {
|
|
191
253
|
name: stream.name,
|
|
192
254
|
campaign_id: newCampaign.id,
|
|
@@ -208,53 +270,241 @@ async function cloneCampaignForApp(app, integrationType) {
|
|
|
208
270
|
state: stream.state
|
|
209
271
|
});
|
|
210
272
|
}
|
|
211
|
-
|
|
273
|
+
await http_1.default.put(`/campaigns/${newCampaign.id}`, {
|
|
274
|
+
group_id: originalCampaign.group_id
|
|
275
|
+
});
|
|
212
276
|
const updatedCampaign = await getCampaignById(newCampaign.id);
|
|
213
|
-
return
|
|
277
|
+
return updatedCampaign;
|
|
214
278
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
279
|
+
async function cloneDirectCampaign(app, platform, addDefaultStreams) {
|
|
280
|
+
let name = `#${app.id} [➥]`;
|
|
281
|
+
let platformName = platform ? (0, app_1.getPlatformName)(platform) : null;
|
|
282
|
+
const platformCampaignName = `#${app.id} [➥] (${platformName})`;
|
|
283
|
+
const generateAlias = () => {
|
|
284
|
+
const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
|
285
|
+
return Array.from({ length: 8 }, () => chars.charAt(Math.floor(Math.random() * chars.length))).join('');
|
|
286
|
+
};
|
|
287
|
+
let allCampaigns = await getAllCampaigns();
|
|
288
|
+
let matchingCampaign = [];
|
|
289
|
+
if (platform && platform !== app_1.EPlatform.GENERAL) {
|
|
290
|
+
// Для конкретної платформи
|
|
291
|
+
const platformName = (0, app_1.getPlatformName)(platform);
|
|
292
|
+
matchingCampaign = allCampaigns.filter((c) => {
|
|
293
|
+
// Точна перевірка ID з межами слів
|
|
294
|
+
const idPattern = new RegExp(`#${app.id}\\b`);
|
|
295
|
+
const hasId = idPattern.test(c.name);
|
|
296
|
+
// Перевіряємо наявність стрілки (може бути в комбінації з іншими символами)
|
|
297
|
+
const hasArrow = c.name.includes('➥');
|
|
298
|
+
// Перевіряємо наявність платформи в дужках в кінці назви
|
|
299
|
+
const platformPattern = new RegExp(`\\(.*${platformName}.*\\)\\s*$`);
|
|
300
|
+
const hasPlatform = platformPattern.test(c.name);
|
|
301
|
+
return hasId && hasArrow && hasPlatform;
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
// Для General платформи
|
|
306
|
+
matchingCampaign = allCampaigns.filter((c) => {
|
|
307
|
+
// Точна перевірка ID з межами слів
|
|
308
|
+
const idPattern = new RegExp(`#${app.id}\\b`);
|
|
309
|
+
const hasId = idPattern.test(c.name);
|
|
310
|
+
// Перевіряємо наявність стрілки (може бути в комбінації з іншими символами)
|
|
311
|
+
const hasArrow = c.name.includes('➥');
|
|
312
|
+
// Перевіряємо відсутність платформи в дужках в кінці
|
|
313
|
+
// Дозволяємо будь-які інші дужки (як для гео або опису)
|
|
314
|
+
const noPlatformAtEnd = !/\(.*(?:iOS|Android|Desktop|Mobile).*\)\s*$/.test(c.name);
|
|
315
|
+
return hasId && hasArrow && noPlatformAtEnd;
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
if (matchingCampaign.length > 0) {
|
|
319
|
+
const existingCampaign = matchingCampaign[0];
|
|
320
|
+
// Якщо addDefaultStreams === true, додаємо потоки до існуючої кампанії
|
|
321
|
+
if (addDefaultStreams) {
|
|
322
|
+
const originalStreams = await getStreamsByCampaignId(3175);
|
|
323
|
+
const existingStreams = await getStreamsByCampaignId(existingCampaign.id);
|
|
324
|
+
for (const stream of originalStreams) {
|
|
325
|
+
// Перевіряємо чи потік вже існує
|
|
326
|
+
const existingStream = existingStreams.find(s => s.name === stream.name);
|
|
327
|
+
if (!existingStream) {
|
|
328
|
+
await http_1.default.post('streams', {
|
|
329
|
+
name: stream.name,
|
|
330
|
+
campaign_id: existingCampaign.id,
|
|
331
|
+
schema: stream.schema,
|
|
332
|
+
type: stream.type,
|
|
333
|
+
action_type: stream.action_type,
|
|
334
|
+
weight: stream.weight,
|
|
335
|
+
offers: stream.offers.map((offer) => ({
|
|
336
|
+
offer_id: offer.offer_id,
|
|
337
|
+
share: offer.share,
|
|
338
|
+
state: offer.state
|
|
339
|
+
})),
|
|
340
|
+
filters: stream.filters.map((filter) => ({
|
|
341
|
+
name: filter.name,
|
|
342
|
+
mode: filter.mode,
|
|
343
|
+
payload: filter.payload
|
|
344
|
+
})),
|
|
345
|
+
position: stream.position,
|
|
346
|
+
state: stream.state
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
}
|
|
236
350
|
}
|
|
351
|
+
return existingCampaign;
|
|
352
|
+
}
|
|
353
|
+
const originalCampaign = await getCampaignById(3175);
|
|
354
|
+
const maxPosition = Math.max(...allCampaigns.map(c => c.position || 0));
|
|
355
|
+
const originalStreams = await getStreamsByCampaignId(3175);
|
|
356
|
+
let allDomains = await exports.KeitaroService.getDomains(true);
|
|
357
|
+
if (!allDomains) {
|
|
358
|
+
throw Error(`Failed to get all domains list`);
|
|
359
|
+
}
|
|
360
|
+
const domain = allDomains[Math.floor(Math.random() * allDomains.length)];
|
|
361
|
+
const maxGroupId = Math.max(...allCampaigns.map(c => c.group_id || 0));
|
|
362
|
+
let alias = generateAlias();
|
|
363
|
+
let payload = {
|
|
364
|
+
// Унікальні поля
|
|
365
|
+
name: platformName ? platformCampaignName : name,
|
|
366
|
+
alias: alias,
|
|
367
|
+
domain_id: domain.id,
|
|
368
|
+
position: [maxPosition + 100],
|
|
369
|
+
group_id: maxGroupId + 1,
|
|
370
|
+
traffic_source_id: keitaro_utils_1.TRAFFIC_SOURCE_ID_FLASH_AI,
|
|
371
|
+
parameters: (0, keitaro_utils_1.prepareOWCampaignParameters)(app),
|
|
372
|
+
source: originalCampaign.source,
|
|
373
|
+
bind_visitors: "slo",
|
|
374
|
+
// Неунікальні поля з оригінальної кампанії
|
|
375
|
+
type: originalCampaign.type,
|
|
376
|
+
state: originalCampaign.state,
|
|
377
|
+
cost_type: originalCampaign.cost_type,
|
|
378
|
+
cost_value: originalCampaign.cost_value,
|
|
379
|
+
cost_currency: originalCampaign.cost_currency,
|
|
380
|
+
uniqueness_period: originalCampaign.uniqueness_period,
|
|
381
|
+
cookies_ttl: originalCampaign.cookies_ttl,
|
|
382
|
+
notes: originalCampaign.notes,
|
|
383
|
+
collect_clicks: originalCampaign.collect_clicks,
|
|
384
|
+
uniqueness_type: originalCampaign.uniqueness_type,
|
|
385
|
+
};
|
|
386
|
+
const newCampaign = await createCampaign(payload);
|
|
387
|
+
// Додаємо потоки: всі якщо addDefaultStreams === true, інакше тільки перший
|
|
388
|
+
const streamsToAdd = addDefaultStreams ? originalStreams : originalStreams.slice(0, 1);
|
|
389
|
+
for (const stream of streamsToAdd) {
|
|
390
|
+
await http_1.default.post('streams', {
|
|
391
|
+
name: stream.name,
|
|
392
|
+
campaign_id: newCampaign.id,
|
|
393
|
+
schema: stream.schema,
|
|
394
|
+
type: stream.type,
|
|
395
|
+
action_type: stream.action_type,
|
|
396
|
+
weight: stream.weight,
|
|
397
|
+
offers: stream.offers.map((offer) => ({
|
|
398
|
+
offer_id: offer.offer_id,
|
|
399
|
+
share: offer.share,
|
|
400
|
+
state: offer.state
|
|
401
|
+
})),
|
|
402
|
+
filters: stream.filters.map((filter) => ({
|
|
403
|
+
name: filter.name,
|
|
404
|
+
mode: filter.mode,
|
|
405
|
+
payload: filter.payload
|
|
406
|
+
})),
|
|
407
|
+
position: stream.position,
|
|
408
|
+
state: stream.state
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
await http_1.default.put(`/campaigns/${newCampaign.id}`, {
|
|
412
|
+
group_id: originalCampaign.group_id
|
|
413
|
+
});
|
|
414
|
+
const updatedCampaign = await getCampaignById(newCampaign.id);
|
|
415
|
+
return updatedCampaign;
|
|
416
|
+
}
|
|
417
|
+
async function cloneDCampaign(app) {
|
|
418
|
+
let name = `D #${app.id} (${app.bundle})`;
|
|
419
|
+
let allCampaigns = await getAllCampaigns();
|
|
420
|
+
let matchingCampaign = allCampaigns.filter((c) => c.name.includes(`D #${app.id}`));
|
|
421
|
+
if (matchingCampaign.length > 0)
|
|
422
|
+
return matchingCampaign[0];
|
|
423
|
+
const { data: campaigns } = await http_1.default.post(`/campaigns/2693/clone`);
|
|
424
|
+
if (campaigns.length == 0)
|
|
425
|
+
throw Error("Campaign cloning falied");
|
|
426
|
+
let clonedCampaign = campaigns[0];
|
|
427
|
+
let allDomains = await exports.KeitaroService.getDomains(true);
|
|
428
|
+
if (!allDomains) {
|
|
429
|
+
throw Error(`Failed to get all domains list`);
|
|
430
|
+
}
|
|
431
|
+
const domain = allDomains[Math.floor(Math.random() * allDomains.length)];
|
|
432
|
+
let payload = {
|
|
433
|
+
name: name,
|
|
434
|
+
traffic_source_id: keitaro_utils_1.TRAFFIC_SOURCE_ID_FLASH_AI,
|
|
435
|
+
domain_id: domain.id,
|
|
436
|
+
group_id: 93,
|
|
437
|
+
};
|
|
438
|
+
const { data: campaign } = await http_1.default.put(`/campaigns/${clonedCampaign.id}`, payload);
|
|
439
|
+
return campaign;
|
|
440
|
+
}
|
|
441
|
+
async function changeCampaignsGroup(fromId, toId, exceptForCampaignIds, onlyForCampaignIds) {
|
|
442
|
+
let campaigns = await getAllCampaigns();
|
|
443
|
+
const matchingCampaigns = campaigns.filter(campaign => campaign.group_id == fromId
|
|
444
|
+
&& exceptForCampaignIds.length > 0 ? !exceptForCampaignIds.includes(campaign.id) : onlyForCampaignIds?.includes(campaign.id));
|
|
445
|
+
for (let campaign of matchingCampaigns) {
|
|
446
|
+
await updateCampaign(campaign.id, { group_id: toId });
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
// Domain
|
|
450
|
+
async function getDomains(onlyActive) {
|
|
451
|
+
const { data: domains } = await http_1.default.get(`/domains`);
|
|
452
|
+
return onlyActive ? domains.filter((d) => d.network_status == "active") : domains;
|
|
453
|
+
}
|
|
454
|
+
async function getProfitForTimeRange(from, to) {
|
|
455
|
+
let fromString = (0, general_1.convertMillisToDate)(from);
|
|
456
|
+
let toString = (0, general_1.convertMillisToDate)(to);
|
|
457
|
+
let { data: data } = await http_1.default.post(`/report/build`, {
|
|
458
|
+
range: {
|
|
459
|
+
from: fromString,
|
|
460
|
+
to: toString,
|
|
461
|
+
timezone: 'Europe/Kyiv'
|
|
462
|
+
},
|
|
463
|
+
metrics: ['profit']
|
|
464
|
+
});
|
|
465
|
+
return data.rows[0].profit;
|
|
466
|
+
}
|
|
467
|
+
// async function getProfitForTodayAndYesterday(): Promise<any> {
|
|
468
|
+
// let timestamps = getTimestampsForTodayAndYesterday()
|
|
469
|
+
// let today = await KeitaroService.getProfitForTimeRange(timestamps.today.start, timestamps.today.end)
|
|
470
|
+
// let yesterday = await KeitaroService.getProfitForTimeRange(timestamps.yesterday.start, timestamps.yesterday.end)
|
|
471
|
+
// return {
|
|
472
|
+
// today: today,
|
|
473
|
+
// yesterday: yesterday
|
|
474
|
+
// }
|
|
475
|
+
// }
|
|
476
|
+
async function fixBrokenClickCosts(startDate, endDate) {
|
|
477
|
+
// Get all campaigns to update
|
|
478
|
+
const campaigns = await getAllCampaigns();
|
|
479
|
+
const campaignIds = campaigns.map(campaign => campaign.id);
|
|
480
|
+
// Prepare the payload for the API request
|
|
481
|
+
const payload = {
|
|
482
|
+
campaign_ids: campaignIds,
|
|
483
|
+
costs: [{
|
|
484
|
+
start_date: startDate,
|
|
485
|
+
end_date: endDate,
|
|
486
|
+
cost: 0,
|
|
487
|
+
filters: {}
|
|
488
|
+
}],
|
|
489
|
+
timezone: "Europe/Kyiv",
|
|
490
|
+
currency: "USD",
|
|
491
|
+
only_campaign_uniques: 0
|
|
492
|
+
};
|
|
493
|
+
// Make the API request to update costs
|
|
494
|
+
await http_1.default.post('/clicks/update_costs', payload);
|
|
495
|
+
}
|
|
496
|
+
async function getClicks(request) {
|
|
497
|
+
const defaultRequest = typeof request === 'string' ? {
|
|
498
|
+
range: { interval: request }
|
|
499
|
+
} : {
|
|
500
|
+
...request
|
|
237
501
|
};
|
|
502
|
+
const { data } = await http_1.default.post('/clicks/log', defaultRequest);
|
|
503
|
+
return data.rows;
|
|
238
504
|
}
|
|
239
505
|
exports.KeitaroService = {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
updateCampaign,
|
|
245
|
-
cloneCampaignForApp,
|
|
246
|
-
getOfferwallCampaigns,
|
|
247
|
-
// Stream operations
|
|
248
|
-
getStreamsByCampaignId,
|
|
249
|
-
createStream,
|
|
250
|
-
// Domain operations
|
|
251
|
-
getDomains,
|
|
252
|
-
// Offer operations
|
|
253
|
-
getAllOffers,
|
|
254
|
-
createOfferInKeitaro,
|
|
255
|
-
addOfferToKeitaro,
|
|
256
|
-
// Utilities
|
|
257
|
-
generateAlias,
|
|
258
|
-
campaignToKeitaroData,
|
|
506
|
+
getStreamsByCampaignId, updateCampaign, getAllCampaigns, getAllOffers, cloneStreams, addOffersToKeitaro, getOfferByKeitaroId, getDomains, createCampaign, getCampaignById, upsertStreamToCampaign, cloneOWCampaign,
|
|
507
|
+
updateOffer, changeCampaignsGroup, getProfitForTimeRange, getClicks,
|
|
508
|
+
// getProfitForTodayAndYesterday,
|
|
509
|
+
cloneDCampaign, findKeitaroOffers, fixBrokenClickCosts, cloneDirectCampaign
|
|
259
510
|
};
|
|
260
|
-
exports.default = exports.KeitaroService;
|