@bprotsyk/aso-core 2.1.37 → 2.1.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/README.md +1 -1
  2. package/lib/app/app-integration.d.ts +53 -53
  3. package/lib/app/app-integration.js +63 -63
  4. package/lib/app/app-list-item.d.ts +5 -5
  5. package/lib/app/app-list-item.js +2 -2
  6. package/lib/app/app-type.d.ts +4 -4
  7. package/lib/app/app-type.js +8 -8
  8. package/lib/app/app.d.ts +208 -290
  9. package/lib/app/app.js +156 -156
  10. package/lib/general/cloudflare-domain.d.ts +42 -42
  11. package/lib/general/cloudflare-domain.js +12 -12
  12. package/lib/general/domain.d.ts +110 -169
  13. package/lib/general/domain.js +62 -62
  14. package/lib/general/namecheap-domain.d.ts +85 -132
  15. package/lib/general/namecheap-domain.js +14 -14
  16. package/lib/general/push.d.ts +6 -6
  17. package/lib/general/push.js +2 -2
  18. package/lib/general/queue.d.ts +2 -2
  19. package/lib/general/queue.js +1 -1
  20. package/lib/general/shape.d.ts +18 -18
  21. package/lib/general/shape.js +36 -36
  22. package/lib/index.d.ts +26 -26
  23. package/lib/index.js +69 -69
  24. package/lib/keitaro/keitaro-campaign.d.ts +31 -31
  25. package/lib/keitaro/keitaro-campaign.js +5 -5
  26. package/lib/keitaro/keitaro-domain.d.ts +6 -6
  27. package/lib/keitaro/keitaro-domain.js +2 -2
  28. package/lib/keitaro/keitaro-offer.d.ts +7 -7
  29. package/lib/keitaro/keitaro-offer.js +2 -2
  30. package/lib/keitaro/keitaro-stream.d.ts +20 -20
  31. package/lib/keitaro/keitaro-stream.js +2 -2
  32. package/lib/network/keitaro/http.d.ts +2 -2
  33. package/lib/network/keitaro/http.js +12 -12
  34. package/lib/network/keitaro/keitaro-service.d.ts +50 -48
  35. package/lib/network/keitaro/keitaro-service.js +283 -293
  36. package/lib/offers/list.d.ts +42 -435
  37. package/lib/offers/list.js +12 -12
  38. package/lib/offers/offer.d.ts +91 -152
  39. package/lib/offers/offer.js +42 -42
  40. package/lib/offers/offerwall/offerwall-home-dialog-data.d.ts +6 -6
  41. package/lib/offers/offerwall/offerwall-home-dialog-data.js +2 -2
  42. package/lib/offers/offerwall/offerwall-offer.d.ts +12 -12
  43. package/lib/offers/offerwall/offerwall-offer.js +2 -2
  44. package/lib/offers/offerwall/offerwall-response.d.ts +6 -6
  45. package/lib/offers/offerwall/offerwall-response.js +2 -2
  46. package/lib/offers/offerwall/offerwall-section.d.ts +6 -6
  47. package/lib/offers/offerwall/offerwall-section.js +2 -2
  48. package/lib/offers/section.d.ts +47 -60
  49. package/lib/offers/section.js +20 -20
  50. package/lib/panel/app/upsert-flash-app-request.d.ts +31 -31
  51. package/lib/panel/app/upsert-flash-app-request.js +2 -2
  52. package/lib/panel/auth.d.ts +9 -9
  53. package/lib/panel/auth.js +2 -2
  54. package/lib/panel/flash/upsert-flash-app-request.d.ts +31 -31
  55. package/lib/panel/flash/upsert-flash-app-request.js +2 -2
  56. package/lib/panel/user.d.ts +46 -59
  57. package/lib/panel/user.js +28 -28
  58. package/lib/templates/nginx-template.conf +35 -35
  59. package/lib/templates/nginx-template.d.ts +1 -1
  60. package/lib/templates/nginx-template.js +39 -39
  61. package/lib/templates/nginx-template.ts +35 -35
  62. package/lib/utils/general.d.ts +11 -11
  63. package/lib/utils/general.js +40 -40
  64. package/lib/utils/huawei/converter.d.ts +2 -2
  65. package/lib/utils/huawei/converter.js +53 -53
  66. package/lib/utils/keitaro-utils.d.ts +13 -13
  67. package/lib/utils/keitaro-utils.js +614 -569
  68. package/lib/utils/server-util.js +303 -303
  69. package/package.json +51 -51
  70. package/src/app/app-integration.ts +66 -66
  71. package/src/app/app-list-item.ts +4 -4
  72. package/src/app/app-type.ts +3 -3
  73. package/src/app/app.ts +317 -317
  74. package/src/general/cloudflare-domain.ts +44 -44
  75. package/src/general/domain.ts +106 -106
  76. package/src/general/namecheap-domain.ts +63 -63
  77. package/src/general/push.ts +5 -5
  78. package/src/general/queue.ts +4 -4
  79. package/src/general/shape.tsx +55 -55
  80. package/src/index.ts +32 -32
  81. package/src/keitaro/keitaro-campaign.ts +35 -35
  82. package/src/keitaro/keitaro-domain.ts +5 -5
  83. package/src/keitaro/keitaro-offer.ts +6 -6
  84. package/src/keitaro/keitaro-stream.ts +19 -19
  85. package/src/network/keitaro/http.ts +8 -8
  86. package/src/network/keitaro/keitaro-service.ts +348 -364
  87. package/src/offers/list.ts +22 -19
  88. package/src/offers/offer.ts +80 -80
  89. package/src/offers/offerwall/offerwall-home-dialog-data.ts +6 -6
  90. package/src/offers/offerwall/offerwall-offer.ts +12 -12
  91. package/src/offers/offerwall/offerwall-response.ts +7 -7
  92. package/src/offers/offerwall/offerwall-section.ts +7 -7
  93. package/src/offers/section.ts +29 -29
  94. package/src/panel/app/upsert-flash-app-request.ts +39 -39
  95. package/src/panel/auth.ts +9 -9
  96. package/src/panel/user.ts +38 -38
  97. package/src/templates/nginx-template.ts +35 -35
  98. package/src/utils/data.csv +65 -65
  99. package/src/utils/general.ts +36 -36
  100. package/src/utils/huawei/converter.ts +55 -55
  101. package/src/utils/keitaro-utils.ts +717 -664
  102. package/src/utils/map-apps.json +4747 -4747
  103. package/src/utils/server-util.ts +368 -368
  104. package/src/utils/update-postbacks.js +27 -27
  105. package/tsconfig.json +20 -20
@@ -1,364 +1,348 @@
1
- import { IKeitaroStream } from "../../keitaro/keitaro-stream";
2
- import { IOffer } from "../../offers/offer"
3
- import keitaroApi from "./http"
4
- import { IKeitaroCampaign } from "../../keitaro/keitaro-campaign";
5
- import { IKeitaroDomain } from "../../keitaro/keitaro-domain";
6
- import { IApp } from "../../app/app";
7
- import { TRAFFIC_SOURCE_ID_FLASH_AI, prepareOWCampaignParameters } from "../../utils/keitaro-utils";
8
- import { convertMillisToDate, getTimestampsForTodayAndYesterday } from "../../utils/general";
9
- import { IKeitaroOffer } from "index";
10
-
11
- export interface IKeitaroOffersFilter {
12
- keitaroId?: number,
13
- name?: string,
14
- caption?: string
15
- }
16
-
17
- async function getStreamsByCampaignId(campaignId: number): Promise<IKeitaroStream[]> {
18
- const { data: streams } = await keitaroApi.get<IKeitaroStream[]>(`campaigns/${campaignId}/streams`);
19
-
20
- return streams
21
- }
22
-
23
- async function getAllCampaigns(): Promise<IKeitaroCampaign[]> {
24
- const { data: campaigns } = await keitaroApi.get<IKeitaroCampaign[]>('campaigns');
25
- console.log("Campaigns fetched:", campaigns);
26
- return campaigns
27
- }
28
-
29
- async function cloneStreams(originalCampaignId: number, streamPositionsToClone: number[], campaignRegExp: RegExp): Promise<void> {
30
- // Get the original campaign's streams
31
- const originalStreams = await getStreamsByCampaignId(originalCampaignId)
32
-
33
- // Filter the original streams by the given stream positions to clone
34
- const streamsToClone = originalStreams.filter(stream => streamPositionsToClone.includes(stream.position));
35
-
36
- // Get a list of all campaigns
37
- const allCampaigns = await getAllCampaigns()
38
-
39
- // Filter the campaigns by the given RegExp
40
- const matchingCampaigns = allCampaigns.filter(campaign => campaignRegExp.exec(campaign.name) && campaign.id != originalCampaignId);
41
- // console.log(matchingCampaigns)
42
-
43
- // For each matching campaign, clone the streams
44
- for (const matchingCampaign of matchingCampaigns) {
45
- for (const streamToClone of streamsToClone) {
46
- await keitaroApi.post('streams', {
47
- name: streamToClone.name,
48
- campaign_id: matchingCampaign.id,
49
- schema: streamToClone.schema,
50
- type: streamToClone.type,
51
- action_type: streamToClone.action_type,
52
- weight: 100,
53
- offers: streamToClone.offers.map((offer) => {
54
- return {
55
- offer_id: offer.offer_id,
56
- share: 100
57
- }
58
- }),
59
- filters: streamToClone.filters.map((filter) => {
60
- return {
61
- name: filter.name,
62
- mode: filter.mode,
63
- payload: filter.payload
64
- }
65
- }),
66
- });
67
- }
68
- }
69
- }
70
-
71
- async function updateCampaign(id: number, payload: Partial<IKeitaroCampaign>) {
72
- await keitaroApi.put(`campaigns/${id}`, payload)
73
- }
74
-
75
- async function createStreamForMatchingCampaigns(streamPartialPayload: any, offerId: string, campaignRegExp: RegExp, avoidGroup?: number) {
76
- // Get a list of all campaigns
77
- const allCampaigns = await getAllCampaigns()
78
-
79
- // Filter the campaigns by the given RegExp
80
- const matchingCampaigns = allCampaigns.filter(campaign => (avoidGroup ? campaign.group_id != avoidGroup : true) && campaignRegExp.exec(campaign.name));
81
- // console.log(matchingCampaigns)
82
-
83
-
84
- // For each matching campaign, clone the streams
85
- for (const matchingCampaign of matchingCampaigns) {
86
- let streams = await getStreamsByCampaignId(matchingCampaign.id)
87
-
88
- let identicalStream = streams.find((stream) => stream.name.includes(offerId))
89
-
90
- if (identicalStream) {
91
- await keitaroApi.put(`streams/${identicalStream.id}`, {
92
- campaign_id: matchingCampaign.id,
93
- ...streamPartialPayload
94
- });
95
- } else {
96
- await keitaroApi.post('streams', {
97
- campaign_id: matchingCampaign.id,
98
- ...streamPartialPayload
99
- });
100
- }
101
- }
102
- }
103
-
104
- async function getAllOffers(): Promise<IKeitaroOffer[]> {
105
- const { data: offers } = await keitaroApi.get<IKeitaroOffer[]>('offers')
106
-
107
- return offers
108
- }
109
-
110
-
111
- async function findKeitaroOffers(filter: IKeitaroOffersFilter): Promise<IKeitaroOffer[]> {
112
- let offers = await getAllOffers()
113
-
114
- if (filter.caption) offers = offers.filter((o) => o.name.includes(filter.caption!))
115
- if (filter.keitaroId) offers = offers.filter((o) => o.id == filter.keitaroId!)
116
- if (filter.name) offers = offers.filter((o) => o.name.includes(filter.name!))
117
-
118
- return offers
119
- }
120
-
121
- async function getOfferByKeitaroId(id: number): Promise<IKeitaroOffer> {
122
- const { data: offer } = await keitaroApi.get<IKeitaroOffer>(`offers/${id}`)
123
-
124
- return offer
125
- }
126
-
127
- async function updateOffer(offer: any): Promise<IKeitaroOffer> {
128
- const { data: o } = await keitaroApi.put<IKeitaroOffer>(`offers/${offer.id}`, offer)
129
-
130
- return o
131
- }
132
-
133
- function createStreamPartialPayload(keitaroOfferId: number, offerName: string, offerId: string, offerGeo: string) {
134
- return {
135
- name: `${offerName} ${offerGeo} (${offerId})`,
136
- schema: "landings",
137
- type: "regular",
138
- action_type: "http",
139
- weight: 100,
140
- offers: [{
141
- offer_id: keitaroOfferId,
142
- share: 100,
143
- state: "active"
144
- }],
145
- filters: [{
146
- name: "sub_id_15",
147
- mode: "accept",
148
- payload: [offerId]
149
- }],
150
- }
151
- }
152
-
153
- async function addOfferToKeitaro(offer: IOffer, affiliateId: number, link: string, avoidGroup?: number, groupId?: number) {
154
- // TODO look if offer already exists by offer.name
155
- let allOffers = await getAllOffers()
156
- let identicalOffer = allOffers.find((o) => { return o.name.includes(offer.name) })
157
-
158
- let keitaroOfferId
159
- if (identicalOffer) {
160
- keitaroOfferId = identicalOffer.id
161
- } else {
162
- let offerPayload = {
163
- name: `${offer.caption} ${offer.geo} (${offer.name})`,
164
- group_id: groupId || 1,
165
- action_payload: link,
166
- affiliate_network_id: affiliateId,
167
- country: [offer.geo],
168
- action_type: "http",
169
- offer_type: "external",
170
- payout_auto: true,
171
- payout_upsell: true,
172
- }
173
-
174
- const { data: keitaroOffer } = await keitaroApi.post(`offers`, offerPayload);
175
-
176
- keitaroOfferId = keitaroOffer.id
177
- }
178
-
179
- let streamPartialPayload = createStreamPartialPayload(keitaroOfferId, offer.caption, offer.name, offer.geo)
180
-
181
- await createStreamForMatchingCampaigns(streamPartialPayload, offer.name, /◈/, avoidGroup)
182
- }
183
-
184
- async function createCampaign(campaignData: Partial<IKeitaroCampaign>): Promise<IKeitaroCampaign> {
185
- let { data: campaign } = await keitaroApi.post(`/campaigns`, campaignData)
186
-
187
- return campaign
188
- }
189
-
190
- async function getCampaignById(id: number): Promise<IKeitaroCampaign> {
191
- const { data: campaign } = await keitaroApi.get(`/campaigns/${id}`);
192
- return campaign
193
- }
194
-
195
- export async function upsertStreamToCampaign(campaign: IKeitaroCampaign, stream: Partial<IKeitaroStream>) {
196
- let streams = await getStreamsByCampaignId(campaign.id)
197
-
198
- let identicalStream = streams.find((s) => stream.name == s.name)
199
-
200
- if (identicalStream) {
201
- console.log(`Found identical! Name: ${stream.name}`)
202
- await keitaroApi.put(`streams/${identicalStream.id}`, {
203
- campaign_id: campaign.id,
204
- ...stream
205
- });
206
- } else {
207
- await keitaroApi.post('streams', {
208
- campaign_id: campaign.id,
209
- ...stream
210
- });
211
- }
212
- }
213
-
214
- // async function cloneOWCampaign(app: IApp): Promise<IKeitaroCampaign> {
215
- // let name = `#${app.id} [◈]`
216
-
217
- // let allCampaigns = await getAllCampaigns()
218
- // let matchingCampaign = allCampaigns.filter((c) => new RegExp(`#${app.id}.*◈`).test(c.name))
219
- // if (matchingCampaign.length > 0) return matchingCampaign[0]
220
-
221
- // const { data: campaigns } = await keitaroApi.post(`/campaigns/2673/clone`);
222
-
223
- // if (campaigns.length == 0) throw Error("Campaign cloning falied")
224
-
225
- // let clonedCampaign: IKeitaroCampaign = campaigns[0]
226
-
227
- // let allDomains = await KeitaroService.getDomains(true)
228
- // if (!allDomains) {
229
- // throw Error(`Failed to get all domains list`)
230
- // }
231
-
232
- // const domain = allDomains[Math.floor(Math.random() * allDomains.length)];
233
-
234
- // let payload: Partial<IKeitaroCampaign> = {
235
- // name: name,
236
- // traffic_source_id: TRAFFIC_SOURCE_ID_FLASH_AI,
237
- // domain_id: domain.id,
238
- // parameters: prepareOWCampaignParameters(app)
239
- // }
240
-
241
- // const { data: campaign } = await keitaroApi.put(`/campaigns/${clonedCampaign.id}`, payload)
242
-
243
- // return campaign
244
- // }
245
- async function cloneOWCampaign(app: IApp): Promise<IKeitaroCampaign> {
246
- let name = `#${app.id} [◈]`;
247
-
248
- console.log("Fetching all campaigns...");
249
- let allCampaigns = await getAllCampaigns();
250
- let matchingCampaign = allCampaigns.filter((c) => new RegExp(`#${app.id}.*◈`).test(c.name));
251
- if (matchingCampaign.length > 0) return matchingCampaign[0];
252
-
253
- console.log("Cloning campaign...");
254
- console.log(`Campaigns Data:`, await keitaroApi.post(`/campaigns/2673/clone`));
255
- const { data: campaigns } = await keitaroApi.post(`/campaigns/2673/clone`);
256
- console.log("Campaigns cloned:", campaigns);
257
-
258
- if (campaigns.length == 0) throw Error("Campaign cloning failed");
259
-
260
- let clonedCampaign: IKeitaroCampaign = campaigns[0];
261
-
262
- console.log("Fetching all domains...");
263
- let allDomains = await KeitaroService.getDomains(true);
264
- if (!allDomains) {
265
- throw Error(`Failed to get all domains list`);
266
- }
267
-
268
- const domain = allDomains[Math.floor(Math.random() * allDomains.length)];
269
-
270
- let payload: Partial<IKeitaroCampaign> = {
271
- name: name,
272
- traffic_source_id: TRAFFIC_SOURCE_ID_FLASH_AI,
273
- domain_id: domain.id,
274
- parameters: prepareOWCampaignParameters(app)
275
- };
276
-
277
- console.log("Updating cloned campaign...");
278
- const { data: campaign } = await keitaroApi.put(`/campaigns/${clonedCampaign.id}`, payload);
279
- console.log("Campaign updated:", campaign);
280
-
281
- return campaign;
282
- }
283
-
284
- async function cloneDCampaign(app: IApp): Promise<IKeitaroCampaign> {
285
- let name = `D #${app.id} (${app.bundle})`
286
-
287
- let allCampaigns = await getAllCampaigns()
288
- let matchingCampaign = allCampaigns.filter((c) => c.name.includes(`D #${app.id}`))
289
- if (matchingCampaign.length > 0) return matchingCampaign[0]
290
-
291
- const { data: campaigns } = await keitaroApi.post(`/campaigns/2693/clone`);
292
-
293
- if (campaigns.length == 0) throw Error("Campaign cloning falied")
294
-
295
- let clonedCampaign: IKeitaroCampaign = campaigns[0]
296
-
297
- let allDomains = await KeitaroService.getDomains(true)
298
- if (!allDomains) {
299
- throw Error(`Failed to get all domains list`)
300
- }
301
-
302
- const domain = allDomains[Math.floor(Math.random() * allDomains.length)];
303
-
304
- let payload: Partial<IKeitaroCampaign> = {
305
- name: name,
306
- traffic_source_id: TRAFFIC_SOURCE_ID_FLASH_AI,
307
- domain_id: domain.id,
308
- group_id: 93,
309
- }
310
-
311
- const { data: campaign } = await keitaroApi.put(`/campaigns/${clonedCampaign.id}`, payload)
312
-
313
- return campaign
314
- }
315
-
316
- async function changeCampaignsGroup(fromId: number, toId: number, exceptForCampaignIds: number[], onlyForCampaignIds?: number[]) {
317
- let campaigns = await getAllCampaigns()
318
- const matchingCampaigns = campaigns.filter(campaign => campaign.group_id == fromId
319
- && exceptForCampaignIds.length > 0 ? !exceptForCampaignIds.includes(campaign.id) : onlyForCampaignIds?.includes(campaign.id))
320
-
321
- for (let campaign of matchingCampaigns) {
322
- await updateCampaign(campaign.id, { group_id: toId })
323
- }
324
- }
325
-
326
- // Domain
327
- async function getDomains(onlyActive?: boolean): Promise<IKeitaroDomain[]> {
328
- const { data: domains } = await keitaroApi.get<IKeitaroDomain[]>(`/domains`)
329
- return onlyActive ? domains.filter((d) => d.network_status == "active") : domains
330
- }
331
-
332
- async function getProfitForTimeRange(from: number, to: number): Promise<number> {
333
- let fromString = convertMillisToDate(from)
334
- let toString = convertMillisToDate(to)
335
-
336
- let { data: data } = await keitaroApi.post(`/report/build`, {
337
- range: {
338
- from: fromString,
339
- to: toString,
340
- timezone: 'Europe/Kyiv'
341
- },
342
- metrics: ['profit']
343
- })
344
-
345
- return data.rows[0].profit
346
- }
347
-
348
- // async function getProfitForTodayAndYesterday(): Promise<any> {
349
- // let timestamps = getTimestampsForTodayAndYesterday()
350
- // let today = await KeitaroService.getProfitForTimeRange(timestamps.today.start, timestamps.today.end)
351
- // let yesterday = await KeitaroService.getProfitForTimeRange(timestamps.yesterday.start, timestamps.yesterday.end)
352
-
353
- // return {
354
- // today: today,
355
- // yesterday: yesterday
356
- // }
357
- // }
358
-
359
- export const KeitaroService = {
360
- getStreamsByCampaignId, updateCampaign, getAllCampaigns, getAllOffers, cloneStreams, addOfferToKeitaro, getOfferByKeitaroId, getDomains, createCampaign, getCampaignById, upsertStreamToCampaign, cloneOWCampaign,
361
- updateOffer, changeCampaignsGroup, getProfitForTimeRange,
362
- // getProfitForTodayAndYesterday,
363
- cloneDCampaign, findKeitaroOffers
364
- }
1
+ import { IKeitaroStream } from "../../keitaro/keitaro-stream";
2
+ import { IOffer } from "../../offers/offer"
3
+ import keitaroApi from "./http"
4
+ import { IKeitaroCampaign } from "../../keitaro/keitaro-campaign";
5
+ import { IKeitaroDomain } from "../../keitaro/keitaro-domain";
6
+ import { IApp } from "../../app/app";
7
+ import { TRAFFIC_SOURCE_ID_FLASH_AI, prepareOWCampaignParameters } from "../../utils/keitaro-utils";
8
+ import { convertMillisToDate, getTimestampsForTodayAndYesterday } from "../../utils/general";
9
+ import { IKeitaroOffer } from "index";
10
+
11
+ export interface IKeitaroOffersFilter {
12
+ keitaroId?: number,
13
+ name?: string,
14
+ caption?: string
15
+ }
16
+
17
+ async function getStreamsByCampaignId(campaignId: number): Promise<IKeitaroStream[]> {
18
+ const { data: streams } = await keitaroApi.get<IKeitaroStream[]>(`campaigns/${campaignId}/streams`);
19
+
20
+ return streams
21
+ }
22
+
23
+ async function getAllCampaigns(): Promise<IKeitaroCampaign[]> {
24
+ const { data: campaigns } = await keitaroApi.get<IKeitaroCampaign[]>('campaigns');
25
+ return campaigns
26
+ }
27
+
28
+ async function cloneStreams(originalCampaignId: number, streamPositionsToClone: number[], campaignRegExp: RegExp): Promise<void> {
29
+ // Get the original campaign's streams
30
+ const originalStreams = await getStreamsByCampaignId(originalCampaignId)
31
+
32
+ // Filter the original streams by the given stream positions to clone
33
+ const streamsToClone = originalStreams.filter(stream => streamPositionsToClone.includes(stream.position));
34
+
35
+ // Get a list of all campaigns
36
+ const allCampaigns = await getAllCampaigns()
37
+
38
+ // Filter the campaigns by the given RegExp
39
+ const matchingCampaigns = allCampaigns.filter(campaign => campaignRegExp.exec(campaign.name) && campaign.id != originalCampaignId);
40
+ // console.log(matchingCampaigns)
41
+
42
+ // For each matching campaign, clone the streams
43
+ for (const matchingCampaign of matchingCampaigns) {
44
+ for (const streamToClone of streamsToClone) {
45
+ await keitaroApi.post('streams', {
46
+ name: streamToClone.name,
47
+ campaign_id: matchingCampaign.id,
48
+ schema: streamToClone.schema,
49
+ type: streamToClone.type,
50
+ action_type: streamToClone.action_type,
51
+ weight: 100,
52
+ offers: streamToClone.offers.map((offer) => {
53
+ return {
54
+ offer_id: offer.offer_id,
55
+ share: 100
56
+ }
57
+ }),
58
+ filters: streamToClone.filters.map((filter) => {
59
+ return {
60
+ name: filter.name,
61
+ mode: filter.mode,
62
+ payload: filter.payload
63
+ }
64
+ }),
65
+ });
66
+ }
67
+ }
68
+ }
69
+
70
+ async function updateCampaign(id: number, payload: Partial<IKeitaroCampaign>) {
71
+ await keitaroApi.put(`campaigns/${id}`, payload)
72
+ }
73
+
74
+ async function createStreamForMatchingCampaigns(streamPartialPayload: any, offerId: string, campaignRegExp: RegExp, avoidGroup?: number) {
75
+ // Get a list of all campaigns
76
+ const allCampaigns = await getAllCampaigns()
77
+
78
+ // Filter the campaigns by the given RegExp
79
+ const matchingCampaigns = allCampaigns.filter(campaign => (avoidGroup ? campaign.group_id != avoidGroup : true) && campaignRegExp.exec(campaign.name));
80
+ // console.log(matchingCampaigns)
81
+
82
+
83
+ // For each matching campaign, clone the streams
84
+ for (const matchingCampaign of matchingCampaigns) {
85
+ let streams = await getStreamsByCampaignId(matchingCampaign.id)
86
+
87
+ let identicalStream = streams.find((stream) => stream.name.includes(offerId))
88
+
89
+ if (identicalStream) {
90
+ await keitaroApi.put(`streams/${identicalStream.id}`, {
91
+ campaign_id: matchingCampaign.id,
92
+ ...streamPartialPayload
93
+ });
94
+ } else {
95
+ await keitaroApi.post('streams', {
96
+ campaign_id: matchingCampaign.id,
97
+ ...streamPartialPayload
98
+ });
99
+ }
100
+ }
101
+ }
102
+
103
+ async function getAllOffers(): Promise<IKeitaroOffer[]> {
104
+ const { data: offers } = await keitaroApi.get<IKeitaroOffer[]>('offers')
105
+
106
+ return offers
107
+ }
108
+
109
+
110
+ async function findKeitaroOffers(filter: IKeitaroOffersFilter): Promise<IKeitaroOffer[]> {
111
+ let offers = await getAllOffers()
112
+
113
+ if (filter.caption) offers = offers.filter((o) => o.name.includes(filter.caption!))
114
+ if (filter.keitaroId) offers = offers.filter((o) => o.id == filter.keitaroId!)
115
+ if (filter.name) offers = offers.filter((o) => o.name.includes(filter.name!))
116
+
117
+ return offers
118
+ }
119
+
120
+ async function getOfferByKeitaroId(id: number): Promise<IKeitaroOffer> {
121
+ const { data: offer } = await keitaroApi.get<IKeitaroOffer>(`offers/${id}`)
122
+
123
+ return offer
124
+ }
125
+
126
+ async function updateOffer(offer: any): Promise<IKeitaroOffer> {
127
+ const { data: o } = await keitaroApi.put<IKeitaroOffer>(`offers/${offer.id}`, offer)
128
+
129
+ return o
130
+ }
131
+
132
+ function createStreamPartialPayload(keitaroOfferId: number, offerName: string, offerId: string, offerGeo: string) {
133
+ return {
134
+ name: `${offerName} ${offerGeo} (${offerId})`,
135
+ schema: "landings",
136
+ type: "regular",
137
+ action_type: "http",
138
+ weight: 100,
139
+ offers: [{
140
+ offer_id: keitaroOfferId,
141
+ share: 100,
142
+ state: "active"
143
+ }],
144
+ filters: [{
145
+ name: "sub_id_15",
146
+ mode: "accept",
147
+ payload: [offerId]
148
+ }],
149
+ }
150
+ }
151
+
152
+ async function addOfferToKeitaro(offer: IOffer, affiliateId: number, link: string, avoidGroup?: number, groupId?: number) {
153
+ // TODO look if offer already exists by offer.name
154
+ let allOffers = await getAllOffers()
155
+ let identicalOffer = allOffers.find((o) => { return o.name.includes(offer.name) })
156
+
157
+ let keitaroOfferId
158
+ if (identicalOffer) {
159
+ keitaroOfferId = identicalOffer.id
160
+ } else {
161
+ let offerPayload = {
162
+ name: `${offer.caption} ${offer.geo} (${offer.name})`,
163
+ group_id: groupId || 1,
164
+ action_payload: link,
165
+ affiliate_network_id: affiliateId,
166
+ country: [offer.geo],
167
+ action_type: "http",
168
+ offer_type: "external",
169
+ payout_auto: true,
170
+ payout_upsell: true,
171
+ }
172
+
173
+ const { data: keitaroOffer } = await keitaroApi.post(`offers`, offerPayload);
174
+
175
+ keitaroOfferId = keitaroOffer.id
176
+ }
177
+
178
+ let streamPartialPayload = createStreamPartialPayload(keitaroOfferId, offer.caption, offer.name, offer.geo)
179
+
180
+ await createStreamForMatchingCampaigns(streamPartialPayload, offer.name, /◈/, avoidGroup)
181
+ }
182
+
183
+ async function createCampaign(campaignData: Partial<IKeitaroCampaign>): Promise<IKeitaroCampaign> {
184
+ let { data: campaign } = await keitaroApi.post(`/campaigns`, campaignData)
185
+
186
+ return campaign
187
+ }
188
+
189
+ async function getCampaignById(id: number): Promise<IKeitaroCampaign> {
190
+ const { data: campaign } = await keitaroApi.get(`/campaigns/${id}`);
191
+ return campaign
192
+ }
193
+
194
+ export async function upsertStreamToCampaign(campaign: IKeitaroCampaign, stream: Partial<IKeitaroStream>) {
195
+ let streams = await getStreamsByCampaignId(campaign.id)
196
+
197
+ let identicalStream = streams.find((s) => stream.name == s.name)
198
+
199
+ if (identicalStream) {
200
+ console.log(`Found identical! Name: ${stream.name}`)
201
+ await keitaroApi.put(`streams/${identicalStream.id}`, {
202
+ campaign_id: campaign.id,
203
+ ...stream
204
+ });
205
+ } else {
206
+ await keitaroApi.post('streams', {
207
+ campaign_id: campaign.id,
208
+ ...stream
209
+ });
210
+ }
211
+ }
212
+
213
+ async function cloneOWCampaign(app: IApp): Promise<IKeitaroCampaign> {
214
+ let name = `#${app.id} [◈]`
215
+
216
+ let allCampaigns = await getAllCampaigns()
217
+ let matchingCampaign = allCampaigns.filter((c) => new RegExp(`#${app.id}.*◈`).test(c.name))
218
+ if (matchingCampaign.length > 0) return matchingCampaign[0]
219
+
220
+ const { data: campaigns } = await keitaroApi.post(`/campaigns/2673/clone`);
221
+
222
+ if (campaigns.length == 0) throw Error("Campaign cloning falied")
223
+
224
+ let clonedCampaign: IKeitaroCampaign = campaigns[0]
225
+
226
+ let allDomains = await KeitaroService.getDomains(true)
227
+ if (!allDomains) {
228
+ throw Error(`Failed to get all domains list`)
229
+ }
230
+
231
+ const domain = allDomains[Math.floor(Math.random() * allDomains.length)];
232
+
233
+ let payload: Partial<IKeitaroCampaign> = {
234
+ name: name,
235
+ traffic_source_id: TRAFFIC_SOURCE_ID_FLASH_AI,
236
+ domain_id: domain.id,
237
+ parameters: prepareOWCampaignParameters(app)
238
+ }
239
+
240
+ const { data: campaign } = await keitaroApi.put(`/campaigns/${clonedCampaign.id}`, payload)
241
+
242
+ return campaign
243
+ }
244
+
245
+ async function cloneDCampaign(app: IApp): Promise<IKeitaroCampaign> {
246
+ let name = `D #${app.id} (${app.bundle})`
247
+
248
+ let allCampaigns = await getAllCampaigns()
249
+ let matchingCampaign = allCampaigns.filter((c) => c.name.includes(`D #${app.id}`))
250
+ if (matchingCampaign.length > 0) return matchingCampaign[0]
251
+
252
+ const { data: campaigns } = await keitaroApi.post(`/campaigns/2693/clone`);
253
+
254
+ if (campaigns.length == 0) throw Error("Campaign cloning falied")
255
+
256
+ let clonedCampaign: IKeitaroCampaign = campaigns[0]
257
+
258
+ let allDomains = await KeitaroService.getDomains(true)
259
+ if (!allDomains) {
260
+ throw Error(`Failed to get all domains list`)
261
+ }
262
+
263
+ const domain = allDomains[Math.floor(Math.random() * allDomains.length)];
264
+
265
+ let payload: Partial<IKeitaroCampaign> = {
266
+ name: name,
267
+ traffic_source_id: TRAFFIC_SOURCE_ID_FLASH_AI,
268
+ domain_id: domain.id,
269
+ group_id: 93,
270
+ }
271
+
272
+ const { data: campaign } = await keitaroApi.put(`/campaigns/${clonedCampaign.id}`, payload)
273
+
274
+ return campaign
275
+ }
276
+
277
+ async function changeCampaignsGroup(fromId: number, toId: number, exceptForCampaignIds: number[], onlyForCampaignIds?: number[]) {
278
+ let campaigns = await getAllCampaigns()
279
+ const matchingCampaigns = campaigns.filter(campaign => campaign.group_id == fromId
280
+ && exceptForCampaignIds.length > 0 ? !exceptForCampaignIds.includes(campaign.id) : onlyForCampaignIds?.includes(campaign.id))
281
+
282
+ for (let campaign of matchingCampaigns) {
283
+ await updateCampaign(campaign.id, { group_id: toId })
284
+ }
285
+ }
286
+
287
+ // Domain
288
+ async function getDomains(onlyActive?: boolean): Promise<IKeitaroDomain[]> {
289
+ const { data: domains } = await keitaroApi.get<IKeitaroDomain[]>(`/domains`)
290
+ return onlyActive ? domains.filter((d) => d.network_status == "active") : domains
291
+ }
292
+
293
+ async function getProfitForTimeRange(from: number, to: number): Promise<number> {
294
+ let fromString = convertMillisToDate(from)
295
+ let toString = convertMillisToDate(to)
296
+
297
+ let { data: data } = await keitaroApi.post(`/report/build`, {
298
+ range: {
299
+ from: fromString,
300
+ to: toString,
301
+ timezone: 'Europe/Kyiv'
302
+ },
303
+ metrics: ['profit']
304
+ })
305
+
306
+ return data.rows[0].profit
307
+ }
308
+
309
+ // async function getProfitForTodayAndYesterday(): Promise<any> {
310
+ // let timestamps = getTimestampsForTodayAndYesterday()
311
+ // let today = await KeitaroService.getProfitForTimeRange(timestamps.today.start, timestamps.today.end)
312
+ // let yesterday = await KeitaroService.getProfitForTimeRange(timestamps.yesterday.start, timestamps.yesterday.end)
313
+
314
+ // return {
315
+ // today: today,
316
+ // yesterday: yesterday
317
+ // }
318
+ // }
319
+
320
+ async function fixBrokenClickCosts(startDate: string, endDate: string): Promise<void> {
321
+ // Get all campaigns to update
322
+ const campaigns = await getAllCampaigns();
323
+ const campaignIds = campaigns.map(campaign => campaign.id);
324
+
325
+ // Prepare the payload for the API request
326
+ const payload = {
327
+ campaign_ids: campaignIds,
328
+ costs: [{
329
+ start_date: startDate,
330
+ end_date: endDate,
331
+ cost: 0,
332
+ filters: {}
333
+ }],
334
+ timezone: "Europe/Kyiv",
335
+ currency: "USD",
336
+ only_campaign_uniques: 0
337
+ };
338
+
339
+ // Make the API request to update costs
340
+ await keitaroApi.post('/clicks/update_costs', payload);
341
+ }
342
+
343
+ export const KeitaroService = {
344
+ getStreamsByCampaignId, updateCampaign, getAllCampaigns, getAllOffers, cloneStreams, addOfferToKeitaro, getOfferByKeitaroId, getDomains, createCampaign, getCampaignById, upsertStreamToCampaign, cloneOWCampaign,
345
+ updateOffer, changeCampaignsGroup, getProfitForTimeRange,
346
+ // getProfitForTodayAndYesterday,
347
+ cloneDCampaign, findKeitaroOffers, fixBrokenClickCosts
348
+ }