From 191287096598b205708e18658ae6ef3b2f4afe0d Mon Sep 17 00:00:00 2001 From: Denis Golubovskiy Date: Fri, 27 Dec 2024 14:13:54 +0100 Subject: [PATCH] Init --- .prettierrc | 5 + LICENSE | 201 +++++++++++++ README.md | 17 ++ template.js | 225 +++++++++++++++ template.tpl | 797 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1245 insertions(+) create mode 100644 .prettierrc create mode 100644 LICENSE create mode 100644 README.md create mode 100644 template.js create mode 100644 template.tpl diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..0b101a9 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "singleQuote": true, + "printWidth": 120, + "trailingComma": "none" +} \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9e2abf5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2024 Stape + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..3b6d848 --- /dev/null +++ b/README.md @@ -0,0 +1,17 @@ +# Admitad tag for Google Tag Manager Server Side + +There are two types of events that Admitad tag includes: PageView and Conversion. + +- Pageview event stores the Admitad EVENT URL parameter inside the Admitad cookie. +- Conversion event sends a request with the specified conversion event data to Admitad postback URL. + +## How to use the Admitad tag: + +**Pageview** - add the Admitad tag to the pageview event. + +**Conversion events** + + +## Open Source + +Admitad Tag for GTM Server Side is developed and maintained by [Stape Team](https://stape.io/) under the Apache 2.0 license. diff --git a/template.js b/template.js new file mode 100644 index 0000000..295d682 --- /dev/null +++ b/template.js @@ -0,0 +1,225 @@ +const sendHttpRequest = require('sendHttpRequest'); +const setCookie = require('setCookie'); +const parseUrl = require('parseUrl'); +const JSON = require('JSON'); +const getRequestHeader = require('getRequestHeader'); +const encodeUriComponent = require('encodeUriComponent'); +const getCookieValues = require('getCookieValues'); +const getAllEventData = require('getAllEventData'); +const logToConsole = require('logToConsole'); +const getContainerVersion = require('getContainerVersion'); +const makeString = require('makeString'); + +const containerVersion = getContainerVersion(); +const isDebug = containerVersion.debugMode; +const isLoggingEnabled = determinateIsLoggingEnabled(); +const traceId = getRequestHeader('trace-id'); +const eventData = getAllEventData(); + +if (!isConsentGivenOrNotRequired()) { + return data.gtmOnSuccess(); +} + +if (data.type === 'page_view') { + const url = eventData.page_location || getRequestHeader('referer'); + + if (url) { + const value = parseUrl(url).searchParams[data.clickIdParameterName]; + + if (value) { + const options = { + domain: 'auto', + path: '/', + secure: true, + httpOnly: false, + 'max-age': 86400 * 395 + }; + + setCookie('_aid', value, options, false); + } + } +} else { + const requestUrl = getRequestUrls(); + + for (let i = 0; i < requestUrl.length; i++) { + if (requestUrl[i]) { + sendRequest(requestUrl[i]); + } + } +} + +data.gtmOnSuccess(); + +function sendRequest(requestUrl) { + if (isLoggingEnabled) { + logToConsole( + JSON.stringify({ + Name: 'Admitad', + Type: 'Request', + TraceId: traceId, + EventName: 'Conversion', + RequestMethod: 'GET', + RequestUrl: requestUrl + }) + ); + } + + sendHttpRequest( + requestUrl, + (statusCode, headers, body) => { + if (isLoggingEnabled) { + logToConsole( + JSON.stringify({ + Name: 'Admitad', + Type: 'Response', + TraceId: traceId, + EventName: 'Conversion', + ResponseStatusCode: statusCode, + ResponseHeaders: headers, + ResponseBody: body + }) + ); + } + }, + { method: 'GET' } + ); +} + +function getRequestUrls() { + let requestUrl = 'https://ad.admitad.com/r?postback=1'; + + requestUrl = requestUrl + '&campaign_code=' + enc(data.campaignCode); + requestUrl = requestUrl + '&postback_key=' + enc(data.postbackKey); + requestUrl = requestUrl + '&action_code=' + enc(data.actionCode); + requestUrl = requestUrl + '&tariff_code=' + enc(data.tariffCode); + requestUrl = requestUrl + '&payment_type=' + enc(data.paymentType); + + const orderId = data.orderId || eventData.orderId || eventData.order_id || eventData.transaction_id; + if (orderId) { + requestUrl = requestUrl + '&order_id=' + enc(orderId); + } + + const price = data.price || eventData.amount || eventData.value || eventData.price; + if (price) { + requestUrl = requestUrl + '&price=' + enc(price); + } + + const clientId = data.clientId || eventData.external_id; + if (clientId) { + requestUrl = requestUrl + '&client_id=' + enc(clientId); + } + + const currency = data.currencyCode || eventData.currencyCode || eventData.currency; + if (currency) { + requestUrl = requestUrl + '¤cy_code=' + enc(currency); + } + + const city = data.city || eventData.city || eventData.city; + if (city) { + requestUrl = requestUrl + '&city=' + enc(city); + } + + const coupon = data.promocode || eventData.promocode || eventData.coupon; + if (coupon) { + requestUrl = requestUrl + '&promocode=' + enc(coupon); + } + + const cookie = getCookieValues('_aid')[0] || ''; + if (cookie) { + requestUrl = requestUrl + '&uid=' + enc(cookie); + } + + if (data.quantity || data.positionId || data.positionCount || data.productId) { + const quantity = data.quantity || eventData.quantity; + if (quantity) { + requestUrl = requestUrl + '&quantity=' + enc(quantity); + } + + if (data.positionId) { + requestUrl = requestUrl + '&position_id=' + enc(data.positionId); + } + + if (data.positionCount) { + requestUrl = requestUrl + '&position_count=' + enc(data.positionCount); + } + + const productId = data.productId || eventData.productId; + if (productId) { + requestUrl = requestUrl + '&product_id=' + enc(productId); + } + + return [requestUrl]; + } + + + const items = data.items || eventData.items || {}; + + if (!items && !items.length) { + return [requestUrl]; + } + + let requestUrls = []; + + for (let i = 0; i < items.length; i++) { + let item = items[i]; + let itemUrl = requestUrl + '&quantity=' + enc((item.quantity || item.item_quantity)); + + if (item.positionId) { + itemUrl = itemUrl + '&position_id=' + enc((i+1)); + } + + if (item.positionCount) { + itemUrl = itemUrl + '&position_count=' + enc((items.length+1)); + } + + if (item.productId) { + itemUrl = itemUrl + '&product_id=' + enc((item.productId || item.product_id || item.item_id)); + } + + if (sameUrlExists(requestUrls, itemUrl)) { + continue; + } + + requestUrls.push(itemUrl); + } + + return requestUrls; +} + +function sameUrlExists(urls, url) { + for (let i = 0; i < urls.length; i++) { + if (urls[i] === url) { + return true; + } + } + + return false; +} + +function enc(data) { + data = data || ''; + return encodeUriComponent(makeString(data)); +} + +function determinateIsLoggingEnabled() { + if (!data.logType) { + return isDebug; + } + + if (data.logType === 'no') { + return false; + } + + if (data.logType === 'debug') { + return isDebug; + } + + return data.logType === 'always'; +} + +function isConsentGivenOrNotRequired() { + if (data.adStorageConsent !== 'required') return true; + if (eventData.consent_state) return !!eventData.consent_state.ad_storage; + const xGaGcs = eventData['x-ga-gcs'] || ''; // x-ga-gcs is a string like "G110" + return xGaGcs[2] === '1'; +} diff --git a/template.tpl b/template.tpl new file mode 100644 index 0000000..359fabb --- /dev/null +++ b/template.tpl @@ -0,0 +1,797 @@ +___TERMS_OF_SERVICE___ + +By creating or modifying this file you agree to Google Tag Manager's Community +Template Gallery Developer Terms of Service available at +https://developers.google.com/tag-manager/gallery-tos (or such other URL as +Google may provide), as modified from time to time. + + +___INFO___ + +{ + "type": "TAG", + "id": "cvt_temp_public_id", + "version": 1, + "securityGroups": [], + "displayName": "Admitad (Mitgo)", + "brand": { + "id": "brand_dummy", + "displayName": "Custom Template", + "thumbnail": "data:image/png;base64,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" + }, + "description": "Admitad (Mitgo) server to server conversion tracking", + "containerContexts": [ + "SERVER" + ] +} + + +___TEMPLATE_PARAMETERS___ + +[ + { + "type": "RADIO", + "name": "type", + "displayName": "Event Type", + "radioItems": [ + { + "value": "page_view", + "displayValue": "PageView" + }, + { + "value": "conversion", + "displayValue": "Conversion" + } + ], + "simpleValueType": true, + "defaultValue": "page_view", + "help": "\u003cb\u003ePageView\u003c/b\u003e - stores the {admitad_uid} URL parameter inside the _aid cookie\u003cbr\u003e\u003cbr\u003e\n\u003cb\u003eConversion\u003c/b\u003e - Send request with data about the conversion to the Admitad" + }, + { + "type": "TEXT", + "name": "clickIdParameterName", + "displayName": "Url parameter name", + "simpleValueType": true, + "valueValidators": [ + { + "type": "NON_EMPTY" + } + ], + "enablingConditions": [ + { + "paramName": "type", + "paramValue": "page_view", + "type": "EQUALS" + } + ], + "defaultValue": "admitad_uid" + }, + { + "type": "GROUP", + "name": "conversionGroup", + "groupStyle": "NO_ZIPPY", + "subParams": [ + { + "type": "TEXT", + "name": "campaignCode", + "displayName": "Campaign Code", + "simpleValueType": true, + "help": "A variable which is the target action code from your program settings. \u003ca target\u003d\"_blank\" href\u003d\"https://support.mitgo.com/knowledge-base/article/integration-via-postback-request_2#action-code-parameter\"\u003eHow to find an action code.\u003c/a\u003e", + "valueValidators": [ + { + "type": "NON_EMPTY" + } + ] + }, + { + "type": "TEXT", + "name": "postbackKey", + "displayName": "Postback Key", + "simpleValueType": true, + "help": "A constant whose value is defined in the postback request." + }, + { + "type": "TEXT", + "name": "actionCode", + "displayName": "Action Code", + "simpleValueType": true, + "help": "A variable which is the target action code from your program settings. \u003ca target\u003d\"_blank\" href\u003d\"https://support.mitgo.com/knowledge-base/article/integration-via-postback-request_2#action-code-parameter\"\u003eHow to find an action code.\u003c/a\u003e", + "valueValidators": [ + { + "type": "NON_EMPTY" + } + ] + }, + { + "type": "TEXT", + "name": "tariffCode", + "displayName": "Tariff Code", + "simpleValueType": true, + "help": "A variable which is the rate code from your program settings. \u003ca target\u003d\"_blank\" href\u003d\"https://support.mitgo.com/knowledge-base/article/integration-via-postback-request_2#tariff-code-parameter\"\u003eHow to find an tariff code.\u003c/a\u003e", + "defaultValue": 1 + }, + { + "type": "TEXT", + "name": "paymentType", + "displayName": "Payment Type", + "simpleValueType": true, + "help": "A constant with the value \"sale\".", + "defaultValue": "sale" + }, + { + "type": "GROUP", + "name": "overrideParamsGroup", + "displayName": "Parameters Override (Optional)", + "groupStyle": "ZIPPY_CLOSED", + "subParams": [ + { + "type": "TEXT", + "name": "orderId", + "displayName": "Order ID", + "simpleValueType": true, + "help": "Unique alphanumeric Order ID for the transaction or event" + }, + { + "type": "TEXT", + "name": "currencyCode", + "displayName": "Currency Code", + "simpleValueType": true, + "help": "Defined in ISO 4217. Letters only." + }, + { + "type": "TEXT", + "name": "price", + "displayName": "Price", + "simpleValueType": true, + "help": "Use a period as a divider." + }, + { + "type": "TEXT", + "name": "clientId", + "displayName": "Client ID", + "simpleValueType": true, + "help": "Your internal client ID" + }, + { + "type": "TEXT", + "name": "quantity", + "displayName": "Quantity", + "simpleValueType": true + }, + { + "type": "TEXT", + "name": "positionId", + "displayName": "Position Id", + "simpleValueType": true, + "help": "A variable varying from 1 to N, where N \u003d position_count." + }, + { + "type": "TEXT", + "name": "positionCount", + "displayName": "Position Count", + "simpleValueType": true, + "help": "A variable with the value N that depends on what\u0027s in the user\u0027s cart." + }, + { + "type": "TEXT", + "name": "productId", + "displayName": "Product ID", + "simpleValueType": true, + "help": "Product ID that must match the ID from the product feed if you use this tool. \u003ca target\u003d\"_blank\" href\u003d\"https://support.admitad.com/hc/en-us/articles/4405920538897\"\u003e Learn more about the product feed.\u003c/a\u003e" + }, + { + "type": "TEXT", + "name": "countryCode", + "displayName": "Country Code", + "simpleValueType": true, + "help": "Defined in ISO 3166. Letters only." + }, + { + "type": "TEXT", + "name": "city", + "displayName": "City", + "simpleValueType": true, + "help": "Only use this parameter if you have set up geotargeting." + }, + { + "type": "TEXT", + "name": "promocode", + "displayName": "Promocode", + "simpleValueType": true, + "help": "Use this parameter if you need to set up passing personal promo codes." + }, + { + "type": "SELECT", + "name": "items", + "displayName": "Products (Items)", + "macrosInSelect": true, + "selectItems": [], + "simpleValueType": true + } + ], + "help": "By default, all parameters will be parsed from eventData" + } + ], + "enablingConditions": [ + { + "paramName": "type", + "paramValue": "conversion", + "type": "EQUALS" + } + ] + }, + { + "type": "GROUP", + "name": "consentSettingsGroup", + "displayName": "Consent Settings", + "groupStyle": "ZIPPY_CLOSED", + "subParams": [ + { + "type": "RADIO", + "name": "adStorageConsent", + "displayName": "", + "radioItems": [ + { + "value": "optional", + "displayValue": "Send data always" + }, + { + "value": "required", + "displayValue": "Send data in case marketing consent given" + } + ], + "simpleValueType": true, + "defaultValue": "optional" + } + ] + }, + { + "type": "GROUP", + "name": "logsGroup", + "displayName": "Logs Settings", + "groupStyle": "ZIPPY_CLOSED", + "subParams": [ + { + "type": "RADIO", + "name": "logType", + "radioItems": [ + { + "value": "no", + "displayValue": "Do not log" + }, + { + "value": "debug", + "displayValue": "Log to console during debug and preview" + }, + { + "value": "always", + "displayValue": "Always log to console" + } + ], + "simpleValueType": true, + "defaultValue": "debug" + } + ], + "enablingConditions": [ + { + "paramName": "type", + "paramValue": "conversion", + "type": "EQUALS" + } + ] + } +] + + +___SANDBOXED_JS_FOR_SERVER___ + +const sendHttpRequest = require('sendHttpRequest'); +const setCookie = require('setCookie'); +const parseUrl = require('parseUrl'); +const JSON = require('JSON'); +const getRequestHeader = require('getRequestHeader'); +const encodeUriComponent = require('encodeUriComponent'); +const getCookieValues = require('getCookieValues'); +const getAllEventData = require('getAllEventData'); +const logToConsole = require('logToConsole'); +const getContainerVersion = require('getContainerVersion'); +const makeString = require('makeString'); + +const containerVersion = getContainerVersion(); +const isDebug = containerVersion.debugMode; +const isLoggingEnabled = determinateIsLoggingEnabled(); +const traceId = getRequestHeader('trace-id'); +const eventData = getAllEventData(); + +if (!isConsentGivenOrNotRequired()) { + return data.gtmOnSuccess(); +} + +if (data.type === 'page_view') { + const url = eventData.page_location || getRequestHeader('referer'); + + if (url) { + const value = parseUrl(url).searchParams[data.clickIdParameterName]; + + if (value) { + const options = { + domain: 'auto', + path: '/', + secure: true, + httpOnly: false, + 'max-age': 86400 * 395 + }; + + setCookie('_aid', value, options, false); + } + } +} else { + const requestUrl = getRequestUrls(); + + for (let i = 0; i < requestUrl.length; i++) { + if (requestUrl[i]) { + sendRequest(requestUrl[i]); + } + } +} + +data.gtmOnSuccess(); + +function sendRequest(requestUrl) { + if (isLoggingEnabled) { + logToConsole( + JSON.stringify({ + Name: 'Admitad', + Type: 'Request', + TraceId: traceId, + EventName: 'Conversion', + RequestMethod: 'GET', + RequestUrl: requestUrl + }) + ); + } + + sendHttpRequest( + requestUrl, + (statusCode, headers, body) => { + if (isLoggingEnabled) { + logToConsole( + JSON.stringify({ + Name: 'Admitad', + Type: 'Response', + TraceId: traceId, + EventName: 'Conversion', + ResponseStatusCode: statusCode, + ResponseHeaders: headers, + ResponseBody: body + }) + ); + } + }, + { method: 'GET' } + ); +} + +function getRequestUrls() { + let requestUrl = 'https://ad.admitad.com/r?postback=1'; + + requestUrl = requestUrl + '&campaign_code=' + enc(data.campaignCode); + requestUrl = requestUrl + '&postback_key=' + enc(data.postbackKey); + requestUrl = requestUrl + '&action_code=' + enc(data.actionCode); + requestUrl = requestUrl + '&tariff_code=' + enc(data.tariffCode); + requestUrl = requestUrl + '&payment_type=' + enc(data.paymentType); + + const orderId = data.orderId || eventData.orderId || eventData.order_id || eventData.transaction_id; + if (orderId) { + requestUrl = requestUrl + '&order_id=' + enc(orderId); + } + + const price = data.price || eventData.amount || eventData.value || eventData.price; + if (price) { + requestUrl = requestUrl + '&price=' + enc(price); + } + + const clientId = data.clientId || eventData.external_id; + if (clientId) { + requestUrl = requestUrl + '&client_id=' + enc(clientId); + } + + const currency = data.currencyCode || eventData.currencyCode || eventData.currency; + if (currency) { + requestUrl = requestUrl + '¤cy_code=' + enc(currency); + } + + const city = data.city || eventData.city || eventData.city; + if (city) { + requestUrl = requestUrl + '&city=' + enc(city); + } + + const coupon = data.promocode || eventData.promocode || eventData.coupon; + if (coupon) { + requestUrl = requestUrl + '&promocode=' + enc(coupon); + } + + const cookie = getCookieValues('_aid')[0] || ''; + if (cookie) { + requestUrl = requestUrl + '&uid=' + enc(cookie); + } + + if (data.quantity || data.positionId || data.positionCount || data.productId) { + const quantity = data.quantity || eventData.quantity; + if (quantity) { + requestUrl = requestUrl + '&quantity=' + enc(quantity); + } + + if (data.positionId) { + requestUrl = requestUrl + '&position_id=' + enc(data.positionId); + } + + if (data.positionCount) { + requestUrl = requestUrl + '&position_count=' + enc(data.positionCount); + } + + const productId = data.productId || eventData.productId; + if (productId) { + requestUrl = requestUrl + '&product_id=' + enc(productId); + } + + return [requestUrl]; + } + + + const items = data.items || eventData.items || {}; + + if (!items && !items.length) { + return [requestUrl]; + } + + let requestUrls = []; + + for (let i = 0; i < items.length; i++) { + let item = items[i]; + let itemUrl = requestUrl + '&quantity=' + enc((item.quantity || item.item_quantity)); + + if (item.positionId) { + itemUrl = itemUrl + '&position_id=' + enc((i+1)); + } + + if (item.positionCount) { + itemUrl = itemUrl + '&position_count=' + enc((items.length+1)); + } + + if (item.productId) { + itemUrl = itemUrl + '&product_id=' + enc((item.productId || item.product_id || item.item_id)); + } + + if (sameUrlExists(requestUrls, itemUrl)) { + continue; + } + + requestUrls.push(itemUrl); + } + + return requestUrls; +} + +function sameUrlExists(urls, url) { + for (let i = 0; i < urls.length; i++) { + if (urls[i] === url) { + return true; + } + } + + return false; +} + +function enc(data) { + data = data || ''; + return encodeUriComponent(makeString(data)); +} + +function determinateIsLoggingEnabled() { + if (!data.logType) { + return isDebug; + } + + if (data.logType === 'no') { + return false; + } + + if (data.logType === 'debug') { + return isDebug; + } + + return data.logType === 'always'; +} + +function isConsentGivenOrNotRequired() { + if (data.adStorageConsent !== 'required') return true; + if (eventData.consent_state) return !!eventData.consent_state.ad_storage; + const xGaGcs = eventData['x-ga-gcs'] || ''; // x-ga-gcs is a string like "G110" + return xGaGcs[2] === '1'; +} + + +___SERVER_PERMISSIONS___ + +[ + { + "instance": { + "key": { + "publicId": "read_request", + "versionId": "1" + }, + "param": [ + { + "key": "headerWhitelist", + "value": { + "type": 2, + "listItem": [ + { + "type": 3, + "mapKey": [ + { + "type": 1, + "string": "headerName" + } + ], + "mapValue": [ + { + "type": 1, + "string": "trace-id" + } + ] + }, + { + "type": 3, + "mapKey": [ + { + "type": 1, + "string": "headerName" + } + ], + "mapValue": [ + { + "type": 1, + "string": "referer" + } + ] + } + ] + } + }, + { + "key": "headersAllowed", + "value": { + "type": 8, + "boolean": true + } + }, + { + "key": "requestAccess", + "value": { + "type": 1, + "string": "specific" + } + }, + { + "key": "headerAccess", + "value": { + "type": 1, + "string": "specific" + } + }, + { + "key": "queryParameterAccess", + "value": { + "type": 1, + "string": "any" + } + } + ] + }, + "clientAnnotations": { + "isEditedByUser": true + }, + "isRequired": true + }, + { + "instance": { + "key": { + "publicId": "get_cookies", + "versionId": "1" + }, + "param": [ + { + "key": "cookieAccess", + "value": { + "type": 1, + "string": "specific" + } + }, + { + "key": "cookieNames", + "value": { + "type": 2, + "listItem": [ + { + "type": 1, + "string": "_aid" + } + ] + } + } + ] + }, + "clientAnnotations": { + "isEditedByUser": true + }, + "isRequired": true + }, + { + "instance": { + "key": { + "publicId": "logging", + "versionId": "1" + }, + "param": [ + { + "key": "environments", + "value": { + "type": 1, + "string": "all" + } + } + ] + }, + "clientAnnotations": { + "isEditedByUser": true + }, + "isRequired": true + }, + { + "instance": { + "key": { + "publicId": "read_container_data", + "versionId": "1" + }, + "param": [] + }, + "isRequired": true + }, + { + "instance": { + "key": { + "publicId": "set_cookies", + "versionId": "1" + }, + "param": [ + { + "key": "allowedCookies", + "value": { + "type": 2, + "listItem": [ + { + "type": 3, + "mapKey": [ + { + "type": 1, + "string": "name" + }, + { + "type": 1, + "string": "domain" + }, + { + "type": 1, + "string": "path" + }, + { + "type": 1, + "string": "secure" + }, + { + "type": 1, + "string": "session" + } + ], + "mapValue": [ + { + "type": 1, + "string": "_aid" + }, + { + "type": 1, + "string": "*" + }, + { + "type": 1, + "string": "*" + }, + { + "type": 1, + "string": "any" + }, + { + "type": 1, + "string": "any" + } + ] + } + ] + } + } + ] + }, + "clientAnnotations": { + "isEditedByUser": true + }, + "isRequired": true + }, + { + "instance": { + "key": { + "publicId": "read_event_data", + "versionId": "1" + }, + "param": [ + { + "key": "eventDataAccess", + "value": { + "type": 1, + "string": "any" + } + } + ] + }, + "clientAnnotations": { + "isEditedByUser": true + }, + "isRequired": true + }, + { + "instance": { + "key": { + "publicId": "send_http", + "versionId": "1" + }, + "param": [ + { + "key": "allowedUrls", + "value": { + "type": 1, + "string": "specific" + } + }, + { + "key": "urls", + "value": { + "type": 2, + "listItem": [ + { + "type": 1, + "string": "https://ad.admitad.com/" + } + ] + } + } + ] + }, + "clientAnnotations": { + "isEditedByUser": true + }, + "isRequired": true + } +] + + +___TESTS___ + +scenarios: [] + + +___NOTES___ + +Created on 12/27/2024, 3:32:15 PM + +