mirror of
https://github.com/plausible/analytics.git
synced 2024-12-23 17:44:43 +03:00
Filter out empty entries when listing stats for UTM props (#3339)
* Filter out empty entries when listing stats for UTM props * Update test fixtures removing noref entries in UTM CSV stat exports * Update external API tests to account for lack of noref records for UTM stats * Filter out entries with empty UTM props from imported GA stats * Remove unreachable GA utm_source dim clause in imported stats logic
This commit is contained in:
parent
9b029c1558
commit
27a11fc5b7
@ -443,9 +443,10 @@ defmodule Plausible.Stats.Breakdown do
|
|||||||
defp do_group_by(q, "visit:utm_medium") do
|
defp do_group_by(q, "visit:utm_medium") do
|
||||||
from(
|
from(
|
||||||
s in q,
|
s in q,
|
||||||
|
where: fragment("not empty(?)", s.utm_medium),
|
||||||
group_by: s.utm_medium,
|
group_by: s.utm_medium,
|
||||||
select_merge: %{
|
select_merge: %{
|
||||||
utm_medium: fragment("if(empty(?), ?, ?)", s.utm_medium, @no_ref, s.utm_medium)
|
utm_medium: s.utm_medium
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
@ -453,9 +454,10 @@ defmodule Plausible.Stats.Breakdown do
|
|||||||
defp do_group_by(q, "visit:utm_source") do
|
defp do_group_by(q, "visit:utm_source") do
|
||||||
from(
|
from(
|
||||||
s in q,
|
s in q,
|
||||||
|
where: fragment("not empty(?)", s.utm_source),
|
||||||
group_by: s.utm_source,
|
group_by: s.utm_source,
|
||||||
select_merge: %{
|
select_merge: %{
|
||||||
utm_source: fragment("if(empty(?), ?, ?)", s.utm_source, @no_ref, s.utm_source)
|
utm_source: s.utm_source
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
@ -463,9 +465,10 @@ defmodule Plausible.Stats.Breakdown do
|
|||||||
defp do_group_by(q, "visit:utm_campaign") do
|
defp do_group_by(q, "visit:utm_campaign") do
|
||||||
from(
|
from(
|
||||||
s in q,
|
s in q,
|
||||||
|
where: fragment("not empty(?)", s.utm_campaign),
|
||||||
group_by: s.utm_campaign,
|
group_by: s.utm_campaign,
|
||||||
select_merge: %{
|
select_merge: %{
|
||||||
utm_campaign: fragment("if(empty(?), ?, ?)", s.utm_campaign, @no_ref, s.utm_campaign)
|
utm_campaign: s.utm_campaign
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
@ -473,9 +476,10 @@ defmodule Plausible.Stats.Breakdown do
|
|||||||
defp do_group_by(q, "visit:utm_content") do
|
defp do_group_by(q, "visit:utm_content") do
|
||||||
from(
|
from(
|
||||||
s in q,
|
s in q,
|
||||||
|
where: fragment("not empty(?)", s.utm_content),
|
||||||
group_by: s.utm_content,
|
group_by: s.utm_content,
|
||||||
select_merge: %{
|
select_merge: %{
|
||||||
utm_content: fragment("if(empty(?), ?, ?)", s.utm_content, @no_ref, s.utm_content)
|
utm_content: s.utm_content
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
@ -483,9 +487,10 @@ defmodule Plausible.Stats.Breakdown do
|
|||||||
defp do_group_by(q, "visit:utm_term") do
|
defp do_group_by(q, "visit:utm_term") do
|
||||||
from(
|
from(
|
||||||
s in q,
|
s in q,
|
||||||
|
where: fragment("not empty(?)", s.utm_term),
|
||||||
group_by: s.utm_term,
|
group_by: s.utm_term,
|
||||||
select_merge: %{
|
select_merge: %{
|
||||||
utm_term: fragment("if(empty(?), ?, ?)", s.utm_term, @no_ref, s.utm_term)
|
utm_term: s.utm_term
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
@ -142,32 +142,30 @@ defmodule Plausible.Stats.Imported do
|
|||||||
|
|
||||||
:utm_medium ->
|
:utm_medium ->
|
||||||
imported_q
|
imported_q
|
||||||
|
|> where([i], fragment("not empty(?)", i.utm_medium))
|
||||||
|> select_merge([i], %{
|
|> select_merge([i], %{
|
||||||
utm_medium: fragment("if(empty(?), ?, ?)", i.utm_medium, @no_ref, i.utm_medium)
|
utm_medium: i.utm_medium
|
||||||
})
|
|
||||||
|
|
||||||
:utm_source ->
|
|
||||||
imported_q
|
|
||||||
|> select_merge([i], %{
|
|
||||||
utm_source: fragment("if(empty(?), ?, ?)", i.utm_source, @no_ref, i.utm_source)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
:utm_campaign ->
|
:utm_campaign ->
|
||||||
imported_q
|
imported_q
|
||||||
|
|> where([i], fragment("not empty(?)", i.utm_campaign))
|
||||||
|> select_merge([i], %{
|
|> select_merge([i], %{
|
||||||
utm_campaign: fragment("if(empty(?), ?, ?)", i.utm_campaign, @no_ref, i.utm_campaign)
|
utm_campaign: i.utm_campaign
|
||||||
})
|
})
|
||||||
|
|
||||||
:utm_term ->
|
:utm_term ->
|
||||||
imported_q
|
imported_q
|
||||||
|
|> where([i], fragment("not empty(?)", i.utm_term))
|
||||||
|> select_merge([i], %{
|
|> select_merge([i], %{
|
||||||
utm_term: fragment("if(empty(?), ?, ?)", i.utm_term, @no_ref, i.utm_term)
|
utm_term: i.utm_term
|
||||||
})
|
})
|
||||||
|
|
||||||
:utm_content ->
|
:utm_content ->
|
||||||
imported_q
|
imported_q
|
||||||
|
|> where([i], fragment("not empty(?)", i.utm_content))
|
||||||
|> select_merge([i], %{
|
|> select_merge([i], %{
|
||||||
utm_content: fragment("if(empty(?), ?, ?)", i.utm_content, @no_ref, i.utm_content)
|
utm_content: i.utm_content
|
||||||
})
|
})
|
||||||
|
|
||||||
:page ->
|
:page ->
|
||||||
|
@ -306,12 +306,6 @@ defmodule Plausible.ImportedTest do
|
|||||||
"name" => "social",
|
"name" => "social",
|
||||||
"visit_duration" => 20,
|
"visit_duration" => 20,
|
||||||
"visitors" => 3
|
"visitors" => 3
|
||||||
},
|
|
||||||
%{
|
|
||||||
"bounce_rate" => 100.0,
|
|
||||||
"name" => "Direct / None",
|
|
||||||
"visit_duration" => 60.0,
|
|
||||||
"visitors" => 1
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
@ -395,12 +389,6 @@ defmodule Plausible.ImportedTest do
|
|||||||
"visitors" => 2,
|
"visitors" => 2,
|
||||||
"bounce_rate" => 100.0,
|
"bounce_rate" => 100.0,
|
||||||
"visit_duration" => 50.0
|
"visit_duration" => 50.0
|
||||||
},
|
|
||||||
%{
|
|
||||||
"bounce_rate" => 0.0,
|
|
||||||
"name" => "Direct / None",
|
|
||||||
"visit_duration" => 100.0,
|
|
||||||
"visitors" => 1
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
@ -485,12 +473,6 @@ defmodule Plausible.ImportedTest do
|
|||||||
"visitors" => 2,
|
"visitors" => 2,
|
||||||
"bounce_rate" => 100.0,
|
"bounce_rate" => 100.0,
|
||||||
"visit_duration" => 50.0
|
"visit_duration" => 50.0
|
||||||
},
|
|
||||||
%{
|
|
||||||
"bounce_rate" => 0.0,
|
|
||||||
"name" => "Direct / None",
|
|
||||||
"visit_duration" => 100.0,
|
|
||||||
"visitors" => 1
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
@ -574,12 +556,6 @@ defmodule Plausible.ImportedTest do
|
|||||||
"visitors" => 2,
|
"visitors" => 2,
|
||||||
"bounce_rate" => 100.0,
|
"bounce_rate" => 100.0,
|
||||||
"visit_duration" => 50.0
|
"visit_duration" => 50.0
|
||||||
},
|
|
||||||
%{
|
|
||||||
"bounce_rate" => 0.0,
|
|
||||||
"name" => "Direct / None",
|
|
||||||
"visit_duration" => 100.0,
|
|
||||||
"visitors" => 1
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
@ -1,2 +1 @@
|
|||||||
name,conversions,conversion_rate
|
name,conversions,conversion_rate
|
||||||
Direct / None,1,33.3
|
|
||||||
|
|
@ -1,2 +1 @@
|
|||||||
name,conversions,conversion_rate
|
name,conversions,conversion_rate
|
||||||
Direct / None,1,33.3
|
|
||||||
|
|
@ -1,2 +1 @@
|
|||||||
name,conversions,conversion_rate
|
name,conversions,conversion_rate
|
||||||
Direct / None,1,33.3
|
|
||||||
|
|
@ -1,2 +1 @@
|
|||||||
name,conversions,conversion_rate
|
name,conversions,conversion_rate
|
||||||
Direct / None,1,33.3
|
|
||||||
|
|
@ -1,2 +1 @@
|
|||||||
name,conversions,conversion_rate
|
name,conversions,conversion_rate
|
||||||
Direct / None,1,33.3
|
|
||||||
|
|
@ -1,2 +1 @@
|
|||||||
name,visitors,bounce_rate,visit_duration
|
name,visitors,bounce_rate,visit_duration
|
||||||
Direct / None,1,0,60
|
|
||||||
|
|
@ -1,2 +1 @@
|
|||||||
name,visitors,bounce_rate,visit_duration
|
name,visitors,bounce_rate,visit_duration
|
||||||
Direct / None,1,0,60
|
|
||||||
|
|
@ -1,2 +1 @@
|
|||||||
name,visitors,bounce_rate,visit_duration
|
name,visitors,bounce_rate,visit_duration
|
||||||
Direct / None,1,0,60
|
|
||||||
|
|
@ -1,2 +1 @@
|
|||||||
name,visitors,bounce_rate,visit_duration
|
name,visitors,bounce_rate,visit_duration
|
||||||
Direct / None,1,0,60
|
|
||||||
|
|
@ -1,2 +1 @@
|
|||||||
name,visitors,bounce_rate,visit_duration
|
name,visitors,bounce_rate,visit_duration
|
||||||
Direct / None,1,0,60
|
|
||||||
|
|
@ -1,3 +1,2 @@
|
|||||||
name,visitors,bounce_rate,visit_duration
|
name,visitors,bounce_rate,visit_duration
|
||||||
Direct / None,3,67,20
|
|
||||||
ads,1,100,0
|
ads,1,100,0
|
||||||
|
|
@ -1,3 +1,2 @@
|
|||||||
name,visitors,bounce_rate,visit_duration
|
name,visitors,bounce_rate,visit_duration
|
||||||
Direct / None,3,67,20
|
|
||||||
content,1,100,0
|
content,1,100,0
|
||||||
|
|
@ -1,3 +1,2 @@
|
|||||||
name,visitors,bounce_rate,visit_duration
|
name,visitors,bounce_rate,visit_duration
|
||||||
Direct / None,3,67,20
|
|
||||||
search,1,100,0
|
search,1,100,0
|
||||||
|
|
@ -1,3 +1,2 @@
|
|||||||
name,visitors,bounce_rate,visit_duration
|
name,visitors,bounce_rate,visit_duration
|
||||||
Direct / None,3,67,20
|
|
||||||
google,1,100,0
|
google,1,100,0
|
||||||
|
|
@ -1,3 +1,2 @@
|
|||||||
name,visitors,bounce_rate,visit_duration
|
name,visitors,bounce_rate,visit_duration
|
||||||
Direct / None,3,67,20
|
|
||||||
term,1,100,0
|
term,1,100,0
|
||||||
|
|
@ -1,3 +1,2 @@
|
|||||||
name,visitors,bounce_rate,visit_duration
|
name,visitors,bounce_rate,visit_duration
|
||||||
Direct / None,3,67,20
|
|
||||||
ads,2,100,0
|
ads,2,100,0
|
||||||
|
|
@ -1,3 +1,2 @@
|
|||||||
name,visitors,bounce_rate,visit_duration
|
name,visitors,bounce_rate,visit_duration
|
||||||
Direct / None,4,75,15
|
|
||||||
content,1,100,0
|
content,1,100,0
|
||||||
|
|
@ -1,3 +1,2 @@
|
|||||||
name,visitors,bounce_rate,visit_duration
|
name,visitors,bounce_rate,visit_duration
|
||||||
Direct / None,4,75,15
|
|
||||||
search,1,100,0
|
search,1,100,0
|
||||||
|
|
@ -1,3 +1,2 @@
|
|||||||
name,visitors,bounce_rate,visit_duration
|
name,visitors,bounce_rate,visit_duration
|
||||||
Direct / None,4,75,15
|
|
||||||
google,1,100,0
|
google,1,100,0
|
||||||
|
|
@ -1,3 +1,2 @@
|
|||||||
name,visitors,bounce_rate,visit_duration
|
name,visitors,bounce_rate,visit_duration
|
||||||
Direct / None,4,75,15
|
|
||||||
term,1,100,0
|
term,1,100,0
|
||||||
|
|
@ -243,8 +243,7 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
|
|||||||
|
|
||||||
assert json_response(conn, 200) == %{
|
assert json_response(conn, 200) == %{
|
||||||
"results" => [
|
"results" => [
|
||||||
%{"utm_medium" => "Search", "visitors" => 2},
|
%{"utm_medium" => "Search", "visitors" => 2}
|
||||||
%{"utm_medium" => "Direct / None", "visitors" => 1}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
@ -275,8 +274,7 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
|
|||||||
|
|
||||||
assert json_response(conn, 200) == %{
|
assert json_response(conn, 200) == %{
|
||||||
"results" => [
|
"results" => [
|
||||||
%{"utm_source" => "Google", "visitors" => 2},
|
%{"utm_source" => "Google", "visitors" => 2}
|
||||||
%{"utm_source" => "Direct / None", "visitors" => 1}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
@ -307,8 +305,7 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
|
|||||||
|
|
||||||
assert json_response(conn, 200) == %{
|
assert json_response(conn, 200) == %{
|
||||||
"results" => [
|
"results" => [
|
||||||
%{"utm_campaign" => "ads", "visitors" => 2},
|
%{"utm_campaign" => "ads", "visitors" => 2}
|
||||||
%{"utm_campaign" => "Direct / None", "visitors" => 1}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
@ -339,8 +336,7 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
|
|||||||
|
|
||||||
assert json_response(conn, 200) == %{
|
assert json_response(conn, 200) == %{
|
||||||
"results" => [
|
"results" => [
|
||||||
%{"utm_content" => "Content1", "visitors" => 2},
|
%{"utm_content" => "Content1", "visitors" => 2}
|
||||||
%{"utm_content" => "Direct / None", "visitors" => 1}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
@ -371,8 +367,7 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
|
|||||||
|
|
||||||
assert json_response(conn, 200) == %{
|
assert json_response(conn, 200) == %{
|
||||||
"results" => [
|
"results" => [
|
||||||
%{"utm_term" => "Term1", "visitors" => 2},
|
%{"utm_term" => "Term1", "visitors" => 2}
|
||||||
%{"utm_term" => "Direct / None", "visitors" => 1}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
@ -568,6 +568,74 @@ defmodule PlausibleWeb.Api.StatsController.SourcesTest do
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "filters out entries without utm_medium present", %{conn: conn, site: site} do
|
||||||
|
populate_stats(site, [
|
||||||
|
build(:pageview,
|
||||||
|
utm_medium: "social",
|
||||||
|
user_id: @user_id,
|
||||||
|
timestamp: ~N[2021-01-01 00:00:00]
|
||||||
|
),
|
||||||
|
build(:pageview,
|
||||||
|
utm_medium: "social",
|
||||||
|
user_id: @user_id,
|
||||||
|
timestamp: ~N[2021-01-01 00:15:00]
|
||||||
|
),
|
||||||
|
build(:pageview,
|
||||||
|
utm_medium: "",
|
||||||
|
timestamp: ~N[2021-01-01 00:00:00]
|
||||||
|
)
|
||||||
|
])
|
||||||
|
|
||||||
|
populate_stats(site, [
|
||||||
|
build(:imported_sources,
|
||||||
|
utm_medium: "social",
|
||||||
|
date: ~D[2021-01-01],
|
||||||
|
visit_duration: 700,
|
||||||
|
bounces: 1,
|
||||||
|
visits: 1,
|
||||||
|
visitors: 1
|
||||||
|
),
|
||||||
|
build(:imported_sources,
|
||||||
|
utm_medium: "",
|
||||||
|
date: ~D[2021-01-01],
|
||||||
|
bounces: 0,
|
||||||
|
visits: 1,
|
||||||
|
visitors: 1,
|
||||||
|
visit_duration: 100
|
||||||
|
)
|
||||||
|
])
|
||||||
|
|
||||||
|
conn =
|
||||||
|
get(
|
||||||
|
conn,
|
||||||
|
"/api/stats/#{site.domain}/utm_mediums?period=day&date=2021-01-01"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert json_response(conn, 200) == [
|
||||||
|
%{
|
||||||
|
"name" => "social",
|
||||||
|
"visitors" => 1,
|
||||||
|
"bounce_rate" => 0,
|
||||||
|
"visit_duration" => 900
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
conn =
|
||||||
|
get(
|
||||||
|
conn,
|
||||||
|
"/api/stats/#{site.domain}/utm_mediums?period=day&date=2021-01-01&with_imported=true"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert json_response(conn, 200) == [
|
||||||
|
%{
|
||||||
|
"name" => "social",
|
||||||
|
"visitors" => 2,
|
||||||
|
"bounce_rate" => 50,
|
||||||
|
"visit_duration" => 800.0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "GET /api/stats/:domain/utm_campaigns" do
|
describe "GET /api/stats/:domain/utm_campaigns" do
|
||||||
@ -656,10 +724,82 @@ defmodule PlausibleWeb.Api.StatsController.SourcesTest do
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "filters out entries without utm_campaign present", %{conn: conn, site: site} do
|
||||||
|
populate_stats(site, [
|
||||||
|
build(:pageview,
|
||||||
|
utm_campaign: "profile",
|
||||||
|
user_id: @user_id,
|
||||||
|
timestamp: ~N[2021-01-01 00:00:00]
|
||||||
|
),
|
||||||
|
build(:pageview,
|
||||||
|
utm_campaign: "profile",
|
||||||
|
user_id: @user_id,
|
||||||
|
timestamp: ~N[2021-01-01 00:15:00]
|
||||||
|
),
|
||||||
|
build(:pageview,
|
||||||
|
utm_campaign: "",
|
||||||
|
timestamp: ~N[2021-01-01 00:00:00]
|
||||||
|
),
|
||||||
|
build(:pageview,
|
||||||
|
utm_campaign: "",
|
||||||
|
timestamp: ~N[2021-01-01 00:00:00]
|
||||||
|
)
|
||||||
|
])
|
||||||
|
|
||||||
|
populate_stats(site, [
|
||||||
|
build(:imported_sources,
|
||||||
|
utm_campaign: "profile",
|
||||||
|
date: ~D[2021-01-01],
|
||||||
|
visit_duration: 700,
|
||||||
|
bounces: 1,
|
||||||
|
visits: 1,
|
||||||
|
visitors: 1
|
||||||
|
),
|
||||||
|
build(:imported_sources,
|
||||||
|
utm_campaign: "",
|
||||||
|
date: ~D[2021-01-01],
|
||||||
|
bounces: 0,
|
||||||
|
visits: 1,
|
||||||
|
visitors: 1,
|
||||||
|
visit_duration: 900
|
||||||
|
)
|
||||||
|
])
|
||||||
|
|
||||||
|
conn =
|
||||||
|
get(
|
||||||
|
conn,
|
||||||
|
"/api/stats/#{site.domain}/utm_campaigns?period=day&date=2021-01-01"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert json_response(conn, 200) == [
|
||||||
|
%{
|
||||||
|
"name" => "profile",
|
||||||
|
"visitors" => 1,
|
||||||
|
"bounce_rate" => 0,
|
||||||
|
"visit_duration" => 900
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
conn =
|
||||||
|
get(
|
||||||
|
conn,
|
||||||
|
"/api/stats/#{site.domain}/utm_campaigns?period=day&date=2021-01-01&with_imported=true"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert json_response(conn, 200) == [
|
||||||
|
%{
|
||||||
|
"name" => "profile",
|
||||||
|
"visitors" => 2,
|
||||||
|
"bounce_rate" => 50,
|
||||||
|
"visit_duration" => 800.0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "GET /api/stats/:domain/utm_sources" do
|
describe "GET /api/stats/:domain/utm_sources" do
|
||||||
setup [:create_user, :log_in, :create_new_site]
|
setup [:create_user, :log_in, :create_new_site, :add_imported_data]
|
||||||
|
|
||||||
test "returns top utm_sources by unique user ids", %{conn: conn, site: site} do
|
test "returns top utm_sources by unique user ids", %{conn: conn, site: site} do
|
||||||
populate_stats(site, [
|
populate_stats(site, [
|
||||||
@ -706,6 +846,326 @@ defmodule PlausibleWeb.Api.StatsController.SourcesTest do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "GET /api/stats/:domain/utm_terms" do
|
||||||
|
setup [:create_user, :log_in, :create_new_site, :add_imported_data]
|
||||||
|
|
||||||
|
test "returns top utm_terms by unique user ids", %{conn: conn, site: site} do
|
||||||
|
populate_stats(site, [
|
||||||
|
build(:pageview,
|
||||||
|
utm_term: "oat milk",
|
||||||
|
user_id: @user_id,
|
||||||
|
timestamp: ~N[2021-01-01 00:00:00]
|
||||||
|
),
|
||||||
|
build(:pageview,
|
||||||
|
utm_term: "oat milk",
|
||||||
|
user_id: @user_id,
|
||||||
|
timestamp: ~N[2021-01-01 00:15:00]
|
||||||
|
),
|
||||||
|
build(:pageview,
|
||||||
|
utm_term: "Sweden",
|
||||||
|
timestamp: ~N[2021-01-01 00:00:00]
|
||||||
|
),
|
||||||
|
build(:pageview,
|
||||||
|
utm_term: "Sweden",
|
||||||
|
timestamp: ~N[2021-01-01 00:00:00]
|
||||||
|
)
|
||||||
|
])
|
||||||
|
|
||||||
|
populate_stats(site, [
|
||||||
|
build(:imported_sources,
|
||||||
|
utm_term: "oat milk",
|
||||||
|
date: ~D[2021-01-01],
|
||||||
|
visit_duration: 700,
|
||||||
|
bounces: 1,
|
||||||
|
visits: 1,
|
||||||
|
visitors: 1
|
||||||
|
),
|
||||||
|
build(:imported_sources,
|
||||||
|
utm_term: "Sweden",
|
||||||
|
date: ~D[2021-01-01],
|
||||||
|
bounces: 0,
|
||||||
|
visits: 1,
|
||||||
|
visitors: 1,
|
||||||
|
visit_duration: 900
|
||||||
|
)
|
||||||
|
])
|
||||||
|
|
||||||
|
conn =
|
||||||
|
get(
|
||||||
|
conn,
|
||||||
|
"/api/stats/#{site.domain}/utm_terms?period=day&date=2021-01-01"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert json_response(conn, 200) == [
|
||||||
|
%{
|
||||||
|
"name" => "Sweden",
|
||||||
|
"visitors" => 2,
|
||||||
|
"bounce_rate" => 100,
|
||||||
|
"visit_duration" => 0
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
"name" => "oat milk",
|
||||||
|
"visitors" => 1,
|
||||||
|
"bounce_rate" => 0,
|
||||||
|
"visit_duration" => 900
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
conn =
|
||||||
|
get(
|
||||||
|
conn,
|
||||||
|
"/api/stats/#{site.domain}/utm_terms?period=day&date=2021-01-01&with_imported=true"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert json_response(conn, 200) == [
|
||||||
|
%{
|
||||||
|
"name" => "Sweden",
|
||||||
|
"visitors" => 3,
|
||||||
|
"bounce_rate" => 67,
|
||||||
|
"visit_duration" => 300
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
"name" => "oat milk",
|
||||||
|
"visitors" => 2,
|
||||||
|
"bounce_rate" => 50,
|
||||||
|
"visit_duration" => 800.0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "filters out entries without utm_term present", %{conn: conn, site: site} do
|
||||||
|
populate_stats(site, [
|
||||||
|
build(:pageview,
|
||||||
|
utm_term: "oat milk",
|
||||||
|
user_id: @user_id,
|
||||||
|
timestamp: ~N[2021-01-01 00:00:00]
|
||||||
|
),
|
||||||
|
build(:pageview,
|
||||||
|
utm_term: "oat milk",
|
||||||
|
user_id: @user_id,
|
||||||
|
timestamp: ~N[2021-01-01 00:15:00]
|
||||||
|
),
|
||||||
|
build(:pageview,
|
||||||
|
utm_term: "",
|
||||||
|
timestamp: ~N[2021-01-01 00:00:00]
|
||||||
|
),
|
||||||
|
build(:pageview,
|
||||||
|
utm_term: "",
|
||||||
|
timestamp: ~N[2021-01-01 00:00:00]
|
||||||
|
)
|
||||||
|
])
|
||||||
|
|
||||||
|
populate_stats(site, [
|
||||||
|
build(:imported_sources,
|
||||||
|
utm_term: "oat milk",
|
||||||
|
date: ~D[2021-01-01],
|
||||||
|
visit_duration: 700,
|
||||||
|
bounces: 1,
|
||||||
|
visits: 1,
|
||||||
|
visitors: 1
|
||||||
|
),
|
||||||
|
build(:imported_sources,
|
||||||
|
utm_term: "",
|
||||||
|
date: ~D[2021-01-01],
|
||||||
|
bounces: 0,
|
||||||
|
visits: 1,
|
||||||
|
visitors: 1,
|
||||||
|
visit_duration: 900
|
||||||
|
)
|
||||||
|
])
|
||||||
|
|
||||||
|
conn =
|
||||||
|
get(
|
||||||
|
conn,
|
||||||
|
"/api/stats/#{site.domain}/utm_terms?period=day&date=2021-01-01"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert json_response(conn, 200) == [
|
||||||
|
%{
|
||||||
|
"name" => "oat milk",
|
||||||
|
"visitors" => 1,
|
||||||
|
"bounce_rate" => 0,
|
||||||
|
"visit_duration" => 900
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
conn =
|
||||||
|
get(
|
||||||
|
conn,
|
||||||
|
"/api/stats/#{site.domain}/utm_terms?period=day&date=2021-01-01&with_imported=true"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert json_response(conn, 200) == [
|
||||||
|
%{
|
||||||
|
"name" => "oat milk",
|
||||||
|
"visitors" => 2,
|
||||||
|
"bounce_rate" => 50,
|
||||||
|
"visit_duration" => 800.0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "GET /api/stats/:domain/utm_contents" do
|
||||||
|
setup [:create_user, :log_in, :create_new_site, :add_imported_data]
|
||||||
|
|
||||||
|
test "returns top utm_contents by unique user ids", %{conn: conn, site: site} do
|
||||||
|
populate_stats(site, [
|
||||||
|
build(:pageview,
|
||||||
|
utm_content: "ad",
|
||||||
|
user_id: @user_id,
|
||||||
|
timestamp: ~N[2021-01-01 00:00:00]
|
||||||
|
),
|
||||||
|
build(:pageview,
|
||||||
|
utm_content: "ad",
|
||||||
|
user_id: @user_id,
|
||||||
|
timestamp: ~N[2021-01-01 00:15:00]
|
||||||
|
),
|
||||||
|
build(:pageview,
|
||||||
|
utm_content: "blog",
|
||||||
|
timestamp: ~N[2021-01-01 00:00:00]
|
||||||
|
),
|
||||||
|
build(:pageview,
|
||||||
|
utm_content: "blog",
|
||||||
|
timestamp: ~N[2021-01-01 00:00:00]
|
||||||
|
)
|
||||||
|
])
|
||||||
|
|
||||||
|
populate_stats(site, [
|
||||||
|
build(:imported_sources,
|
||||||
|
utm_content: "ad",
|
||||||
|
date: ~D[2021-01-01],
|
||||||
|
visit_duration: 700,
|
||||||
|
bounces: 1,
|
||||||
|
visits: 1,
|
||||||
|
visitors: 1
|
||||||
|
),
|
||||||
|
build(:imported_sources,
|
||||||
|
utm_content: "blog",
|
||||||
|
date: ~D[2021-01-01],
|
||||||
|
bounces: 0,
|
||||||
|
visits: 1,
|
||||||
|
visitors: 1,
|
||||||
|
visit_duration: 900
|
||||||
|
)
|
||||||
|
])
|
||||||
|
|
||||||
|
conn =
|
||||||
|
get(
|
||||||
|
conn,
|
||||||
|
"/api/stats/#{site.domain}/utm_contents?period=day&date=2021-01-01"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert json_response(conn, 200) == [
|
||||||
|
%{
|
||||||
|
"name" => "blog",
|
||||||
|
"visitors" => 2,
|
||||||
|
"bounce_rate" => 100,
|
||||||
|
"visit_duration" => 0
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
"name" => "ad",
|
||||||
|
"visitors" => 1,
|
||||||
|
"bounce_rate" => 0,
|
||||||
|
"visit_duration" => 900
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
conn =
|
||||||
|
get(
|
||||||
|
conn,
|
||||||
|
"/api/stats/#{site.domain}/utm_contents?period=day&date=2021-01-01&with_imported=true"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert json_response(conn, 200) == [
|
||||||
|
%{
|
||||||
|
"name" => "blog",
|
||||||
|
"visitors" => 3,
|
||||||
|
"bounce_rate" => 67,
|
||||||
|
"visit_duration" => 300
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
"name" => "ad",
|
||||||
|
"visitors" => 2,
|
||||||
|
"bounce_rate" => 50,
|
||||||
|
"visit_duration" => 800.0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "filters out entries without utm_content present", %{conn: conn, site: site} do
|
||||||
|
populate_stats(site, [
|
||||||
|
build(:pageview,
|
||||||
|
utm_content: "ad",
|
||||||
|
user_id: @user_id,
|
||||||
|
timestamp: ~N[2021-01-01 00:00:00]
|
||||||
|
),
|
||||||
|
build(:pageview,
|
||||||
|
utm_content: "ad",
|
||||||
|
user_id: @user_id,
|
||||||
|
timestamp: ~N[2021-01-01 00:15:00]
|
||||||
|
),
|
||||||
|
build(:pageview,
|
||||||
|
utm_content: "",
|
||||||
|
timestamp: ~N[2021-01-01 00:00:00]
|
||||||
|
),
|
||||||
|
build(:pageview,
|
||||||
|
utm_content: "",
|
||||||
|
timestamp: ~N[2021-01-01 00:00:00]
|
||||||
|
)
|
||||||
|
])
|
||||||
|
|
||||||
|
populate_stats(site, [
|
||||||
|
build(:imported_sources,
|
||||||
|
utm_content: "ad",
|
||||||
|
date: ~D[2021-01-01],
|
||||||
|
visit_duration: 700,
|
||||||
|
bounces: 1,
|
||||||
|
visits: 1,
|
||||||
|
visitors: 1
|
||||||
|
),
|
||||||
|
build(:imported_sources,
|
||||||
|
utm_content: "",
|
||||||
|
date: ~D[2021-01-01],
|
||||||
|
bounces: 0,
|
||||||
|
visits: 1,
|
||||||
|
visitors: 1,
|
||||||
|
visit_duration: 900
|
||||||
|
)
|
||||||
|
])
|
||||||
|
|
||||||
|
conn =
|
||||||
|
get(
|
||||||
|
conn,
|
||||||
|
"/api/stats/#{site.domain}/utm_contents?period=day&date=2021-01-01"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert json_response(conn, 200) == [
|
||||||
|
%{
|
||||||
|
"name" => "ad",
|
||||||
|
"visitors" => 1,
|
||||||
|
"bounce_rate" => 0,
|
||||||
|
"visit_duration" => 900
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
conn =
|
||||||
|
get(
|
||||||
|
conn,
|
||||||
|
"/api/stats/#{site.domain}/utm_contents?period=day&date=2021-01-01&with_imported=true"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert json_response(conn, 200) == [
|
||||||
|
%{
|
||||||
|
"name" => "ad",
|
||||||
|
"visitors" => 2,
|
||||||
|
"bounce_rate" => 50,
|
||||||
|
"visit_duration" => 800.0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "GET /api/stats/:domain/sources - with goal filter" do
|
describe "GET /api/stats/:domain/sources - with goal filter" do
|
||||||
setup [:create_user, :log_in, :create_new_site]
|
setup [:create_user, :log_in, :create_new_site]
|
||||||
|
|
||||||
@ -1074,180 +1534,4 @@ defmodule PlausibleWeb.Api.StatsController.SourcesTest do
|
|||||||
]
|
]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "GET /api/stats/:domain/utm_terms" do
|
|
||||||
setup [:create_user, :log_in, :create_new_site, :add_imported_data]
|
|
||||||
|
|
||||||
test "returns top utm_terms by unique user ids", %{conn: conn, site: site} do
|
|
||||||
populate_stats(site, [
|
|
||||||
build(:pageview,
|
|
||||||
utm_term: "oat milk",
|
|
||||||
user_id: @user_id,
|
|
||||||
timestamp: ~N[2021-01-01 00:00:00]
|
|
||||||
),
|
|
||||||
build(:pageview,
|
|
||||||
utm_term: "oat milk",
|
|
||||||
user_id: @user_id,
|
|
||||||
timestamp: ~N[2021-01-01 00:15:00]
|
|
||||||
),
|
|
||||||
build(:pageview,
|
|
||||||
utm_term: "Sweden",
|
|
||||||
timestamp: ~N[2021-01-01 00:00:00]
|
|
||||||
),
|
|
||||||
build(:pageview,
|
|
||||||
utm_term: "Sweden",
|
|
||||||
timestamp: ~N[2021-01-01 00:00:00]
|
|
||||||
)
|
|
||||||
])
|
|
||||||
|
|
||||||
populate_stats(site, [
|
|
||||||
build(:imported_sources,
|
|
||||||
utm_term: "oat milk",
|
|
||||||
date: ~D[2021-01-01],
|
|
||||||
visit_duration: 700,
|
|
||||||
bounces: 1,
|
|
||||||
visits: 1,
|
|
||||||
visitors: 1
|
|
||||||
),
|
|
||||||
build(:imported_sources,
|
|
||||||
utm_term: "Sweden",
|
|
||||||
date: ~D[2021-01-01],
|
|
||||||
bounces: 0,
|
|
||||||
visits: 1,
|
|
||||||
visitors: 1,
|
|
||||||
visit_duration: 900
|
|
||||||
)
|
|
||||||
])
|
|
||||||
|
|
||||||
conn =
|
|
||||||
get(
|
|
||||||
conn,
|
|
||||||
"/api/stats/#{site.domain}/utm_terms?period=day&date=2021-01-01"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert json_response(conn, 200) == [
|
|
||||||
%{
|
|
||||||
"name" => "Sweden",
|
|
||||||
"visitors" => 2,
|
|
||||||
"bounce_rate" => 100,
|
|
||||||
"visit_duration" => 0
|
|
||||||
},
|
|
||||||
%{
|
|
||||||
"name" => "oat milk",
|
|
||||||
"visitors" => 1,
|
|
||||||
"bounce_rate" => 0,
|
|
||||||
"visit_duration" => 900
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
conn =
|
|
||||||
get(
|
|
||||||
conn,
|
|
||||||
"/api/stats/#{site.domain}/utm_terms?period=day&date=2021-01-01&with_imported=true"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert json_response(conn, 200) == [
|
|
||||||
%{
|
|
||||||
"name" => "Sweden",
|
|
||||||
"visitors" => 3,
|
|
||||||
"bounce_rate" => 67,
|
|
||||||
"visit_duration" => 300
|
|
||||||
},
|
|
||||||
%{
|
|
||||||
"name" => "oat milk",
|
|
||||||
"visitors" => 2,
|
|
||||||
"bounce_rate" => 50,
|
|
||||||
"visit_duration" => 800.0
|
|
||||||
}
|
|
||||||
]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "GET /api/stats/:domain/utm_contents" do
|
|
||||||
setup [:create_user, :log_in, :create_new_site, :add_imported_data]
|
|
||||||
|
|
||||||
test "returns top utm_contents by unique user ids", %{conn: conn, site: site} do
|
|
||||||
populate_stats(site, [
|
|
||||||
build(:pageview,
|
|
||||||
utm_content: "ad",
|
|
||||||
user_id: @user_id,
|
|
||||||
timestamp: ~N[2021-01-01 00:00:00]
|
|
||||||
),
|
|
||||||
build(:pageview,
|
|
||||||
utm_content: "ad",
|
|
||||||
user_id: @user_id,
|
|
||||||
timestamp: ~N[2021-01-01 00:15:00]
|
|
||||||
),
|
|
||||||
build(:pageview,
|
|
||||||
utm_content: "blog",
|
|
||||||
timestamp: ~N[2021-01-01 00:00:00]
|
|
||||||
),
|
|
||||||
build(:pageview,
|
|
||||||
utm_content: "blog",
|
|
||||||
timestamp: ~N[2021-01-01 00:00:00]
|
|
||||||
)
|
|
||||||
])
|
|
||||||
|
|
||||||
populate_stats(site, [
|
|
||||||
build(:imported_sources,
|
|
||||||
utm_content: "ad",
|
|
||||||
date: ~D[2021-01-01],
|
|
||||||
visit_duration: 700,
|
|
||||||
bounces: 1,
|
|
||||||
visits: 1,
|
|
||||||
visitors: 1
|
|
||||||
),
|
|
||||||
build(:imported_sources,
|
|
||||||
utm_content: "blog",
|
|
||||||
date: ~D[2021-01-01],
|
|
||||||
bounces: 0,
|
|
||||||
visits: 1,
|
|
||||||
visitors: 1,
|
|
||||||
visit_duration: 900
|
|
||||||
)
|
|
||||||
])
|
|
||||||
|
|
||||||
conn =
|
|
||||||
get(
|
|
||||||
conn,
|
|
||||||
"/api/stats/#{site.domain}/utm_contents?period=day&date=2021-01-01"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert json_response(conn, 200) == [
|
|
||||||
%{
|
|
||||||
"name" => "blog",
|
|
||||||
"visitors" => 2,
|
|
||||||
"bounce_rate" => 100,
|
|
||||||
"visit_duration" => 0
|
|
||||||
},
|
|
||||||
%{
|
|
||||||
"name" => "ad",
|
|
||||||
"visitors" => 1,
|
|
||||||
"bounce_rate" => 0,
|
|
||||||
"visit_duration" => 900
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
conn =
|
|
||||||
get(
|
|
||||||
conn,
|
|
||||||
"/api/stats/#{site.domain}/utm_contents?period=day&date=2021-01-01&with_imported=true"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert json_response(conn, 200) == [
|
|
||||||
%{
|
|
||||||
"name" => "blog",
|
|
||||||
"visitors" => 3,
|
|
||||||
"bounce_rate" => 67,
|
|
||||||
"visit_duration" => 300
|
|
||||||
},
|
|
||||||
%{
|
|
||||||
"name" => "ad",
|
|
||||||
"visitors" => 2,
|
|
||||||
"bounce_rate" => 50,
|
|
||||||
"visit_duration" => 800.0
|
|
||||||
}
|
|
||||||
]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user