@mhubcloud/tms_core 3.5.1 → 3.6.0-beta.1
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/LICENSE +202 -202
- package/dist/index.js +32 -0
- package/package.json +46 -46
- package/.eslintignore +0 -3
- package/.eslintrc.cjs +0 -87
- package/.prettierignore +0 -3
- package/.prettierrc +0 -10
- package/.vscode/extensions.json +0 -12
- package/.vscode/settings.json +0 -51
- package/index.js +0 -17
- package/releasePlan.md +0 -2
- package/src/broker.ts +0 -182
- package/src/defaultPublisher.ts +0 -144
- package/src/index.ts +0 -30
- package/src/publishers/affiliatePort.ts +0 -69
- package/src/publishers/cj.ts +0 -70
- package/src/publishers/facebook.ts +0 -93
- package/src/publishers/googleAds.ts +0 -193
- package/src/publishers/googleAnalytics4.ts +0 -60
- package/src/publishers/piano.ts +0 -71
- package/src/publishers/universalAnalytics.ts +0 -63
- package/src/types/EventPublisher.ts +0 -13
- package/src/types/EventToLog.ts +0 -5
- package/src/types/PlatformPublisher.ts +0 -20
- package/src/types/ServiceBusMessage.ts +0 -10
- package/src/types/UtilTypes.ts +0 -1
- package/src/types/global.d.ts +0 -3
- package/src/utils/testUtils.ts +0 -18
- package/src/utils/utils.ts +0 -433
- package/tests/AffiliatePort.js +0 -133
- package/tests/CJ.js +0 -161
- package/tests/Facebook.js +0 -128
- package/tests/GoogleAds.js +0 -130
- package/tests/GoogleAnalytics4.js +0 -99
- package/tests/Piano.js +0 -120
- package/tests/UniversalAnalytics.js +0 -107
- package/tsconfig.eslint.json +0 -43
- package/tsconfig.json +0 -26
package/src/utils/utils.ts
DELETED
|
@@ -1,433 +0,0 @@
|
|
|
1
|
-
import * as crypto from 'crypto';
|
|
2
|
-
import { Logger } from '@azure/functions';
|
|
3
|
-
import * as appInsights from 'applicationinsights';
|
|
4
|
-
import {
|
|
5
|
-
SeverityLevel,
|
|
6
|
-
Telemetry,
|
|
7
|
-
} from 'applicationinsights/out/Declarations/Contracts';
|
|
8
|
-
import { EventPublisherBaseClass } from '../types/EventPublisher';
|
|
9
|
-
import { EventToLog } from '../types/EventToLog';
|
|
10
|
-
import { PlatformRequestOptions } from '../types/PlatformPublisher';
|
|
11
|
-
import { TypeSafeObject } from '../types/UtilTypes';
|
|
12
|
-
|
|
13
|
-
let aiClient: appInsights.TelemetryClient | null = null;
|
|
14
|
-
|
|
15
|
-
if (process.env.APPLICATIONINSIGHTS_CONNECTION_STRING) {
|
|
16
|
-
appInsights
|
|
17
|
-
.setup() // Set environment variable APPLICATIONINSIGHTS_CONNECTION_STRING, so setup() can be called w/o parameters
|
|
18
|
-
.setAutoCollectDependencies(false)
|
|
19
|
-
.setAutoCollectConsole(true, false)
|
|
20
|
-
.setSendLiveMetrics(false)
|
|
21
|
-
.setAutoCollectRequests(false)
|
|
22
|
-
.setAutoCollectPerformance(false)
|
|
23
|
-
.setUseDiskRetryCaching(false)
|
|
24
|
-
.start();
|
|
25
|
-
aiClient = appInsights.defaultClient;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Base class for Event Publisher classes
|
|
30
|
-
* Facilitates registration (depracated) and configuration
|
|
31
|
-
*/
|
|
32
|
-
export class EventPublisherBase implements EventPublisherBaseClass {
|
|
33
|
-
config;
|
|
34
|
-
constructor(config: TypeSafeObject) {
|
|
35
|
-
this.config = config;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/** @deprecated Please use a 'new Class(config)' notation. The .register() method will be deleted in future major version
|
|
39
|
-
* Registers a new instance of @see EventPublisherBase -derived class with array of publishers
|
|
40
|
-
* @param {EventPublisher[]} publishers Tha publishers array to register with
|
|
41
|
-
* @param {Object} config Configuration to pass to new instance
|
|
42
|
-
* Call this static method on @see EventPublisherBase -derived class.
|
|
43
|
-
* It will create its instance and pass @param config to its constructor.
|
|
44
|
-
* Than it will add resulting instance of @param publishers.
|
|
45
|
-
*/
|
|
46
|
-
public static register(publishers: unknown[], config: TypeSafeObject) {
|
|
47
|
-
// ? Otestovat zpetnou kompatibilitu
|
|
48
|
-
publishers.push(
|
|
49
|
-
new this(
|
|
50
|
-
config,
|
|
51
|
-
) /* Trick: Creates instance of the specific derived class `register` has been called on */,
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Logs message to Azure Function context and to Application Insights (if configured)
|
|
58
|
-
*/
|
|
59
|
-
export function logMessage(
|
|
60
|
-
level: SeverityLevel,
|
|
61
|
-
message: string,
|
|
62
|
-
properties?: Telemetry['properties'],
|
|
63
|
-
): void {
|
|
64
|
-
console.log(message);
|
|
65
|
-
aiClient?.trackTrace({
|
|
66
|
-
message,
|
|
67
|
-
severity: level,
|
|
68
|
-
properties,
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export function logEvent(
|
|
73
|
-
publisher: string,
|
|
74
|
-
event: string,
|
|
75
|
-
region: string,
|
|
76
|
-
status: number,
|
|
77
|
-
payload: string | undefined,
|
|
78
|
-
id: string,
|
|
79
|
-
): void {
|
|
80
|
-
let message = '';
|
|
81
|
-
|
|
82
|
-
if (status || status === 0) {
|
|
83
|
-
message =
|
|
84
|
-
status >= 200 && status < 300
|
|
85
|
-
? 'Event dispatched to platform'
|
|
86
|
-
: 'Event dispatch failed';
|
|
87
|
-
} else {
|
|
88
|
-
message = 'Event dispatched to platform';
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
let properties: Telemetry['properties'] = {
|
|
92
|
-
publisher,
|
|
93
|
-
event,
|
|
94
|
-
region,
|
|
95
|
-
id,
|
|
96
|
-
status,
|
|
97
|
-
payload,
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
properties = removeUndefined(properties);
|
|
101
|
-
|
|
102
|
-
logMessage(1, message, properties);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Logs exception to Azure Function context and to Application Insights (if configured)
|
|
107
|
-
*/
|
|
108
|
-
export function logException(exception: Error) {
|
|
109
|
-
// log.warn(exception.message);
|
|
110
|
-
aiClient?.trackMetric({
|
|
111
|
-
name: `Error/${exception.name}`,
|
|
112
|
-
value: 1,
|
|
113
|
-
});
|
|
114
|
-
aiClient?.trackException({ exception: exception });
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Creates a deep copy of given object removing any properties or array items with undefined value
|
|
119
|
-
* @param originalValue Object or array to copy. If value is neither array nor object it's returned as passed.
|
|
120
|
-
* @returns Deep copy of @param originalValue (providing array or object has been passed in). Any properties or array item with undefined value are skipped when making the copy, recursively. Returns @param obj untouched if neither array nor object has been passed in.
|
|
121
|
-
*/
|
|
122
|
-
export function removeUndefined(
|
|
123
|
-
originalValue: TypeSafeObject | unknown[],
|
|
124
|
-
): TypeSafeObject | unknown[] {
|
|
125
|
-
// ? Toto bych rad otestoval. Klidne unit testy.
|
|
126
|
-
if (originalValue instanceof Array) {
|
|
127
|
-
return removeUndefinedFromArray(originalValue);
|
|
128
|
-
} else if (originalValue instanceof Object) {
|
|
129
|
-
return removeUndefinedFromObject(originalValue);
|
|
130
|
-
} else {
|
|
131
|
-
return originalValue;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function removeUndefinedFromObject(object: TypeSafeObject) {
|
|
136
|
-
const resultObject: TypeSafeObject = {};
|
|
137
|
-
for (const property in object) {
|
|
138
|
-
if (
|
|
139
|
-
Object.prototype.hasOwnProperty.call(object, property) &&
|
|
140
|
-
object[property] !== undefined
|
|
141
|
-
) {
|
|
142
|
-
resultObject[property] = removeUndefined(
|
|
143
|
-
object[property] as TypeSafeObject | unknown[],
|
|
144
|
-
);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
return resultObject;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function removeUndefinedFromArray(array: unknown[]) {
|
|
151
|
-
const resultArray: unknown[] = [];
|
|
152
|
-
for (const item of array) {
|
|
153
|
-
if (item !== undefined) {
|
|
154
|
-
resultArray.push(removeUndefined(item as TypeSafeObject | unknown[]));
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
return resultArray;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Computes SHA-256 hash of an email string. If email is not a string, undefined is returned
|
|
162
|
-
*/
|
|
163
|
-
export function encodeEmail(email: string) {
|
|
164
|
-
return computeSha256HashFromString(email);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Computes SHA-256 hash of any string. If provided value is not a string, undefined is returned
|
|
169
|
-
*/
|
|
170
|
-
function computeSha256HashFromString(stringToHash: string) {
|
|
171
|
-
if (typeof stringToHash !== 'string') {
|
|
172
|
-
return undefined;
|
|
173
|
-
}
|
|
174
|
-
return crypto
|
|
175
|
-
.createHash('sha256')
|
|
176
|
-
.update(stringToHash.toLowerCase(), 'ascii')
|
|
177
|
-
.digest('hex')
|
|
178
|
-
.toLowerCase();
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
interface Ad {
|
|
182
|
-
adPlatform: string;
|
|
183
|
-
visitAt: number;
|
|
184
|
-
adCodes?: Record<string, string>;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
interface AdCodeInfo {
|
|
188
|
-
code: string;
|
|
189
|
-
visitAt: number;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Extracts ad code from standardly structured event data (in legacy or new format)
|
|
194
|
-
* @param data Event data to extract ad code from. As you can see the `ads` field is accepted in 2 formats the first being legacy and the later being new one.
|
|
195
|
-
* @param adPlatform value of `data.ads.adPlatform` field to filter ad codes by platform (this is for new style data; ignored for legacy data)
|
|
196
|
-
* @param adCode value of `data.ads.adType` field to filter items in `data.ads` by (this is for legacy style data); als used for new style data to identify the main parameter from `data.ads.adCodes` to obtain
|
|
197
|
-
* @param format If this custom function is provided it forats the code returned, so the function does not return object but string formated by this function. But nothing prevents it from returning object if the consumer can hanlde it.
|
|
198
|
-
*/
|
|
199
|
-
export function extractAdCode(
|
|
200
|
-
data: {
|
|
201
|
-
ads: Ad[];
|
|
202
|
-
},
|
|
203
|
-
adPlatform: string,
|
|
204
|
-
adCode: string,
|
|
205
|
-
format: ((code: AdCodeInfo, ad: Ad) => string | null | unknown) | null = null,
|
|
206
|
-
): AdCodeInfo | null | string | unknown {
|
|
207
|
-
// ? Tady se udělalo hodně změn, protože se dal pryč legacy kód. Pro kontrolu je potřebná lepší znalost dat.
|
|
208
|
-
// ? Udelat unit test
|
|
209
|
-
const ad = data.ads
|
|
210
|
-
.filter((x) => {
|
|
211
|
-
return x.adPlatform === adPlatform;
|
|
212
|
-
})
|
|
213
|
-
.sort((a, b) => b.visitAt - a.visitAt)[0];
|
|
214
|
-
if (!ad) {
|
|
215
|
-
return null;
|
|
216
|
-
}
|
|
217
|
-
const code: string | null | undefined = ad.adCodes
|
|
218
|
-
? ad.adCodes[adCode]
|
|
219
|
-
: null;
|
|
220
|
-
if (code) {
|
|
221
|
-
const returnValue: AdCodeInfo = { code: code, visitAt: ad.visitAt };
|
|
222
|
-
if (format) {
|
|
223
|
-
return format(returnValue, ad);
|
|
224
|
-
}
|
|
225
|
-
return returnValue;
|
|
226
|
-
}
|
|
227
|
-
return null;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
export function extractPlatformCodes(
|
|
231
|
-
data: {
|
|
232
|
-
ads: Ad[];
|
|
233
|
-
},
|
|
234
|
-
adPlatform: string,
|
|
235
|
-
) {
|
|
236
|
-
const platformCodes = data.ads
|
|
237
|
-
.filter((x) => {
|
|
238
|
-
return x.adPlatform === adPlatform;
|
|
239
|
-
})
|
|
240
|
-
.sort((a, b) => b.visitAt - a.visitAt)[0];
|
|
241
|
-
if (!platformCodes) {
|
|
242
|
-
return null;
|
|
243
|
-
} else {
|
|
244
|
-
return {
|
|
245
|
-
adCodes: platformCodes.adCodes,
|
|
246
|
-
visitAt: platformCodes.visitAt,
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* Transforms an object to be flat, for instance for GA4
|
|
253
|
-
* @param event Event that is received
|
|
254
|
-
* @param separator Separator that will be used to unnest the structure. The default separator is underscore _
|
|
255
|
-
* @returns
|
|
256
|
-
*/
|
|
257
|
-
export function flatten(
|
|
258
|
-
event: TypeSafeObject,
|
|
259
|
-
separator = '_',
|
|
260
|
-
): TypeSafeObject {
|
|
261
|
-
// ? Tady je pro safety potřeba celou funkci vylepšit
|
|
262
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
263
|
-
return Object.assign(
|
|
264
|
-
{},
|
|
265
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-unsafe-argument
|
|
266
|
-
...(function _flatten(
|
|
267
|
-
o: TypeSafeObject,
|
|
268
|
-
separator: string,
|
|
269
|
-
parent?: string,
|
|
270
|
-
): any {
|
|
271
|
-
return [].concat(
|
|
272
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
273
|
-
...Object.keys(o).map((key) => {
|
|
274
|
-
if (typeof o[key] === 'object' && o[key] !== null) {
|
|
275
|
-
const newParent = parent ? parent + separator + key : key;
|
|
276
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
277
|
-
return _flatten(o[key] as TypeSafeObject, separator, newParent);
|
|
278
|
-
} else {
|
|
279
|
-
const newKey = parent ? parent + separator + key : key;
|
|
280
|
-
return { [newKey]: o[key] };
|
|
281
|
-
}
|
|
282
|
-
}),
|
|
283
|
-
);
|
|
284
|
-
})(event, separator),
|
|
285
|
-
);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* Enhances header before sending test request to secondary target (like Pipedream)
|
|
290
|
-
* @param headers Request header dictionary. This contains the original headers and will be ehnanced.
|
|
291
|
-
* @param origUrl Original URL the request has been sent to
|
|
292
|
-
* @param origRequest The entire original request options
|
|
293
|
-
* @param origResponse Response recievend from original request
|
|
294
|
-
*/
|
|
295
|
-
export function prepareTestRequestHeaders(
|
|
296
|
-
headers: TypeSafeObject,
|
|
297
|
-
origUrl: string,
|
|
298
|
-
origRequest: TypeSafeObject,
|
|
299
|
-
origResponse: Response,
|
|
300
|
-
) {
|
|
301
|
-
headers['x-mhub-orig-url'] = origUrl;
|
|
302
|
-
headers['x-mhub-orig-method'] = origRequest.method;
|
|
303
|
-
headers['x-mhub-orig-response-status-code'] = origResponse.status;
|
|
304
|
-
headers['x-mhub-orig-response-status-message'] = origResponse.statusText;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
interface HandleRequestParams {
|
|
308
|
-
source: string;
|
|
309
|
-
baseUrl: string;
|
|
310
|
-
requestOptions: PlatformRequestOptions;
|
|
311
|
-
query?: string;
|
|
312
|
-
event: EventToLog;
|
|
313
|
-
logger: Logger;
|
|
314
|
-
handlePlatformResponse?: boolean;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
/**
|
|
318
|
-
*
|
|
319
|
-
* @param params
|
|
320
|
-
* @returns
|
|
321
|
-
*/
|
|
322
|
-
|
|
323
|
-
export async function handlePlatformRequest({
|
|
324
|
-
source,
|
|
325
|
-
baseUrl,
|
|
326
|
-
requestOptions,
|
|
327
|
-
query = '',
|
|
328
|
-
event,
|
|
329
|
-
}: HandleRequestParams) {
|
|
330
|
-
if (!baseUrl || baseUrl.length < 3) {
|
|
331
|
-
// ? Mohli bychom zacit delat poradnou kontrolu validity vstupnich paramteru. Idealne pres ZOD
|
|
332
|
-
throw new Error('URL for request was not provided or was not valid');
|
|
333
|
-
}
|
|
334
|
-
const fullUrl = baseUrl + query;
|
|
335
|
-
|
|
336
|
-
const fetchRequestOptions: RequestInit = {
|
|
337
|
-
method: requestOptions.method ?? 'POST',
|
|
338
|
-
body: requestOptions.body ?? undefined,
|
|
339
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
340
|
-
headers: { ...requestOptions.headers },
|
|
341
|
-
};
|
|
342
|
-
|
|
343
|
-
let rawPlatformResponse: Response | undefined;
|
|
344
|
-
|
|
345
|
-
try {
|
|
346
|
-
rawPlatformResponse = await fetch(fullUrl, fetchRequestOptions);
|
|
347
|
-
} catch (e: unknown) {
|
|
348
|
-
logEvent(
|
|
349
|
-
source,
|
|
350
|
-
event.event,
|
|
351
|
-
event.region,
|
|
352
|
-
0,
|
|
353
|
-
requestOptions.body ? JSON.stringify(requestOptions.body) : undefined,
|
|
354
|
-
event.id,
|
|
355
|
-
);
|
|
356
|
-
throw e;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
if (rawPlatformResponse) {
|
|
360
|
-
if (process.env.PUBLISHER_TESTURL) {
|
|
361
|
-
await handleTestRequest({
|
|
362
|
-
fetchRequestOptions,
|
|
363
|
-
fullUrl,
|
|
364
|
-
query,
|
|
365
|
-
rawPlatformResponse,
|
|
366
|
-
});
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
logEvent(
|
|
370
|
-
source,
|
|
371
|
-
event.event,
|
|
372
|
-
event.region,
|
|
373
|
-
rawPlatformResponse.status,
|
|
374
|
-
requestOptions.body ? JSON.stringify(requestOptions.body) : undefined,
|
|
375
|
-
event.id,
|
|
376
|
-
);
|
|
377
|
-
|
|
378
|
-
if (!rawPlatformResponse.ok) {
|
|
379
|
-
throw new Error(
|
|
380
|
-
`HTTP Error code: ${rawPlatformResponse.status}, event: ${
|
|
381
|
-
event.event
|
|
382
|
-
}, region: ${event.region}, body: ${await rawPlatformResponse.text()}`,
|
|
383
|
-
);
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
interface HandleTestRequestParams {
|
|
389
|
-
fetchRequestOptions: RequestInit;
|
|
390
|
-
fullUrl: string;
|
|
391
|
-
query: string | undefined;
|
|
392
|
-
rawPlatformResponse: Response;
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
async function handleTestRequest(params: HandleTestRequestParams) {
|
|
396
|
-
try {
|
|
397
|
-
params.fetchRequestOptions.headers = {
|
|
398
|
-
...params.fetchRequestOptions.headers,
|
|
399
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
400
|
-
'x-mhub-orig-url': params.fullUrl,
|
|
401
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
402
|
-
'x-mhub-orig-method': params.fetchRequestOptions.method ?? '',
|
|
403
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
404
|
-
'x-mhub-orig-response-status-code': `${params.rawPlatformResponse.status}`,
|
|
405
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
406
|
-
'x-mhub-orig-response-status-message':
|
|
407
|
-
params.rawPlatformResponse.statusText,
|
|
408
|
-
};
|
|
409
|
-
await fetch(
|
|
410
|
-
`${process.env.PUBLISHER_TESTURL ?? ''} + ${params.query ?? ''}`,
|
|
411
|
-
params.fetchRequestOptions,
|
|
412
|
-
);
|
|
413
|
-
} catch {
|
|
414
|
-
/* empty */
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
export function formatError(error: Error | Error['message']) {
|
|
419
|
-
let formattedError: Error;
|
|
420
|
-
if (error instanceof Error) {
|
|
421
|
-
formattedError = error;
|
|
422
|
-
if (error.cause) {
|
|
423
|
-
formattedError.message = `${
|
|
424
|
-
error.message
|
|
425
|
-
} Cause: ${error.cause.toString()}`;
|
|
426
|
-
} else {
|
|
427
|
-
formattedError.message = error.message;
|
|
428
|
-
}
|
|
429
|
-
} else {
|
|
430
|
-
formattedError = new Error(error);
|
|
431
|
-
}
|
|
432
|
-
return formattedError;
|
|
433
|
-
}
|
package/tests/AffiliatePort.js
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
const localSettings = require('../local.settings.json').Values;
|
|
2
|
-
process.env = { ...process.env, ...localSettings };
|
|
3
|
-
const publisher = require('../dist/index.js').publisher.AffiliatePort;
|
|
4
|
-
const defaultPublisher = require('../dist/index.js').DefaultPublisher;
|
|
5
|
-
const utils = require('../dist/index.js').utils;
|
|
6
|
-
const testUtils = require('../dist/index.js').testUtils;
|
|
7
|
-
|
|
8
|
-
describe('test AffiliatePort publisher', function () {
|
|
9
|
-
it('purchase', async function () {
|
|
10
|
-
var serviceBusMessage = {
|
|
11
|
-
event: {
|
|
12
|
-
region: 'smarty.cz',
|
|
13
|
-
id: '825333270-1011.1659006863812',
|
|
14
|
-
code: 'purchase',
|
|
15
|
-
},
|
|
16
|
-
user: {
|
|
17
|
-
ts: 'customer.HL',
|
|
18
|
-
email: 'jan.brzobohaty@crossmasters.com',
|
|
19
|
-
id: 'a2992fb8-40ac-4b88-9cf5-7fba02f1f611',
|
|
20
|
-
},
|
|
21
|
-
session: {
|
|
22
|
-
userAgent:
|
|
23
|
-
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.2 Safari/605.1.15',
|
|
24
|
-
ip: '217.195.174.253',
|
|
25
|
-
},
|
|
26
|
-
permissions: [],
|
|
27
|
-
currencyCode: 'CZK',
|
|
28
|
-
publisher: {
|
|
29
|
-
code: 'www.smarty.cz',
|
|
30
|
-
tm: 'GTM-NVNTFG',
|
|
31
|
-
tmv: '193',
|
|
32
|
-
},
|
|
33
|
-
$schema: 'https://schema.measurementhub.net/mhub/2021-12-27/purchase',
|
|
34
|
-
id: '3511111111',
|
|
35
|
-
revenue: 10,
|
|
36
|
-
products: [
|
|
37
|
-
{
|
|
38
|
-
id: '67137',
|
|
39
|
-
price: 10,
|
|
40
|
-
quantity: 1,
|
|
41
|
-
category: 'Playstation',
|
|
42
|
-
masterType: 'Konzole',
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
id: '67137',
|
|
46
|
-
price: 20,
|
|
47
|
-
quantity: 1,
|
|
48
|
-
category: 'Monitor',
|
|
49
|
-
masterType: 'Video',
|
|
50
|
-
},
|
|
51
|
-
],
|
|
52
|
-
location: 'https://www.smarty.cz/checkoutSuccess',
|
|
53
|
-
referrer:
|
|
54
|
-
'https://www.smarty.cz/Order/AddReservation?productId=57873&shopAddressId=24798',
|
|
55
|
-
enqueuedAt: 1659006864038,
|
|
56
|
-
ads: [
|
|
57
|
-
{
|
|
58
|
-
adPlatform: 'affiliateport',
|
|
59
|
-
adCodes: {
|
|
60
|
-
transaction_id: '816f5670dbf52c3dc27a7e849903c327d705ef643993fbab3',
|
|
61
|
-
},
|
|
62
|
-
visitAt: 1658392668000,
|
|
63
|
-
},
|
|
64
|
-
],
|
|
65
|
-
EventProcessedUtcTime: '2022-07-28T11:54:50.2528883Z',
|
|
66
|
-
PartitionId: 0,
|
|
67
|
-
EventEnqueuedUtcTime: '2022-07-28T11:14:24.1170000Z',
|
|
68
|
-
};
|
|
69
|
-
await test(serviceBusMessage);
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Test function
|
|
75
|
-
* @param [object] object obsahující nastavení testovací parametry
|
|
76
|
-
*/
|
|
77
|
-
async function test(serviceBusMessage) {
|
|
78
|
-
await defaultPublisher(
|
|
79
|
-
testUtils.context,
|
|
80
|
-
serviceBusMessage,
|
|
81
|
-
'AffiliatePort',
|
|
82
|
-
publisher,
|
|
83
|
-
trigger,
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// eslint-disable-next-line @typescript-eslint/require-await
|
|
88
|
-
async function trigger(data) {
|
|
89
|
-
const publishers = [];
|
|
90
|
-
let publisher;
|
|
91
|
-
|
|
92
|
-
// Dummy config, replace with your own
|
|
93
|
-
const config = {
|
|
94
|
-
offerId: 123,
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
switch (data.event?.code) {
|
|
98
|
-
case 'purchase':
|
|
99
|
-
publisher = AffiliatePortPurchasePublisher;
|
|
100
|
-
publisher.register(publishers, config);
|
|
101
|
-
break;
|
|
102
|
-
}
|
|
103
|
-
return publishers;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Implements Purchase event publisher for Facebook
|
|
108
|
-
* @implements {EventPublisher<{id: string, access_token: string}>}
|
|
109
|
-
*/
|
|
110
|
-
class AffiliatePortPurchasePublisher extends utils.EventPublisherBase {
|
|
111
|
-
/**
|
|
112
|
-
* Maps `purchase` event data to AffiliatePort payload
|
|
113
|
-
* @param {Object} data `purchase` event data
|
|
114
|
-
* @returns {Object} Data mapped from incoming Service Bus message to platform payload
|
|
115
|
-
*/
|
|
116
|
-
map(data) {
|
|
117
|
-
return {
|
|
118
|
-
orderId: data.id,
|
|
119
|
-
revenue: data.revenue, // should be without VAT and shipping, payment fees
|
|
120
|
-
products: data.products.map((pr) => ({
|
|
121
|
-
quantity: pr.quantity, // e.g. 1
|
|
122
|
-
price: pr.price, // e.g. 109
|
|
123
|
-
category: pr.category.replace(/ /g, '-'), // e.g. Playstation
|
|
124
|
-
masterType: pr.masterType, // e.g. Konzole
|
|
125
|
-
})),
|
|
126
|
-
transactionID: utils.extractAdCode(
|
|
127
|
-
data,
|
|
128
|
-
'affiliateport',
|
|
129
|
-
'transaction_id',
|
|
130
|
-
)?.code, // AffiliatePort identificator taken automatically from URL
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
}
|