ghost 6.0.6 → 6.0.8
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/components/tryghost-i18n-6.0.8.tgz +0 -0
- package/core/built/admin/assets/admin-x-activitypub/admin-x-activitypub.js +2 -2
- package/core/built/admin/assets/admin-x-activitypub/{index-BRzGrD-C.mjs → index-1EXYCtPI.mjs} +26876 -22657
- package/core/built/admin/assets/admin-x-activitypub/{index-Co80faUx.mjs → index-If44c6h0.mjs} +2 -2
- package/core/built/admin/assets/admin-x-settings/{CodeEditorView-B4W7CQcA.mjs → CodeEditorView-CzXlGImM.mjs} +2 -2
- package/core/built/admin/assets/admin-x-settings/admin-x-settings.js +1 -1
- package/core/built/admin/assets/admin-x-settings/{index-Bmm3Xeuw.mjs → index-BgCSf8S1.mjs} +4 -5
- package/core/built/admin/assets/admin-x-settings/{index-CuwMM9FM.mjs → index-D2pIApbM.mjs} +26 -11
- package/core/built/admin/assets/admin-x-settings/{index-jv9DN3ZO.mjs → index-RKA3H0Lh.mjs} +2 -2
- package/core/built/admin/assets/admin-x-settings/{modals-CUGEPPYA.mjs → modals-D0f6kxWg.mjs} +2 -2
- package/core/built/admin/assets/{chunk.524.56bb70d3e8660d34aef1.js → chunk.524.099dcd3975a0e60c5579.js} +6 -6
- package/core/built/admin/assets/{chunk.582.ae0341229e71a85d0b2d.js → chunk.582.6830378a89a17aeedd0b.js} +8 -8
- package/core/built/admin/assets/{ghost-2bcbd118a8ad45fed5401e84a7e87c9a.js → ghost-138bb4718f8b9d666bdd7a2b45330d58.js} +34 -33
- package/core/built/admin/assets/{ghost-2c537ee89c36199137eafc1768fd7de8.css → ghost-a7a53bf80dc45c37ae9c174a0d02a882.css} +1 -1
- package/core/built/admin/assets/{ghost-dark-ad23efc1d702e3643a8ee90d089df5d6.css → ghost-dark-6e0062029f988d8676e87f22d8e7f4a3.css} +1 -1
- package/core/built/admin/assets/posts/posts.js +83336 -82274
- package/core/built/admin/assets/stats/stats.js +26957 -26799
- package/core/built/admin/index.html +4 -4
- package/core/frontend/helpers/ghost_head.js +9 -9
- package/core/frontend/public/ghost-stats.min.js +3 -3
- package/core/frontend/public/member-attribution.min.js +1 -1
- package/core/frontend/src/ghost-stats/ghost-stats.js +18 -4
- package/core/frontend/src/member-attribution/member-attribution.js +28 -18
- package/core/frontend/src/utils/url-attribution.js +53 -40
- package/core/server/api/endpoints/utils/serializers/input/posts.js +7 -5
- package/core/server/data/tinybird/endpoints/api_top_utm_campaigns.pipe +31 -0
- package/core/server/data/tinybird/endpoints/api_top_utm_contents.pipe +31 -0
- package/core/server/data/tinybird/endpoints/api_top_utm_mediums.pipe +31 -0
- package/core/server/data/tinybird/endpoints/api_top_utm_sources.pipe +31 -0
- package/core/server/data/tinybird/endpoints/api_top_utm_terms.pipe +31 -0
- package/core/server/data/tinybird/tests/api_top_utm_campaigns.yaml +108 -0
- package/core/server/data/tinybird/tests/api_top_utm_contents.yaml +108 -0
- package/core/server/data/tinybird/tests/api_top_utm_mediums.yaml +108 -0
- package/core/server/data/tinybird/tests/api_top_utm_sources.yaml +108 -0
- package/core/server/data/tinybird/tests/api_top_utm_terms.yaml +108 -0
- package/core/server/services/lib/magic-link/MagicLink.js +17 -11
- package/core/server/services/members/MembersConfigProvider.js +11 -1
- package/core/server/services/members/SingleUseTokenProvider.js +159 -6
- package/core/server/services/members/api.js +1 -1
- package/core/server/services/members/emails/signin.js +9 -5
- package/core/server/services/members/members-api/controllers/RouterController.js +95 -19
- package/core/server/services/members/members-api/members-api.js +8 -4
- package/core/server/services/members/members-ssr.js +5 -3
- package/core/server/services/members/middleware.js +2 -2
- package/core/server/services/tinybird/TinybirdService.js +6 -1
- package/core/server/services/update-check/UpdateCheckService.js +1 -1
- package/core/server/web/members/app.js +12 -3
- package/core/shared/config/defaults.json +1 -1
- package/core/shared/labs.js +3 -1
- package/package.json +7 -7
- package/tsconfig.tsbuildinfo +1 -1
- package/yarn.lock +380 -104
- package/components/tryghost-i18n-6.0.6.tgz +0 -0
|
@@ -3,63 +3,76 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* @
|
|
9
|
-
* @
|
|
6
|
+
* @typedef {Object} AttributionData
|
|
7
|
+
* @property {string|null} source - Primary attribution source (ref || source || utm_source)
|
|
8
|
+
* @property {string|null} medium - UTM medium parameter
|
|
9
|
+
* @property {string|null} url - Browser's document.referrer
|
|
10
|
+
* @property {string|null} utmSource - UTM source parameter
|
|
11
|
+
* @property {string|null} utmMedium - UTM medium parameter
|
|
12
|
+
* @property {string|null} utmTerm - UTM term/keyword parameter
|
|
13
|
+
* @property {string|null} utmCampaign - UTM campaign parameter
|
|
14
|
+
* @property {string|null} utmContent - UTM content/variant parameter
|
|
10
15
|
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Extracts attribution parameters from URL search params
|
|
19
|
+
* @private
|
|
20
|
+
* @param {URLSearchParams} searchParams - The search params to parse
|
|
21
|
+
* @returns {AttributionData} Parsed attribution data with all UTM parameters
|
|
22
|
+
*/
|
|
23
|
+
function extractParams(searchParams) {
|
|
24
|
+
const refParam = searchParams.get('ref');
|
|
25
|
+
const sourceParam = searchParams.get('source');
|
|
26
|
+
const utmSourceParam = searchParams.get('utm_source');
|
|
27
|
+
const utmMediumParam = searchParams.get('utm_medium');
|
|
28
|
+
const utmTermParam = searchParams.get('utm_term');
|
|
29
|
+
const utmCampaignParam = searchParams.get('utm_campaign');
|
|
30
|
+
const utmContentParam = searchParams.get('utm_content');
|
|
20
31
|
|
|
21
32
|
// Determine primary source
|
|
22
33
|
const referrerSource = refParam || sourceParam || utmSourceParam || null;
|
|
23
34
|
|
|
24
|
-
// Check portal hash if needed
|
|
25
|
-
if (!referrerSource && currentUrl.hash && currentUrl.hash.includes('#/portal')) {
|
|
26
|
-
return parsePortalHash(currentUrl);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
35
|
return {
|
|
30
36
|
source: referrerSource,
|
|
31
37
|
medium: utmMediumParam || null,
|
|
32
|
-
url: window.document.referrer || null
|
|
38
|
+
url: window.document.referrer || null,
|
|
39
|
+
utmSource: utmSourceParam || null,
|
|
40
|
+
utmMedium: utmMediumParam || null,
|
|
41
|
+
utmTerm: utmTermParam || null,
|
|
42
|
+
utmCampaign: utmCampaignParam || null,
|
|
43
|
+
utmContent: utmContentParam || null
|
|
33
44
|
};
|
|
34
45
|
}
|
|
35
46
|
|
|
36
47
|
/**
|
|
37
|
-
* Parses
|
|
48
|
+
* Parses URL parameters to extract complete referrer/attribution data
|
|
38
49
|
*
|
|
39
|
-
* @param {
|
|
40
|
-
* @returns {
|
|
50
|
+
* @param {string} url - The URL to parse (defaults to current URL)
|
|
51
|
+
* @returns {AttributionData} Complete attribution data including all UTM parameters
|
|
41
52
|
*/
|
|
42
|
-
export function
|
|
43
|
-
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
const utmSourceParam = hashUrl.searchParams.get('utm_source');
|
|
47
|
-
const utmMediumParam = hashUrl.searchParams.get('utm_medium');
|
|
53
|
+
export function parseReferrerData(url) {
|
|
54
|
+
// Extract current URL parameters
|
|
55
|
+
const currentUrl = new URL(url || window.location.href);
|
|
56
|
+
let searchParams = currentUrl.searchParams;
|
|
48
57
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
58
|
+
// Handle portal hash URLs - extract params from hash instead
|
|
59
|
+
if (currentUrl.hash && currentUrl.hash.includes('#/portal')) {
|
|
60
|
+
const hashUrl = new URL(currentUrl.href.replace('/#/portal', ''));
|
|
61
|
+
searchParams = hashUrl.searchParams;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return extractParams(searchParams);
|
|
54
65
|
}
|
|
55
66
|
|
|
56
67
|
/**
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
* @
|
|
68
|
+
* Selects the primary referrer value from parsed attribution data
|
|
69
|
+
* Prioritizes: source → medium → url
|
|
70
|
+
* Filters out same-domain referrers
|
|
71
|
+
* @private
|
|
72
|
+
* @param {AttributionData} referrerData - Parsed referrer data
|
|
73
|
+
* @returns {string|null} Primary referrer value or null
|
|
61
74
|
*/
|
|
62
|
-
|
|
75
|
+
function selectPrimaryReferrer(referrerData) {
|
|
63
76
|
const { source, medium, url } = referrerData;
|
|
64
77
|
const finalReferrer = source || medium || url || null;
|
|
65
78
|
|
|
@@ -87,6 +100,6 @@ export function getFinalReferrer(referrerData) {
|
|
|
87
100
|
* @returns {string|null} Final referrer value
|
|
88
101
|
*/
|
|
89
102
|
export function getReferrer(url) {
|
|
90
|
-
const referrerData =
|
|
91
|
-
return
|
|
103
|
+
const referrerData = parseReferrerData(url);
|
|
104
|
+
return selectPrimaryReferrer(referrerData);
|
|
92
105
|
}
|
|
@@ -19,10 +19,10 @@ const messages = {
|
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Selects all allowed columns for the given frame.
|
|
22
|
-
*
|
|
22
|
+
*
|
|
23
23
|
* NOTE: This doesn't stop them from being FETCHED, just returned in the response. This causes
|
|
24
24
|
* the output serializer to remove them from the data object before returning.
|
|
25
|
-
*
|
|
25
|
+
*
|
|
26
26
|
* NOTE: This is only intended for the Content API. We need these fields within Admin API responses.
|
|
27
27
|
*
|
|
28
28
|
* @param {Object} frame - The frame object.
|
|
@@ -37,10 +37,10 @@ function removeSourceFormats(frame) {
|
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
39
|
* Selects all allowed columns for the given frame.
|
|
40
|
-
*
|
|
40
|
+
*
|
|
41
41
|
* This removes the lexical and mobiledoc columns from the query. This is a performance improvement as we never intend
|
|
42
42
|
* to expose those columns in the content API and they are very large datasets to be passing around and de/serializing.
|
|
43
|
-
*
|
|
43
|
+
*
|
|
44
44
|
* NOTE: This is only intended for the Content API. We need these fields within Admin API responses.
|
|
45
45
|
*
|
|
46
46
|
* @param {Object} frame - The frame object.
|
|
@@ -97,7 +97,9 @@ function setDefaultOrder(frame) {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
if (!frame.options.order && !frame.options.autoOrder) {
|
|
100
|
-
|
|
100
|
+
// use id as fallback to ensure consistent ordering across pages when posts
|
|
101
|
+
// have the same published_at timestamp
|
|
102
|
+
frame.options.order = 'published_at desc, id desc';
|
|
101
103
|
}
|
|
102
104
|
}
|
|
103
105
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
TOKEN "stats_page" READ
|
|
2
|
+
|
|
3
|
+
NODE top_utm_campaigns
|
|
4
|
+
SQL >
|
|
5
|
+
%
|
|
6
|
+
select
|
|
7
|
+
case
|
|
8
|
+
when length(source) % 6 = 0 then 'summer_sale_2024'
|
|
9
|
+
when length(source) % 6 = 1 then 'newsletter_weekly'
|
|
10
|
+
when length(source) % 6 = 2 then 'product_launch'
|
|
11
|
+
when length(source) % 6 = 3 then 'holiday_promo'
|
|
12
|
+
when length(source) % 6 = 4 then 'brand_awareness'
|
|
13
|
+
when length(source) % 6 = 5 then 'retention_q4'
|
|
14
|
+
end as utm_campaign,
|
|
15
|
+
count() as visits
|
|
16
|
+
from mv_session_data sd
|
|
17
|
+
inner join filtered_sessions fs
|
|
18
|
+
on fs.session_id = sd.session_id
|
|
19
|
+
where
|
|
20
|
+
site_uuid = {{ String(site_uuid, 'mock_site_uuid', description="Tenant ID", required=True) }}
|
|
21
|
+
{% if defined(date_from) and day_diff(date_from, date_to) == 0 %}
|
|
22
|
+
and toDate(toTimezone(first_pageview, {{String(timezone, 'Etc/UTC', description="Site timezone", required=True)}})) = {{ Date(date_from) }}
|
|
23
|
+
{% else %}
|
|
24
|
+
{% if defined(date_from) %} and toDate(toTimezone(first_pageview, {{String(timezone, 'Etc/UTC', description="Site timezone", required=True)}})) >= {{ Date(date_from) }} {% else %} and toDate(toTimezone(first_pageview, {{String(timezone, 'Etc/UTC', description="Site timezone", required=True)}})) >= timestampAdd(today(), interval -7 day) {% end %}
|
|
25
|
+
{% if defined(date_to) %} and toDate(toTimezone(first_pageview, {{String(timezone, 'Etc/UTC', description="Site timezone", required=True)}})) <= {{ Date(date_to) }} {% else %} and toDate(toTimezone(first_pageview, {{String(timezone, 'Etc/UTC', description="Site timezone", required=True)}})) <= today() {% end %}
|
|
26
|
+
{% end %}
|
|
27
|
+
group by utm_campaign
|
|
28
|
+
order by visits desc
|
|
29
|
+
limit {{ Int32(skip, 0) }},{{ Int32(limit, 50) }}
|
|
30
|
+
|
|
31
|
+
TYPE ENDPOINT
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
TOKEN "stats_page" READ
|
|
2
|
+
|
|
3
|
+
NODE top_utm_content
|
|
4
|
+
SQL >
|
|
5
|
+
%
|
|
6
|
+
select
|
|
7
|
+
case
|
|
8
|
+
when length(source) % 6 = 0 then 'hero-banner'
|
|
9
|
+
when length(source) % 6 = 1 then 'sidebar-cta'
|
|
10
|
+
when length(source) % 6 = 2 then 'footer-link'
|
|
11
|
+
when length(source) % 6 = 3 then 'button-primary'
|
|
12
|
+
when length(source) % 6 = 4 then 'text-link'
|
|
13
|
+
when length(source) % 6 = 5 then 'nav-menu'
|
|
14
|
+
end as utm_content,
|
|
15
|
+
count() as visits
|
|
16
|
+
from mv_session_data sd
|
|
17
|
+
inner join filtered_sessions fs
|
|
18
|
+
on fs.session_id = sd.session_id
|
|
19
|
+
where
|
|
20
|
+
site_uuid = {{ String(site_uuid, 'mock_site_uuid', description="Tenant ID", required=True) }}
|
|
21
|
+
{% if defined(date_from) and day_diff(date_from, date_to) == 0 %}
|
|
22
|
+
and toDate(toTimezone(first_pageview, {{String(timezone, 'Etc/UTC', description="Site timezone", required=True)}})) = {{ Date(date_from) }}
|
|
23
|
+
{% else %}
|
|
24
|
+
{% if defined(date_from) %} and toDate(toTimezone(first_pageview, {{String(timezone, 'Etc/UTC', description="Site timezone", required=True)}})) >= {{ Date(date_from) }} {% else %} and toDate(toTimezone(first_pageview, {{String(timezone, 'Etc/UTC', description="Site timezone", required=True)}})) >= timestampAdd(today(), interval -7 day) {% end %}
|
|
25
|
+
{% if defined(date_to) %} and toDate(toTimezone(first_pageview, {{String(timezone, 'Etc/UTC', description="Site timezone", required=True)}})) <= {{ Date(date_to) }} {% else %} and toDate(toTimezone(first_pageview, {{String(timezone, 'Etc/UTC', description="Site timezone", required=True)}})) <= today() {% end %}
|
|
26
|
+
{% end %}
|
|
27
|
+
group by utm_content
|
|
28
|
+
order by visits desc
|
|
29
|
+
limit {{ Int32(skip, 0) }},{{ Int32(limit, 50) }}
|
|
30
|
+
|
|
31
|
+
TYPE ENDPOINT
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
TOKEN "stats_page" READ
|
|
2
|
+
|
|
3
|
+
NODE top_utm_mediums
|
|
4
|
+
SQL >
|
|
5
|
+
%
|
|
6
|
+
select
|
|
7
|
+
case
|
|
8
|
+
when length(source) % 6 = 0 then 'email'
|
|
9
|
+
when length(source) % 6 = 1 then 'social'
|
|
10
|
+
when length(source) % 6 = 2 then 'cpc'
|
|
11
|
+
when length(source) % 6 = 3 then 'organic'
|
|
12
|
+
when length(source) % 6 = 4 then 'referral'
|
|
13
|
+
when length(source) % 6 = 5 then 'display'
|
|
14
|
+
end as utm_medium,
|
|
15
|
+
count() as visits
|
|
16
|
+
from mv_session_data sd
|
|
17
|
+
inner join filtered_sessions fs
|
|
18
|
+
on fs.session_id = sd.session_id
|
|
19
|
+
where
|
|
20
|
+
site_uuid = {{ String(site_uuid, 'mock_site_uuid', description="Tenant ID", required=True) }}
|
|
21
|
+
{% if defined(date_from) and day_diff(date_from, date_to) == 0 %}
|
|
22
|
+
and toDate(toTimezone(first_pageview, {{String(timezone, 'Etc/UTC', description="Site timezone", required=True)}})) = {{ Date(date_from) }}
|
|
23
|
+
{% else %}
|
|
24
|
+
{% if defined(date_from) %} and toDate(toTimezone(first_pageview, {{String(timezone, 'Etc/UTC', description="Site timezone", required=True)}})) >= {{ Date(date_from) }} {% else %} and toDate(toTimezone(first_pageview, {{String(timezone, 'Etc/UTC', description="Site timezone", required=True)}})) >= timestampAdd(today(), interval -7 day) {% end %}
|
|
25
|
+
{% if defined(date_to) %} and toDate(toTimezone(first_pageview, {{String(timezone, 'Etc/UTC', description="Site timezone", required=True)}})) <= {{ Date(date_to) }} {% else %} and toDate(toTimezone(first_pageview, {{String(timezone, 'Etc/UTC', description="Site timezone", required=True)}})) <= today() {% end %}
|
|
26
|
+
{% end %}
|
|
27
|
+
group by utm_medium
|
|
28
|
+
order by visits desc
|
|
29
|
+
limit {{ Int32(skip, 0) }},{{ Int32(limit, 50) }}
|
|
30
|
+
|
|
31
|
+
TYPE ENDPOINT
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
TOKEN "stats_page" READ
|
|
2
|
+
|
|
3
|
+
NODE top_utm_sources
|
|
4
|
+
SQL >
|
|
5
|
+
%
|
|
6
|
+
select
|
|
7
|
+
case
|
|
8
|
+
when length(source) % 6 = 0 then 'google'
|
|
9
|
+
when length(source) % 6 = 1 then 'facebook'
|
|
10
|
+
when length(source) % 6 = 2 then 'twitter'
|
|
11
|
+
when length(source) % 6 = 3 then 'linkedin'
|
|
12
|
+
when length(source) % 6 = 4 then 'newsletter'
|
|
13
|
+
when length(source) % 6 = 5 then 'instagram'
|
|
14
|
+
end as utm_source,
|
|
15
|
+
count() as visits
|
|
16
|
+
from mv_session_data sd
|
|
17
|
+
inner join filtered_sessions fs
|
|
18
|
+
on fs.session_id = sd.session_id
|
|
19
|
+
where
|
|
20
|
+
site_uuid = {{ String(site_uuid, 'mock_site_uuid', description="Tenant ID", required=True) }}
|
|
21
|
+
{% if defined(date_from) and day_diff(date_from, date_to) == 0 %}
|
|
22
|
+
and toDate(toTimezone(first_pageview, {{String(timezone, 'Etc/UTC', description="Site timezone", required=True)}})) = {{ Date(date_from) }}
|
|
23
|
+
{% else %}
|
|
24
|
+
{% if defined(date_from) %} and toDate(toTimezone(first_pageview, {{String(timezone, 'Etc/UTC', description="Site timezone", required=True)}})) >= {{ Date(date_from) }} {% else %} and toDate(toTimezone(first_pageview, {{String(timezone, 'Etc/UTC', description="Site timezone", required=True)}})) >= timestampAdd(today(), interval -7 day) {% end %}
|
|
25
|
+
{% if defined(date_to) %} and toDate(toTimezone(first_pageview, {{String(timezone, 'Etc/UTC', description="Site timezone", required=True)}})) <= {{ Date(date_to) }} {% else %} and toDate(toTimezone(first_pageview, {{String(timezone, 'Etc/UTC', description="Site timezone", required=True)}})) <= today() {% end %}
|
|
26
|
+
{% end %}
|
|
27
|
+
group by utm_source
|
|
28
|
+
order by visits desc
|
|
29
|
+
limit {{ Int32(skip, 0) }},{{ Int32(limit, 50) }}
|
|
30
|
+
|
|
31
|
+
TYPE ENDPOINT
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
TOKEN "stats_page" READ
|
|
2
|
+
|
|
3
|
+
NODE top_utm_terms
|
|
4
|
+
SQL >
|
|
5
|
+
%
|
|
6
|
+
select
|
|
7
|
+
case
|
|
8
|
+
when length(source) % 6 = 0 then 'ghost cms'
|
|
9
|
+
when length(source) % 6 = 1 then 'headless publishing'
|
|
10
|
+
when length(source) % 6 = 2 then 'content management'
|
|
11
|
+
when length(source) % 6 = 3 then 'newsletter platform'
|
|
12
|
+
when length(source) % 6 = 4 then 'blog software'
|
|
13
|
+
when length(source) % 6 = 5 then 'membership site'
|
|
14
|
+
end as utm_term,
|
|
15
|
+
count() as visits
|
|
16
|
+
from mv_session_data sd
|
|
17
|
+
inner join filtered_sessions fs
|
|
18
|
+
on fs.session_id = sd.session_id
|
|
19
|
+
where
|
|
20
|
+
site_uuid = {{ String(site_uuid, 'mock_site_uuid', description="Tenant ID", required=True) }}
|
|
21
|
+
{% if defined(date_from) and day_diff(date_from, date_to) == 0 %}
|
|
22
|
+
and toDate(toTimezone(first_pageview, {{String(timezone, 'Etc/UTC', description="Site timezone", required=True)}})) = {{ Date(date_from) }}
|
|
23
|
+
{% else %}
|
|
24
|
+
{% if defined(date_from) %} and toDate(toTimezone(first_pageview, {{String(timezone, 'Etc/UTC', description="Site timezone", required=True)}})) >= {{ Date(date_from) }} {% else %} and toDate(toTimezone(first_pageview, {{String(timezone, 'Etc/UTC', description="Site timezone", required=True)}})) >= timestampAdd(today(), interval -7 day) {% end %}
|
|
25
|
+
{% if defined(date_to) %} and toDate(toTimezone(first_pageview, {{String(timezone, 'Etc/UTC', description="Site timezone", required=True)}})) <= {{ Date(date_to) }} {% else %} and toDate(toTimezone(first_pageview, {{String(timezone, 'Etc/UTC', description="Site timezone", required=True)}})) <= today() {% end %}
|
|
26
|
+
{% end %}
|
|
27
|
+
group by utm_term
|
|
28
|
+
order by visits desc
|
|
29
|
+
limit {{ Int32(skip, 0) }},{{ Int32(limit, 50) }}
|
|
30
|
+
|
|
31
|
+
TYPE ENDPOINT
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
|
|
2
|
+
- name: Date range
|
|
3
|
+
description: All fixture data
|
|
4
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC
|
|
5
|
+
expected_result: |
|
|
6
|
+
{"utm_campaign":"summer_sale_2024","visits":6}
|
|
7
|
+
{"utm_campaign":"brand_awareness","visits":3}
|
|
8
|
+
{"utm_campaign":"holiday_promo","visits":3}
|
|
9
|
+
{"utm_campaign":"product_launch","visits":3}
|
|
10
|
+
{"utm_campaign":"retention_q4","visits":1}
|
|
11
|
+
|
|
12
|
+
- name: Filtered by browser - Chrome
|
|
13
|
+
description: Filtered by browser - Chrome
|
|
14
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&browser=chrome
|
|
15
|
+
expected_result: |
|
|
16
|
+
{"utm_campaign":"summer_sale_2024","visits":4}
|
|
17
|
+
{"utm_campaign":"brand_awareness","visits":1}
|
|
18
|
+
{"utm_campaign":"holiday_promo","visits":1}
|
|
19
|
+
{"utm_campaign":"product_launch","visits":1}
|
|
20
|
+
|
|
21
|
+
- name: Filtered by device - desktop
|
|
22
|
+
description: Filtered by device - desktop
|
|
23
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&device=desktop
|
|
24
|
+
expected_result: |
|
|
25
|
+
{"utm_campaign":"summer_sale_2024","visits":6}
|
|
26
|
+
{"utm_campaign":"brand_awareness","visits":3}
|
|
27
|
+
{"utm_campaign":"product_launch","visits":3}
|
|
28
|
+
{"utm_campaign":"holiday_promo","visits":2}
|
|
29
|
+
{"utm_campaign":"retention_q4","visits":1}
|
|
30
|
+
|
|
31
|
+
- name: Filtered by location - UK
|
|
32
|
+
description: Filtered by location - UK
|
|
33
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&location=GB
|
|
34
|
+
expected_result: |
|
|
35
|
+
{"utm_campaign":"summer_sale_2024","visits":3}
|
|
36
|
+
{"utm_campaign":"brand_awareness","visits":2}
|
|
37
|
+
{"utm_campaign":"holiday_promo","visits":2}
|
|
38
|
+
{"utm_campaign":"product_launch","visits":1}
|
|
39
|
+
|
|
40
|
+
- name: Filtered by OS - Windows
|
|
41
|
+
description: Filtered by OS - Windows
|
|
42
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&os=windows
|
|
43
|
+
expected_result: |
|
|
44
|
+
{"utm_campaign":"summer_sale_2024","visits":5}
|
|
45
|
+
{"utm_campaign":"brand_awareness","visits":3}
|
|
46
|
+
{"utm_campaign":"product_launch","visits":3}
|
|
47
|
+
{"utm_campaign":"holiday_promo","visits":2}
|
|
48
|
+
{"utm_campaign":"retention_q4","visits":1}
|
|
49
|
+
|
|
50
|
+
- name: Filtered by pathname - /about/
|
|
51
|
+
description: Filtered by pathname - /about/
|
|
52
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&pathname=%2Fabout%2F
|
|
53
|
+
expected_result: |
|
|
54
|
+
{"utm_campaign":"summer_sale_2024","visits":4}
|
|
55
|
+
{"utm_campaign":"product_launch","visits":2}
|
|
56
|
+
{"utm_campaign":"brand_awareness","visits":1}
|
|
57
|
+
{"utm_campaign":"holiday_promo","visits":1}
|
|
58
|
+
|
|
59
|
+
- name: Filtered by post_uuid - 06b1b0c9-fb53-4a15-a060-3db3fde7b1fc (/about/)
|
|
60
|
+
description: Filtered by post_uuid - 06b1b0c9-fb53-4a15-a060-3db3fde7b1fc (/about/)
|
|
61
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&post_uuid=06b1b0c9-fb53-4a15-a060-3db3fde7b1fc
|
|
62
|
+
expected_result: |
|
|
63
|
+
{"utm_campaign":"summer_sale_2024","visits":4}
|
|
64
|
+
{"utm_campaign":"product_launch","visits":2}
|
|
65
|
+
{"utm_campaign":"brand_awareness","visits":1}
|
|
66
|
+
{"utm_campaign":"holiday_promo","visits":1}
|
|
67
|
+
|
|
68
|
+
- name: Filtered by source - bing.com
|
|
69
|
+
description: Filtered by source - bing.com
|
|
70
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&source=bing.com
|
|
71
|
+
expected_result: |
|
|
72
|
+
{"utm_campaign":"product_launch","visits":2}
|
|
73
|
+
|
|
74
|
+
- name: Filtered by member status - paid
|
|
75
|
+
description: Filtered by member status - paid
|
|
76
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&member_status=paid
|
|
77
|
+
expected_result: |
|
|
78
|
+
{"utm_campaign":"brand_awareness","visits":2}
|
|
79
|
+
{"utm_campaign":"summer_sale_2024","visits":2}
|
|
80
|
+
{"utm_campaign":"product_launch","visits":1}
|
|
81
|
+
|
|
82
|
+
- name: Filtered by member status - undefined
|
|
83
|
+
description: Filtered by member status - undefined
|
|
84
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&member_status=undefined
|
|
85
|
+
expected_result: |
|
|
86
|
+
{"utm_campaign":"holiday_promo","visits":3}
|
|
87
|
+
{"utm_campaign":"brand_awareness","visits":1}
|
|
88
|
+
{"utm_campaign":"summer_sale_2024","visits":1}
|
|
89
|
+
{"utm_campaign":"retention_q4","visits":1}
|
|
90
|
+
|
|
91
|
+
- name: Filtered by timezone - America/Los_Angeles
|
|
92
|
+
description: Filtered by timezone - America/Los_Angeles
|
|
93
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=America/Los_Angeles
|
|
94
|
+
expected_result: |
|
|
95
|
+
{"utm_campaign":"summer_sale_2024","visits":5}
|
|
96
|
+
{"utm_campaign":"brand_awareness","visits":3}
|
|
97
|
+
{"utm_campaign":"holiday_promo","visits":2}
|
|
98
|
+
{"utm_campaign":"product_launch","visits":2}
|
|
99
|
+
{"utm_campaign":"retention_q4","visits":1}
|
|
100
|
+
|
|
101
|
+
- name: Test with multiple filters combined
|
|
102
|
+
description: Test with multiple filters combined
|
|
103
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&device=desktop&browser=firefox
|
|
104
|
+
expected_result: |
|
|
105
|
+
{"utm_campaign":"brand_awareness","visits":2}
|
|
106
|
+
{"utm_campaign":"retention_q4","visits":1}
|
|
107
|
+
{"utm_campaign":"holiday_promo","visits":1}
|
|
108
|
+
{"utm_campaign":"product_launch","visits":1}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
|
|
2
|
+
- name: Date range
|
|
3
|
+
description: All fixture data
|
|
4
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC
|
|
5
|
+
expected_result: |
|
|
6
|
+
{"utm_content":"hero-banner","visits":6}
|
|
7
|
+
{"utm_content":"footer-link","visits":3}
|
|
8
|
+
{"utm_content":"text-link","visits":3}
|
|
9
|
+
{"utm_content":"button-primary","visits":3}
|
|
10
|
+
{"utm_content":"nav-menu","visits":1}
|
|
11
|
+
|
|
12
|
+
- name: Filtered by browser - Chrome
|
|
13
|
+
description: Filtered by browser - Chrome
|
|
14
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&browser=chrome
|
|
15
|
+
expected_result: |
|
|
16
|
+
{"utm_content":"hero-banner","visits":4}
|
|
17
|
+
{"utm_content":"footer-link","visits":1}
|
|
18
|
+
{"utm_content":"text-link","visits":1}
|
|
19
|
+
{"utm_content":"button-primary","visits":1}
|
|
20
|
+
|
|
21
|
+
- name: Filtered by device - desktop
|
|
22
|
+
description: Filtered by device - desktop
|
|
23
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&device=desktop
|
|
24
|
+
expected_result: |
|
|
25
|
+
{"utm_content":"hero-banner","visits":6}
|
|
26
|
+
{"utm_content":"footer-link","visits":3}
|
|
27
|
+
{"utm_content":"text-link","visits":3}
|
|
28
|
+
{"utm_content":"button-primary","visits":2}
|
|
29
|
+
{"utm_content":"nav-menu","visits":1}
|
|
30
|
+
|
|
31
|
+
- name: Filtered by location - UK
|
|
32
|
+
description: Filtered by location - UK
|
|
33
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&location=GB
|
|
34
|
+
expected_result: |
|
|
35
|
+
{"utm_content":"hero-banner","visits":3}
|
|
36
|
+
{"utm_content":"text-link","visits":2}
|
|
37
|
+
{"utm_content":"button-primary","visits":2}
|
|
38
|
+
{"utm_content":"footer-link","visits":1}
|
|
39
|
+
|
|
40
|
+
- name: Filtered by OS - Windows
|
|
41
|
+
description: Filtered by OS - Windows
|
|
42
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&os=windows
|
|
43
|
+
expected_result: |
|
|
44
|
+
{"utm_content":"hero-banner","visits":5}
|
|
45
|
+
{"utm_content":"footer-link","visits":3}
|
|
46
|
+
{"utm_content":"text-link","visits":3}
|
|
47
|
+
{"utm_content":"button-primary","visits":2}
|
|
48
|
+
{"utm_content":"nav-menu","visits":1}
|
|
49
|
+
|
|
50
|
+
- name: Filtered by pathname - /about/
|
|
51
|
+
description: Filtered by pathname - /about/
|
|
52
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&pathname=%2Fabout%2F
|
|
53
|
+
expected_result: |
|
|
54
|
+
{"utm_content":"hero-banner","visits":4}
|
|
55
|
+
{"utm_content":"footer-link","visits":2}
|
|
56
|
+
{"utm_content":"text-link","visits":1}
|
|
57
|
+
{"utm_content":"button-primary","visits":1}
|
|
58
|
+
|
|
59
|
+
- name: Filtered by post_uuid - 06b1b0c9-fb53-4a15-a060-3db3fde7b1fc (/about/)
|
|
60
|
+
description: Filtered by post_uuid - 06b1b0c9-fb53-4a15-a060-3db3fde7b1fc (/about/)
|
|
61
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&post_uuid=06b1b0c9-fb53-4a15-a060-3db3fde7b1fc
|
|
62
|
+
expected_result: |
|
|
63
|
+
{"utm_content":"hero-banner","visits":4}
|
|
64
|
+
{"utm_content":"footer-link","visits":2}
|
|
65
|
+
{"utm_content":"text-link","visits":1}
|
|
66
|
+
{"utm_content":"button-primary","visits":1}
|
|
67
|
+
|
|
68
|
+
- name: Filtered by source - bing.com
|
|
69
|
+
description: Filtered by source - bing.com
|
|
70
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&source=bing.com
|
|
71
|
+
expected_result: |
|
|
72
|
+
{"utm_content":"footer-link","visits":2}
|
|
73
|
+
|
|
74
|
+
- name: Filtered by member status - paid
|
|
75
|
+
description: Filtered by member status - paid
|
|
76
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&member_status=paid
|
|
77
|
+
expected_result: |
|
|
78
|
+
{"utm_content":"text-link","visits":2}
|
|
79
|
+
{"utm_content":"hero-banner","visits":2}
|
|
80
|
+
{"utm_content":"footer-link","visits":1}
|
|
81
|
+
|
|
82
|
+
- name: Filtered by member status - undefined
|
|
83
|
+
description: Filtered by member status - undefined
|
|
84
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&member_status=undefined
|
|
85
|
+
expected_result: |
|
|
86
|
+
{"utm_content":"button-primary","visits":3}
|
|
87
|
+
{"utm_content":"nav-menu","visits":1}
|
|
88
|
+
{"utm_content":"text-link","visits":1}
|
|
89
|
+
{"utm_content":"hero-banner","visits":1}
|
|
90
|
+
|
|
91
|
+
- name: Filtered by timezone - America/Los_Angeles
|
|
92
|
+
description: Filtered by timezone - America/Los_Angeles
|
|
93
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=America/Los_Angeles
|
|
94
|
+
expected_result: |
|
|
95
|
+
{"utm_content":"hero-banner","visits":5}
|
|
96
|
+
{"utm_content":"text-link","visits":3}
|
|
97
|
+
{"utm_content":"footer-link","visits":2}
|
|
98
|
+
{"utm_content":"button-primary","visits":2}
|
|
99
|
+
{"utm_content":"nav-menu","visits":1}
|
|
100
|
+
|
|
101
|
+
- name: Test with multiple filters combined
|
|
102
|
+
description: Test with multiple filters combined
|
|
103
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&device=desktop&browser=firefox
|
|
104
|
+
expected_result: |
|
|
105
|
+
{"utm_content":"text-link","visits":2}
|
|
106
|
+
{"utm_content":"nav-menu","visits":1}
|
|
107
|
+
{"utm_content":"footer-link","visits":1}
|
|
108
|
+
{"utm_content":"button-primary","visits":1}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
|
|
2
|
+
- name: Date range
|
|
3
|
+
description: All fixture data
|
|
4
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC
|
|
5
|
+
expected_result: |
|
|
6
|
+
{"utm_medium":"email","visits":6}
|
|
7
|
+
{"utm_medium":"cpc","visits":3}
|
|
8
|
+
{"utm_medium":"organic","visits":3}
|
|
9
|
+
{"utm_medium":"referral","visits":3}
|
|
10
|
+
{"utm_medium":"display","visits":1}
|
|
11
|
+
|
|
12
|
+
- name: Filtered by browser - Chrome
|
|
13
|
+
description: Filtered by browser - Chrome
|
|
14
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&browser=chrome
|
|
15
|
+
expected_result: |
|
|
16
|
+
{"utm_medium":"email","visits":4}
|
|
17
|
+
{"utm_medium":"cpc","visits":1}
|
|
18
|
+
{"utm_medium":"organic","visits":1}
|
|
19
|
+
{"utm_medium":"referral","visits":1}
|
|
20
|
+
|
|
21
|
+
- name: Filtered by device - desktop
|
|
22
|
+
description: Filtered by device - desktop
|
|
23
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&device=desktop
|
|
24
|
+
expected_result: |
|
|
25
|
+
{"utm_medium":"email","visits":6}
|
|
26
|
+
{"utm_medium":"cpc","visits":3}
|
|
27
|
+
{"utm_medium":"referral","visits":3}
|
|
28
|
+
{"utm_medium":"organic","visits":2}
|
|
29
|
+
{"utm_medium":"display","visits":1}
|
|
30
|
+
|
|
31
|
+
- name: Filtered by location - UK
|
|
32
|
+
description: Filtered by location - UK
|
|
33
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&location=GB
|
|
34
|
+
expected_result: |
|
|
35
|
+
{"utm_medium":"email","visits":3}
|
|
36
|
+
{"utm_medium":"organic","visits":2}
|
|
37
|
+
{"utm_medium":"referral","visits":2}
|
|
38
|
+
{"utm_medium":"cpc","visits":1}
|
|
39
|
+
|
|
40
|
+
- name: Filtered by OS - Windows
|
|
41
|
+
description: Filtered by OS - Windows
|
|
42
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&os=windows
|
|
43
|
+
expected_result: |
|
|
44
|
+
{"utm_medium":"email","visits":5}
|
|
45
|
+
{"utm_medium":"cpc","visits":3}
|
|
46
|
+
{"utm_medium":"referral","visits":3}
|
|
47
|
+
{"utm_medium":"organic","visits":2}
|
|
48
|
+
{"utm_medium":"display","visits":1}
|
|
49
|
+
|
|
50
|
+
- name: Filtered by pathname - /about/
|
|
51
|
+
description: Filtered by pathname - /about/
|
|
52
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&pathname=%2Fabout%2F
|
|
53
|
+
expected_result: |
|
|
54
|
+
{"utm_medium":"email","visits":4}
|
|
55
|
+
{"utm_medium":"cpc","visits":2}
|
|
56
|
+
{"utm_medium":"organic","visits":1}
|
|
57
|
+
{"utm_medium":"referral","visits":1}
|
|
58
|
+
|
|
59
|
+
- name: Filtered by post_uuid - 06b1b0c9-fb53-4a15-a060-3db3fde7b1fc (/about/)
|
|
60
|
+
description: Filtered by post_uuid - 06b1b0c9-fb53-4a15-a060-3db3fde7b1fc (/about/)
|
|
61
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&post_uuid=06b1b0c9-fb53-4a15-a060-3db3fde7b1fc
|
|
62
|
+
expected_result: |
|
|
63
|
+
{"utm_medium":"email","visits":4}
|
|
64
|
+
{"utm_medium":"cpc","visits":2}
|
|
65
|
+
{"utm_medium":"organic","visits":1}
|
|
66
|
+
{"utm_medium":"referral","visits":1}
|
|
67
|
+
|
|
68
|
+
- name: Filtered by source - bing.com
|
|
69
|
+
description: Filtered by source - bing.com
|
|
70
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&source=bing.com
|
|
71
|
+
expected_result: |
|
|
72
|
+
{"utm_medium":"cpc","visits":2}
|
|
73
|
+
|
|
74
|
+
- name: Filtered by member status - paid
|
|
75
|
+
description: Filtered by member status - paid
|
|
76
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&member_status=paid
|
|
77
|
+
expected_result: |
|
|
78
|
+
{"utm_medium":"referral","visits":2}
|
|
79
|
+
{"utm_medium":"email","visits":2}
|
|
80
|
+
{"utm_medium":"cpc","visits":1}
|
|
81
|
+
|
|
82
|
+
- name: Filtered by member status - undefined
|
|
83
|
+
description: Filtered by member status - undefined
|
|
84
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&member_status=undefined
|
|
85
|
+
expected_result: |
|
|
86
|
+
{"utm_medium":"organic","visits":3}
|
|
87
|
+
{"utm_medium":"referral","visits":1}
|
|
88
|
+
{"utm_medium":"display","visits":1}
|
|
89
|
+
{"utm_medium":"email","visits":1}
|
|
90
|
+
|
|
91
|
+
- name: Filtered by timezone - America/Los_Angeles
|
|
92
|
+
description: Filtered by timezone - America/Los_Angeles
|
|
93
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=America/Los_Angeles
|
|
94
|
+
expected_result: |
|
|
95
|
+
{"utm_medium":"email","visits":5}
|
|
96
|
+
{"utm_medium":"referral","visits":3}
|
|
97
|
+
{"utm_medium":"cpc","visits":2}
|
|
98
|
+
{"utm_medium":"organic","visits":2}
|
|
99
|
+
{"utm_medium":"display","visits":1}
|
|
100
|
+
|
|
101
|
+
- name: Test with multiple filters combined
|
|
102
|
+
description: Test with multiple filters combined
|
|
103
|
+
parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&device=desktop&browser=firefox
|
|
104
|
+
expected_result: |
|
|
105
|
+
{"utm_medium":"referral","visits":2}
|
|
106
|
+
{"utm_medium":"cpc","visits":1}
|
|
107
|
+
{"utm_medium":"organic","visits":1}
|
|
108
|
+
{"utm_medium":"display","visits":1}
|