@mhubcloud/tms_core 1.5.0 → 1.6.0
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/index.js +5 -2
- package/package.json +1 -1
- package/publishers/CJ.js +66 -0
- package/publishers/Facebook.js +62 -0
- package/publishers/GoogleAnalytics4.js +74 -0
- package/publishers/UniversalAnalytics.js +73 -0
- package/tests/CJ.js +98 -0
- package/tests/Facebook.js +118 -0
- package/tests/GoogleAnalytics4.js +91 -0
- package/tests/{PianoPublisher.js → Piano.js} +0 -0
- package/tests/UniversalAnalytics.js +94 -0
package/index.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
const utils = require('./lib/utils');
|
|
2
2
|
const DefaultPublisher = require('./lib/DefaultPublisher');
|
|
3
|
-
const Piano = require('./publishers/Piano');
|
|
4
3
|
|
|
5
4
|
module.exports = {
|
|
6
5
|
utils : utils,
|
|
7
6
|
DefaultPublisher : DefaultPublisher,
|
|
8
7
|
publisher : {
|
|
9
|
-
Piano : Piano
|
|
8
|
+
Piano : require('./publishers/Piano'),
|
|
9
|
+
Facebook : require('./publishers/Facebook'),
|
|
10
|
+
GoogleAnalytics4 : require('./publishers/GoogleAnalytics4'),
|
|
11
|
+
CJ : require('./publishers/CJ'),
|
|
12
|
+
UniversalAnalytics : require('./publishers/UniversalAnalytics')
|
|
10
13
|
}
|
|
11
14
|
}
|
package/package.json
CHANGED
package/publishers/CJ.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
const fetch = require('node-fetch');
|
|
2
|
+
const utils = require("../lib/utils");
|
|
3
|
+
const SOURCE = "f_CJAffiliate";
|
|
4
|
+
|
|
5
|
+
module.exports = {
|
|
6
|
+
/**
|
|
7
|
+
* Processed data comming from EventHub to data for further processing
|
|
8
|
+
* @param {Object} data The data comming from EventHub
|
|
9
|
+
* @returns {Object} Data for further processing
|
|
10
|
+
*/
|
|
11
|
+
parse: function parse(data, context) {
|
|
12
|
+
//ConsumerBase.cs:ConsumeOneEventAsync
|
|
13
|
+
data.enqueuedAt = context.test ? 1600000000000 : Date.now();
|
|
14
|
+
return data;
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Publishes data to Facebook
|
|
19
|
+
* @param {{cid: string|number, type: string|number}} config Publisher configuration
|
|
20
|
+
* @param {Object} data Data in publisher-friendly format to be published
|
|
21
|
+
* @returns {*} Data returned by platform, if possible JSON-deserialized (otherwise as string)
|
|
22
|
+
* @param {string} event for which is it triggered
|
|
23
|
+
*/
|
|
24
|
+
publish: async function publish(config, data, event) {
|
|
25
|
+
if(!data.cjevent){
|
|
26
|
+
console.log(`CJ - ${event} - skipped because CJEVENT is missing`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
data = utils.removeUndefined(data);
|
|
31
|
+
const baseUrl = "https://www.kdukvh.com/u";
|
|
32
|
+
let dt = "?cid=" + encodeURI(config.cid);
|
|
33
|
+
dt += "&type=" + encodeURI(config.type);
|
|
34
|
+
for (let prp in data) {
|
|
35
|
+
if (data.hasOwnProperty(prp) && data[prp] !== undefined) {
|
|
36
|
+
dt += "&" + encodeURI(prp) + "=" + encodeURI(data[prp] === null ? "" : data[prp].toString());
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const reqOpts = { method: "get", headers: {} /*Needed by test call*/ };
|
|
40
|
+
const resp = await fetch(baseUrl + dt, reqOpts);
|
|
41
|
+
|
|
42
|
+
if (process.env.PUBLISHER_TESTURL) {
|
|
43
|
+
try {
|
|
44
|
+
utils.prepareTestRequestHeaders(reqOpts.headers, baseUrl + dt, reqOpts, resp);
|
|
45
|
+
await fetch(process.env.PUBLISHER_TESTURL + dt, reqOpts);
|
|
46
|
+
} catch { }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
await utils.handleResponse(resp, event);
|
|
50
|
+
|
|
51
|
+
console.log(`CJ - ${event} - sent`);
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Validates an object against given schema
|
|
56
|
+
* @param {Object} data An object to validate.
|
|
57
|
+
* @param {string} schema Name of the schema. That's name of a file with `.schema.json` extension in `customizable/schemas` subfolder of current publisher folder
|
|
58
|
+
* @returns {boolean} Validation result, true if successful, false if unsuccessfull (in which case more info is written to console)
|
|
59
|
+
*/
|
|
60
|
+
validate: function validate(data, schema) {
|
|
61
|
+
if (!schema) throw new Error("Schema parameters not provided");
|
|
62
|
+
if (schema.indexOf("/") >= 0) throw new Error("Schema must be provided as schema name, not schema path");
|
|
63
|
+
//More validation done by utils.validate
|
|
64
|
+
return utils.validate(data, SOURCE, schema);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
const fetch = require('node-fetch');
|
|
2
|
+
const utils = require("../lib/utils");
|
|
3
|
+
const SOURCE = "f_Facebook";
|
|
4
|
+
|
|
5
|
+
module.exports = {
|
|
6
|
+
/**
|
|
7
|
+
* Processed data comming from EventHub to data for further processing
|
|
8
|
+
* @param {Object} data The data comming from EventHub
|
|
9
|
+
* @returns {Object} Data for further processing
|
|
10
|
+
*/
|
|
11
|
+
parse: function parse(data, context) {
|
|
12
|
+
//ConsumerBase.cs:ConsumeOneEventAsync
|
|
13
|
+
data.enqueuedAt = context.test ? 1600000000000 : Date.now();
|
|
14
|
+
return data;
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Publishes data to Facebook
|
|
19
|
+
* @param {{id: string, access_token: string}} config Publisher configuration
|
|
20
|
+
* @param {Object} data Data in publisher-friendly format to be published
|
|
21
|
+
* @param {string} event for which is it triggered
|
|
22
|
+
*/
|
|
23
|
+
publish: async function publish(config, data, event) {
|
|
24
|
+
data = utils.removeUndefined(data);
|
|
25
|
+
const reqOpts = {
|
|
26
|
+
method: "post",
|
|
27
|
+
body: JSON.stringify({ data: [data] }),
|
|
28
|
+
headers: {
|
|
29
|
+
'Content-Type': 'application/json'
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
//https://graph.facebook.com/v11.0/<id>/events
|
|
33
|
+
const baseUrl = "https://graph.facebook.com/v11.0/" + encodeURIComponent(config.id) + "/events";
|
|
34
|
+
const query = "?access_token=" + encodeURI(config.access_token);
|
|
35
|
+
const url = baseUrl + query;
|
|
36
|
+
const resp = await fetch(url, reqOpts);
|
|
37
|
+
|
|
38
|
+
if (process.env.PUBLISHER_TESTURL) {
|
|
39
|
+
try {
|
|
40
|
+
utils.prepareTestRequestHeaders(reqOpts.headers, url, reqOpts, resp);
|
|
41
|
+
await fetch(process.env.PUBLISHER_TESTURL + query, reqOpts);
|
|
42
|
+
} catch { }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
await utils.handleResponse(resp, event);
|
|
46
|
+
|
|
47
|
+
console.log(`Facebook - ${event} - sent`);
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Validates an object against given schema
|
|
52
|
+
* @param {Object} data An object to validate.
|
|
53
|
+
* @param {string} schema Name of the schema. That's name of a file with `.schema.json` extension in `customizable/schemas` subfolder of current publisher folder
|
|
54
|
+
* @returns {boolean} Validation result, true if successful, false if unsuccessfull (in which case more info is written to console)
|
|
55
|
+
*/
|
|
56
|
+
validate: function validate(data, schema) {
|
|
57
|
+
if (!schema) throw new Error("Schema parameters not provided");
|
|
58
|
+
if (schema.indexOf("/") >= 0) throw new Error("Schema must be provided as schema name, not schema path");
|
|
59
|
+
//More validation done by utils.validate
|
|
60
|
+
return utils.validate(data, SOURCE, schema);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
const fetch = require('node-fetch');
|
|
2
|
+
const utils = require("../lib/utils");
|
|
3
|
+
const SOURCE = "f_GoogleAnalytics4";
|
|
4
|
+
|
|
5
|
+
//https://cloud.google.com/appengine/docs/standard/php7/integrating-with-analytics#server-side_analytics_collection
|
|
6
|
+
|
|
7
|
+
module.exports = {
|
|
8
|
+
/**
|
|
9
|
+
* Processed data comming from EventHub to data for further processing
|
|
10
|
+
* @param {Object} data The data comming from EventHub
|
|
11
|
+
* @returns {object} Data for further processing
|
|
12
|
+
*/
|
|
13
|
+
parse: function parse(data, context) {
|
|
14
|
+
//ConsumerBase.cs:ConsumeOneEventAsync
|
|
15
|
+
data.enqueuedAt = context.test ? 1600000000000 : Date.now();
|
|
16
|
+
return data;
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Publishes data to Google Analytics
|
|
21
|
+
* @param {{tid: string}} config Publisher configuration
|
|
22
|
+
* @param {{action: string, ti: string, [key:string]: string|number|boolean}} data Data in publisher-friendly format to be published
|
|
23
|
+
*/
|
|
24
|
+
publish: async function publish(config, data, event) {
|
|
25
|
+
data = utils.removeUndefined(data);
|
|
26
|
+
data.v = 2;
|
|
27
|
+
data.tid = config.trackingId;
|
|
28
|
+
data.ep = {
|
|
29
|
+
anonymize_ip : true
|
|
30
|
+
};
|
|
31
|
+
let payload = "";
|
|
32
|
+
|
|
33
|
+
for (const prp in data) {
|
|
34
|
+
if (data.hasOwnProperty(prp)) {
|
|
35
|
+
if (payload) payload += "&";
|
|
36
|
+
payload += encodeURI(prp) + "=" + encodeURI(data[prp]);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
var reqOpts = {
|
|
41
|
+
hostname: 'www.google-analytics.com',
|
|
42
|
+
port: 443,
|
|
43
|
+
path: '/g/collect?' + payload,
|
|
44
|
+
method: 'POST'
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
await utils.httpRequest(reqOpts);
|
|
48
|
+
|
|
49
|
+
if (process.env.PUBLISHER_TESTURL) {
|
|
50
|
+
try {
|
|
51
|
+
reqOpts.headers = {};
|
|
52
|
+
utils.prepareTestRequestHeaders(reqOpts.headers, reqOpts.hostname + reqOpts.path , reqOpts);
|
|
53
|
+
await fetch(process.env.PUBLISHER_TESTURL, reqOpts);
|
|
54
|
+
} catch(exception) {
|
|
55
|
+
console.log(exception);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
console.log(`GoogleAnalytics4 - ${event} - sent`);
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Validates an object against given schema
|
|
64
|
+
* @param {Object} data An object to validate.
|
|
65
|
+
* @param {string} schema Name of the schema. That's name of a file with `.schema.json` extension in `customizable/schemas` subfolder of current publisher folder
|
|
66
|
+
* @returns {boolean} Validation result, true if successful, false if unsuccessfull (in which case more info is written to console)
|
|
67
|
+
*/
|
|
68
|
+
validate: function validate(data, schema) {
|
|
69
|
+
if (!schema) throw new Error("Schema parameters not provided");
|
|
70
|
+
if (schema.indexOf("/") >= 0) throw new Error("Schema must be provided as schema name, not schema path");
|
|
71
|
+
//More validation done by utils.validate
|
|
72
|
+
return utils.validate(data, SOURCE, schema);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
const fetch = require('node-fetch');
|
|
2
|
+
const utils = require("../lib/utils");
|
|
3
|
+
const SOURCE = "f_UniversalAnalytics";
|
|
4
|
+
|
|
5
|
+
//https://cloud.google.com/appengine/docs/standard/php7/integrating-with-analytics#server-side_analytics_collection
|
|
6
|
+
|
|
7
|
+
module.exports = {
|
|
8
|
+
/**
|
|
9
|
+
* Processed data comming from EventHub to data for further processing
|
|
10
|
+
* @param {Object} data The data comming from EventHub
|
|
11
|
+
* @returns {object} Data for further processing
|
|
12
|
+
*/
|
|
13
|
+
parse: function parse(data, context) {
|
|
14
|
+
//ConsumerBase.cs:ConsumeOneEventAsync
|
|
15
|
+
data.enqueuedAt = context.test ? 1600000000000 : Date.now();
|
|
16
|
+
return data;
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Publishes data to Google Analytics
|
|
21
|
+
* @param {{tid: string}} config Publisher configuration
|
|
22
|
+
* @param {{action: string, ti: string, [key:string]: string|number|boolean}} data Data in publisher-friendly format to be published
|
|
23
|
+
*/
|
|
24
|
+
publish: async function publish(config, data, event) {
|
|
25
|
+
data = utils.removeUndefined(data);
|
|
26
|
+
//https://developers.google.com/analytics/devguides/collection/protocol/v1/devguide#event
|
|
27
|
+
const url = "https://www.google-analytics.com/collect";
|
|
28
|
+
data.v = 1;
|
|
29
|
+
data.tid = config.trackingId;
|
|
30
|
+
let payload = "";
|
|
31
|
+
|
|
32
|
+
for (const prp in data) {
|
|
33
|
+
if (data.hasOwnProperty(prp)) {
|
|
34
|
+
if (payload) payload += "&";
|
|
35
|
+
payload += encodeURI(prp) + "=" + encodeURI(data[prp]);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const reqOpts = {
|
|
40
|
+
method: "post",
|
|
41
|
+
body: payload,
|
|
42
|
+
headers: {
|
|
43
|
+
'Content-Type': 'application/x-www-form-urlencoded'
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const resp = await fetch(url, reqOpts);
|
|
48
|
+
|
|
49
|
+
if (process.env.PUBLISHER_TESTURL) {
|
|
50
|
+
try {
|
|
51
|
+
utils.prepareTestRequestHeaders(reqOpts.headers, url, reqOpts, resp);
|
|
52
|
+
await fetch(process.env.PUBLISHER_TESTURL, reqOpts);
|
|
53
|
+
} catch { }
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
await utils.handleResponse(resp);
|
|
57
|
+
|
|
58
|
+
console.log(`Universal Analytics - ${event} - sent`);
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Validates an object against given schema
|
|
63
|
+
* @param {Object} data An object to validate.
|
|
64
|
+
* @param {string} schema Name of the schema. That's name of a file with `.schema.json` extension in `customizable/schemas` subfolder of current publisher folder
|
|
65
|
+
* @returns {boolean} Validation result, true if successful, false if unsuccessfull (in which case more info is written to console)
|
|
66
|
+
*/
|
|
67
|
+
validate: function validate(data, schema) {
|
|
68
|
+
if (!schema) throw new Error("Schema parameters not provided");
|
|
69
|
+
if (schema.indexOf("/") >= 0) throw new Error("Schema must be provided as schema name, not schema path");
|
|
70
|
+
//More validation done by utils.validate
|
|
71
|
+
return utils.validate(data, SOURCE, schema);
|
|
72
|
+
}
|
|
73
|
+
};
|
package/tests/CJ.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
const publisher = require("../index.js").publisher.CJ;
|
|
2
|
+
const defaultPublisher = require("../index.js").DefaultPublisher;
|
|
3
|
+
const utils = require("../index.js").utils;
|
|
4
|
+
var assert = require('assert');
|
|
5
|
+
|
|
6
|
+
describe('test CJ publisher', function () {
|
|
7
|
+
it('purchase', async function () {
|
|
8
|
+
var eventHubMessages = [
|
|
9
|
+
{
|
|
10
|
+
"currencyCode": "CZK",
|
|
11
|
+
"event": {
|
|
12
|
+
"region": "MAIN",
|
|
13
|
+
"id": "115169112-4870.1657003407533",
|
|
14
|
+
"code": "purchase"
|
|
15
|
+
},
|
|
16
|
+
"session": {
|
|
17
|
+
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36",
|
|
18
|
+
"ip": "89.177.126.237",
|
|
19
|
+
"referrer": "https://crossmasters.com/"
|
|
20
|
+
},
|
|
21
|
+
"referrer": "https://crossmasters.com/",
|
|
22
|
+
"permissions": [],
|
|
23
|
+
"identity": {
|
|
24
|
+
"piano": {
|
|
25
|
+
"id": "1657003393413.319297501"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"publisher": {
|
|
29
|
+
"code": "mhubcloud.com",
|
|
30
|
+
"tm": "GTM-N7K9L4X",
|
|
31
|
+
"tmv": "494"
|
|
32
|
+
},
|
|
33
|
+
"$schema": "/mhub/purchase",
|
|
34
|
+
"id": "20162351",
|
|
35
|
+
"revenue": 440,
|
|
36
|
+
"products": [
|
|
37
|
+
{
|
|
38
|
+
"id": "Car",
|
|
39
|
+
"price": 440,
|
|
40
|
+
"quantity": 1
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
"enqueuedAt": 1657003409370,
|
|
44
|
+
"ads": [{"adPlatform":"cjaffiliate","adCodes":{"cjevent":"816f5670dbf52c3dc27a7e849903c327d705ef643993fbab3"},"visitAt":1658392668000}]
|
|
45
|
+
}
|
|
46
|
+
];
|
|
47
|
+
await test(eventHubMessages);
|
|
48
|
+
});
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Test function
|
|
53
|
+
* @param [object] object obsahující nastavení testovací parametry
|
|
54
|
+
*/
|
|
55
|
+
async function test(eventHubMessages) {
|
|
56
|
+
await defaultPublisher(console, eventHubMessages, "CJ", publisher, trigger);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function trigger(data) {
|
|
60
|
+
const publishers = [];
|
|
61
|
+
if (data.event.code === 'purchase') {
|
|
62
|
+
let publisher = CJPurchasePublisher;
|
|
63
|
+
|
|
64
|
+
publisher.register(publishers, { cid: 1, type: 1111111 });
|
|
65
|
+
}
|
|
66
|
+
return publishers;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
class CJPurchasePublisher extends utils.EventPublisherBase {
|
|
70
|
+
/**
|
|
71
|
+
* Converts input data to publishing payload data understood by the publisher
|
|
72
|
+
* @param {Object} data `purchase` event data
|
|
73
|
+
* @returns {Object} Data mapped from incomming Event Hub message to platform payload
|
|
74
|
+
*/
|
|
75
|
+
map(data) {
|
|
76
|
+
const ret = {
|
|
77
|
+
cjevent: utils.extractAdCode(data, 'cjaffiliate', 'cjevent')?.code,
|
|
78
|
+
cust_status: data.user?.ts?.indexOf("customer") >= 0 ? "return" : "new",
|
|
79
|
+
coupon: data.coupon,
|
|
80
|
+
discount: data.localDiscount,
|
|
81
|
+
method: "S2S",
|
|
82
|
+
currency: data.localCurrencyCode,
|
|
83
|
+
oid: data.id
|
|
84
|
+
// eventTime: "" // This parameters is ignored, as the time is determined by the CJ server
|
|
85
|
+
};
|
|
86
|
+
if (data.products instanceof Array) {
|
|
87
|
+
let i = 0;
|
|
88
|
+
for (const product of data.products) {
|
|
89
|
+
i++;
|
|
90
|
+
ret[`item${i}`] = product.id;
|
|
91
|
+
ret[`amt${i}`] = product.localPrice;
|
|
92
|
+
ret[`qty${i}`] = product.quantity;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return ret;
|
|
97
|
+
}
|
|
98
|
+
};
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
const publisher = require("../index.js").publisher.Facebook;
|
|
2
|
+
const defaultPublisher = require("../index.js").DefaultPublisher;
|
|
3
|
+
const utils = require("../index.js").utils;
|
|
4
|
+
var assert = require('assert');
|
|
5
|
+
|
|
6
|
+
describe('test Facebook publisher', function () {
|
|
7
|
+
it('purchase', async function () {
|
|
8
|
+
var eventHubMessages = [
|
|
9
|
+
{
|
|
10
|
+
"currencyCode": "CZK",
|
|
11
|
+
"event": {
|
|
12
|
+
"region": "MAIN",
|
|
13
|
+
"id": "115169112-4870.1657003407533",
|
|
14
|
+
"code": "purchase"
|
|
15
|
+
},
|
|
16
|
+
"session": {
|
|
17
|
+
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36",
|
|
18
|
+
"ip": "89.177.126.237",
|
|
19
|
+
"referrer": "https://crossmasters.com/"
|
|
20
|
+
},
|
|
21
|
+
"referrer": "https://crossmasters.com/",
|
|
22
|
+
"permissions": [],
|
|
23
|
+
"identity": {
|
|
24
|
+
"piano": {
|
|
25
|
+
"id": "1657003393413.319297501"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"publisher": {
|
|
29
|
+
"code": "mhubcloud.com",
|
|
30
|
+
"tm": "GTM-N7K9L4X",
|
|
31
|
+
"tmv": "494"
|
|
32
|
+
},
|
|
33
|
+
"$schema": "/mhub/purchase",
|
|
34
|
+
"id": "20162351",
|
|
35
|
+
"revenue": 440,
|
|
36
|
+
"products": [
|
|
37
|
+
{
|
|
38
|
+
"id": "Car",
|
|
39
|
+
"price": 440,
|
|
40
|
+
"quantity": 1
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
"enqueuedAt": 1657003409370,
|
|
44
|
+
"ads": []
|
|
45
|
+
}
|
|
46
|
+
];
|
|
47
|
+
await test(eventHubMessages);
|
|
48
|
+
});
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Test function
|
|
53
|
+
* @param [object] object obsahující nastavení testovací parametry
|
|
54
|
+
*/
|
|
55
|
+
async function test(eventHubMessages) {
|
|
56
|
+
try{
|
|
57
|
+
await defaultPublisher(console, eventHubMessages, "Facebook", publisher, trigger);
|
|
58
|
+
}catch(err){
|
|
59
|
+
assert.equal(err.toString().indexOf('Error: HTTP Error code: 400, event: purchase, body: {"error":{"message":"Invalid OAuth access token - Cannot parse access token","type":"OAuthException","code":190'), 0);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function trigger(data) {
|
|
64
|
+
const publishers = [];
|
|
65
|
+
let publisher;
|
|
66
|
+
|
|
67
|
+
//Dummy config, replace with your own
|
|
68
|
+
const config = {
|
|
69
|
+
id: "fffff",
|
|
70
|
+
access_token: "zzzz"
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
switch (data.event?.code) {
|
|
74
|
+
case "purchase":
|
|
75
|
+
publisher = FBPurchasePublisher;
|
|
76
|
+
publisher.register(publishers, config);
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
return publishers;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
class FBPurchasePublisher extends utils.EventPublisherBase {
|
|
83
|
+
/**
|
|
84
|
+
* Maps `purchase` event data to Facebook payload
|
|
85
|
+
* @param {Object} data `purchase` event data
|
|
86
|
+
* @returns {Object} Data mapped from incomming Event Hub message to platform payload
|
|
87
|
+
*/
|
|
88
|
+
map(data) {
|
|
89
|
+
return {
|
|
90
|
+
event_name: "Purchase", // Constant
|
|
91
|
+
event_time: Math.floor(data.enqueuedAt / 1000), // convert to seconds
|
|
92
|
+
action_source: "website", // Constant
|
|
93
|
+
event_id: data.id, // e.g. OBJ1248035
|
|
94
|
+
event_source_url: data.location, // e.g. https://eshop.com/checkoutSuccess
|
|
95
|
+
opt_out: false, // Constant
|
|
96
|
+
user_data: {
|
|
97
|
+
client_user_agent: data.session?.userAgent, // e.g. Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit
|
|
98
|
+
fbc: utils.extractAdCode(data, 'facebook', 'fbclid', ad => `fb.1.${ad.visitAt}.${ad.code}`) || undefined, // e.g. fb.1.1623142020900.IwAR3CoXSdAr4nXyoVGo5H72wAiP8BrgPays0hhH1UgxnW_8D7rDhuHgjvvw0_aem_AXjjss7KoC0VSnBGvyUAkPip4VaZV6qytiIx5s8FQrAy5yzamZNRSC_xaCXEeJ8ecyphjuyQ2zbDAMoaIVayYAHxZgFH8TJsMzysJAIikY0How
|
|
99
|
+
fbp: data.identity?.facebook?.id, // e.g. fb.1.1609144040877.1929163682
|
|
100
|
+
client_ip_address: data.session?.ip, // e.g. 31.30.171.18
|
|
101
|
+
em: utils.encodeEmail(data.user?.email)
|
|
102
|
+
},
|
|
103
|
+
custom_data:
|
|
104
|
+
{
|
|
105
|
+
currency: data.currencyCode, // e.g. EUR
|
|
106
|
+
value: data.revenue, // e.g. 142.52
|
|
107
|
+
contents: data.products.map(pr => ({
|
|
108
|
+
id: pr.id, // e.g. PRDCT1248035
|
|
109
|
+
quantity: pr.quantity, // e.g. 1
|
|
110
|
+
item_price: pr.price // e.g. 109
|
|
111
|
+
})),
|
|
112
|
+
content_type: "product", // Constant
|
|
113
|
+
order_id: data.id, // e.g. OBJ1248035
|
|
114
|
+
content_category: "Purchase" // Constant
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
const publisher = require("../index.js").publisher.GoogleAnalytics4;
|
|
2
|
+
const defaultPublisher = require("../index.js").DefaultPublisher;
|
|
3
|
+
const utils = require("../index.js").utils;
|
|
4
|
+
var assert = require('assert');
|
|
5
|
+
|
|
6
|
+
describe('test GoogleAnalytics4 publisher', function () {
|
|
7
|
+
it('purchase', async function () {
|
|
8
|
+
var eventHubMessages = [
|
|
9
|
+
{
|
|
10
|
+
"currencyCode": "CZK",
|
|
11
|
+
"event": {
|
|
12
|
+
"region": "MAIN",
|
|
13
|
+
"id": "115169112-4870.1657003407533",
|
|
14
|
+
"code": "pageview"
|
|
15
|
+
},
|
|
16
|
+
"session": {
|
|
17
|
+
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36",
|
|
18
|
+
"ip": "89.177.126.237",
|
|
19
|
+
"referrer": "https://crossmasters.com/"
|
|
20
|
+
},
|
|
21
|
+
"referrer": "https://crossmasters.com/",
|
|
22
|
+
"permissions": [],
|
|
23
|
+
"identity": {
|
|
24
|
+
"piano": {
|
|
25
|
+
"id": "1657003393413.319297501"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"publisher": {
|
|
29
|
+
"code": "mhubcloud.com",
|
|
30
|
+
"tm": "GTM-N7K9L4X",
|
|
31
|
+
"tmv": "494"
|
|
32
|
+
},
|
|
33
|
+
"$schema": "/mhub/purchase",
|
|
34
|
+
"id": "20162351",
|
|
35
|
+
"revenue": 440,
|
|
36
|
+
"products": [
|
|
37
|
+
{
|
|
38
|
+
"id": "Car",
|
|
39
|
+
"price": 440,
|
|
40
|
+
"quantity": 1
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
"enqueuedAt": 1657003409370,
|
|
44
|
+
"ads": []
|
|
45
|
+
}
|
|
46
|
+
];
|
|
47
|
+
await test(eventHubMessages);
|
|
48
|
+
});
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Test function
|
|
53
|
+
* @param [object] object obsahující nastavení testovací parametry
|
|
54
|
+
*/
|
|
55
|
+
async function test(eventHubMessages) {
|
|
56
|
+
await defaultPublisher(console, eventHubMessages, "GoogleAnalytics4", publisher, trigger);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function trigger(data) {
|
|
60
|
+
const publishers = [];
|
|
61
|
+
const config = {trackingId: "G-xxxxxxxxxxx"};
|
|
62
|
+
|
|
63
|
+
if (data.event?.code === "pageview") {
|
|
64
|
+
const publisher = GAPageviewPublisher;
|
|
65
|
+
publisher.register(publishers, config);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return publishers;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
class GAPageviewPublisher extends utils.EventPublisherBase {
|
|
72
|
+
/**
|
|
73
|
+
* Maps `pageview` event data to GA payload
|
|
74
|
+
*/
|
|
75
|
+
map(data) {
|
|
76
|
+
return {
|
|
77
|
+
//mandatory for all events
|
|
78
|
+
cid: "456", //client id
|
|
79
|
+
en: "eventMhubCloud",//event name
|
|
80
|
+
|
|
81
|
+
//mandatory for pageview
|
|
82
|
+
dl: "/", //URL
|
|
83
|
+
|
|
84
|
+
//optional
|
|
85
|
+
//ul : "en-us",
|
|
86
|
+
//sr: "1536x864", //screan resolution
|
|
87
|
+
//dr: "ccc", //refferer
|
|
88
|
+
//dt: "xx" //page title
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
const publisher = require("../index.js").publisher.UniversalAnalytics;
|
|
2
|
+
const defaultPublisher = require("../index.js").DefaultPublisher;
|
|
3
|
+
const utils = require("../index.js").utils;
|
|
4
|
+
var assert = require('assert');
|
|
5
|
+
|
|
6
|
+
describe('test UniversalAnalytics publisher', function () {
|
|
7
|
+
it('pageview', async function () {
|
|
8
|
+
var eventHubMessages = [
|
|
9
|
+
{
|
|
10
|
+
"currencyCode": "CZK",
|
|
11
|
+
"event": {
|
|
12
|
+
"region": "MAIN",
|
|
13
|
+
"id": "115169112-4870.1657003407533",
|
|
14
|
+
"code": "pageview"
|
|
15
|
+
},
|
|
16
|
+
"session": {
|
|
17
|
+
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36",
|
|
18
|
+
"ip": "89.177.126.237",
|
|
19
|
+
"referrer": "https://crossmasters.com/"
|
|
20
|
+
},
|
|
21
|
+
"referrer": "https://crossmasters.com/",
|
|
22
|
+
"permissions": [],
|
|
23
|
+
"identity": {
|
|
24
|
+
"piano": {
|
|
25
|
+
"id": "1657003393413.319297501"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"publisher": {
|
|
29
|
+
"code": "mhubcloud.com",
|
|
30
|
+
"tm": "GTM-N7K9L4X",
|
|
31
|
+
"tmv": "494"
|
|
32
|
+
},
|
|
33
|
+
"$schema": "/mhub/pageview",
|
|
34
|
+
"enqueuedAt": 1657003409370,
|
|
35
|
+
"ads": []
|
|
36
|
+
}
|
|
37
|
+
];
|
|
38
|
+
await test(eventHubMessages);
|
|
39
|
+
});
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Test function
|
|
44
|
+
* @param [object] object obsahující nastavení testovací parametry
|
|
45
|
+
*/
|
|
46
|
+
async function test(eventHubMessages) {
|
|
47
|
+
await defaultPublisher(console, eventHubMessages, "UniversalAnalytics", publisher, trigger);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function trigger(data) {
|
|
51
|
+
const publishers = [];
|
|
52
|
+
const config = {trackingId: "UA-xxxxxxx-yy"};
|
|
53
|
+
|
|
54
|
+
if (data.event?.code === "pageview") {
|
|
55
|
+
const publisher = GAPageviewPublisher;
|
|
56
|
+
publisher.register(publishers, config);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return publishers;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
class GAPageviewPublisher extends utils.EventPublisherBase {
|
|
63
|
+
/**
|
|
64
|
+
* Maps `pageview` event data to GA payload
|
|
65
|
+
*/
|
|
66
|
+
map(data) {
|
|
67
|
+
/** @type {AdCodeInfo} */
|
|
68
|
+
let gclid = utils.extractAdCode(data, "googleads", "gclid");
|
|
69
|
+
/** @type {AdCodeInfo} */
|
|
70
|
+
let referrer = utils.extractAdCode(data, "referrerPlatform", "referrer");
|
|
71
|
+
/** @type {Ad} */
|
|
72
|
+
let utm = utils.extractAdCode(data, "googleAnalytics", "utm_source", (_, data) => data.adCodes ? data : null); //Only supports new format
|
|
73
|
+
|
|
74
|
+
//https://developers.google.com/analytics/devguides/collection/protocol/v1/devguide#event
|
|
75
|
+
//https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#dr
|
|
76
|
+
return {
|
|
77
|
+
//mandatory for all events
|
|
78
|
+
t : "pageview",
|
|
79
|
+
cid: "456", //TODO
|
|
80
|
+
|
|
81
|
+
//mandatory for pageview
|
|
82
|
+
dp: "/",
|
|
83
|
+
|
|
84
|
+
//Traffic Sources - optional
|
|
85
|
+
//TODO not tested
|
|
86
|
+
cn: utm?.adCodes?.utm_campaign,
|
|
87
|
+
cs: utm?.adCodes?.utm_source,
|
|
88
|
+
cm: utm?.adCodes?.utm_medium,
|
|
89
|
+
cc: utm?.adCodes?.utm_content,
|
|
90
|
+
gclid: gclid?.code,
|
|
91
|
+
dr: referrer?.code
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
};
|