Mix format

This commit is contained in:
Uku Taht 2020-11-03 11:20:11 +02:00
parent f0cbf33d7c
commit 0a7684f3bc
24 changed files with 584 additions and 436 deletions

View File

@ -1,7 +1,8 @@
use Mix.Config
base_url = System.get_env("BASE_URL", "http://localhost:8000")
|> URI.parse
base_url =
System.get_env("BASE_URL", "http://localhost:8000")
|> URI.parse()
config :plausible,
admin_user: System.get_env("ADMIN_USER_NAME", "admin"),
@ -81,10 +82,11 @@ config :plausible, :paddle,
config :plausible, Plausible.ClickhouseRepo,
loggers: [Ecto.LogEntry],
url: System.get_env(
"CLICKHOUSE_DATABASE_URL",
"http://127.0.0.1:8123/plausible_dev"
)
url:
System.get_env(
"CLICKHOUSE_DATABASE_URL",
"http://127.0.0.1:8123/plausible_dev"
)
config :plausible,
Plausible.Repo,

View File

@ -5,8 +5,10 @@ import Config
# params are made optional to facilitate smooth release
port = System.get_env("PORT") || 8000
base_url = System.get_env("BASE_URL", "http://localhost:8000")
|> URI.parse
base_url =
System.get_env("BASE_URL", "http://localhost:8000")
|> URI.parse()
secret_key_base = System.get_env("SECRET_KEY_BASE")
@ -23,7 +25,10 @@ env = System.get_env("ENVIRONMENT", "prod")
mailer_adapter = System.get_env("MAILER_ADAPTER", "Bamboo.SMTPAdapter")
mailer_email = System.get_env("MAILER_EMAIL", "hello@plausible.local")
app_version = System.get_env("APP_VERSION", "0.0.1")
ch_db_url = System.get_env("CLICKHOUSE_DATABASE_URL", "http://plausible_events_db:8123/plausible_events_db")
ch_db_url =
System.get_env("CLICKHOUSE_DATABASE_URL", "http://plausible_events_db:8123/plausible_events_db")
### Mandatory params End
sentry_dsn = System.get_env("SENTRY_DSN")
@ -75,9 +80,9 @@ config :plausible, PlausibleWeb.Endpoint,
code_reloader: false
config :plausible,
Plausible.Repo,
url: db_url,
adapter: Ecto.Adapters.Postgres
Plausible.Repo,
url: db_url,
adapter: Ecto.Adapters.Postgres
config :sentry,
dsn: sentry_dsn,
@ -194,10 +199,11 @@ if geolite2_country_db do
]
end
logger_backends = case logflare_api_key do
api_key when is_binary(api_key) -> [LogflareLogger.HttpBackend]
_ -> [:console]
end
logger_backends =
case logflare_api_key do
api_key when is_binary(api_key) -> [LogflareLogger.HttpBackend]
_ -> [:console]
end
config :logger,
level: log_level,

View File

@ -25,10 +25,11 @@ config :plausible,
config :plausible, Plausible.ClickhouseRepo,
loggers: [Ecto.LogEntry],
pool_size: String.to_integer(System.get_env("CLICKHOUSE_DATABASE_POOLSIZE", "5")),
url: System.get_env(
"CLICKHOUSE_DATABASE_URL",
"http://127.0.0.1:8123/plausible_test"
)
url:
System.get_env(
"CLICKHOUSE_DATABASE_URL",
"http://127.0.0.1:8123/plausible_test"
)
config :plausible, Plausible.Mailer, adapter: Bamboo.TestAdapter

View File

@ -29,8 +29,9 @@ defmodule Plausible.Billing do
end
def subscription_cancelled(params) do
subscription = Repo.get_by(Subscription, paddle_subscription_id: params["subscription_id"])
|> Repo.preload(:user)
subscription =
Repo.get_by(Subscription, paddle_subscription_id: params["subscription_id"])
|> Repo.preload(:user)
if subscription do
changeset =
@ -42,8 +43,11 @@ defmodule Plausible.Billing do
{:ok, updated} ->
PlausibleWeb.Email.cancellation_email(subscription.user)
|> Plausible.Mailer.send_email()
{:ok, updated}
err -> err
err ->
err
end
else
{:ok, nil}

View File

@ -33,11 +33,12 @@ defmodule Plausible.Google.Api do
Authorization: "Bearer #{auth.access_token}"
)
domains = Jason.decode!(res.body)
|> Map.get("siteEntry", [])
|> Enum.filter(fn site -> site["permissionLevel"] in @verified_permission_levels end)
|> Enum.map(fn site -> site["siteUrl"] end)
|> Enum.map(fn url -> String.trim_trailing(url, "/") end)
domains =
Jason.decode!(res.body)
|> Map.get("siteEntry", [])
|> Enum.filter(fn site -> site["permissionLevel"] in @verified_permission_levels end)
|> Enum.map(fn site -> site["siteUrl"] end)
|> Enum.map(fn url -> String.trim_trailing(url, "/") end)
{:ok, domains}
else
@ -48,7 +49,7 @@ defmodule Plausible.Google.Api do
defp property_base_url(property) do
case property do
"sc-domain:" <> domain -> "https://" <> domain
url -> url
url -> url
end
end
@ -63,12 +64,20 @@ defmodule Plausible.Google.Api do
defp do_fetch_stats(auth, query, limit) do
property = URI.encode_www_form(auth.property)
base_url = property_base_url(auth.property)
filter_groups = if query.filters["page"] do
[%{filters: [%{
dimension: "page",
expression: "https://#{base_url}#{query.filters["page"]}"
}]}]
end
filter_groups =
if query.filters["page"] do
[
%{
filters: [
%{
dimension: "page",
expression: "https://#{base_url}#{query.filters["page"]}"
}
]
}
]
end
res =
HTTPoison.post!(

View File

@ -40,7 +40,8 @@ defmodule Plausible.Stats.Clickhouse do
fragment("uniq(?)", e.user_id)},
group_by: fragment("month"),
order_by: fragment("month")
) |> Enum.into(%{})
)
|> Enum.into(%{})
present_index =
Enum.find_index(steps, fn step ->
@ -64,7 +65,8 @@ defmodule Plausible.Stats.Clickhouse do
fragment("uniq(?)", e.user_id)},
group_by: fragment("day"),
order_by: fragment("day")
) |> Enum.into(%{})
)
|> Enum.into(%{})
present_index =
Enum.find_index(steps, fn step -> step == Timex.now(site.timezone) |> Timex.to_date() end)
@ -87,7 +89,8 @@ defmodule Plausible.Stats.Clickhouse do
fragment("uniq(?)", e.user_id)},
group_by: fragment("hour"),
order_by: fragment("hour")
) |> Enum.into(%{})
)
|> Enum.into(%{})
now = Timex.now(site.timezone)
is_today = Timex.to_date(now) == query.date_range.first
@ -117,7 +120,8 @@ defmodule Plausible.Stats.Clickhouse do
},
group_by: fragment("relativeMinute"),
order_by: fragment("relativeMinute")
) |> Enum.into(%{})
)
|> Enum.into(%{})
labels = Enum.into(-30..-1, [])
plot = Enum.map(labels, fn label -> groups[label] || 0 end)
@ -143,28 +147,28 @@ defmodule Plausible.Stats.Clickhouse do
ClickhouseRepo.one(
from e in base_session_query(site, query),
select: fragment("sum(sign * pageviews)")
select: fragment("sum(sign * pageviews)")
)
end
def total_events(site, query) do
ClickhouseRepo.one(
from e in base_query_w_sessions(site, query),
select: fragment("count(*) as events")
select: fragment("count(*) as events")
)
end
def pageviews_and_visitors(site, query) do
ClickhouseRepo.one(
from e in base_query_w_sessions(site, query),
select: {fragment("count(*)"), fragment("uniq(user_id)")}
select: {fragment("count(*)"), fragment("uniq(user_id)")}
)
end
def unique_visitors(site, query) do
ClickhouseRepo.one(
from e in base_query_w_sessions(site, query),
select: fragment("uniq(user_id)")
select: fragment("uniq(user_id)")
)
end
@ -173,17 +177,18 @@ defmodule Plausible.Stats.Clickhouse do
ClickhouseRepo.all(
from s in base_query_w_sessions(site, query),
where: s.referrer_source != "",
group_by: s.referrer_source,
order_by: [desc: fragment("count")],
limit: ^limit,
offset: ^offset,
select: %{
name: s.referrer_source,
url: fragment("any(?)", s.referrer),
count: fragment("uniq(?) as count", s.user_id)
}
) |> Enum.map(fn ref ->
where: s.referrer_source != "",
group_by: s.referrer_source,
order_by: [desc: fragment("count")],
limit: ^limit,
offset: ^offset,
select: %{
name: s.referrer_source,
url: fragment("any(?)", s.referrer),
count: fragment("uniq(?) as count", s.user_id)
}
)
|> Enum.map(fn ref ->
Map.update(ref, :url, nil, fn url -> url && URI.parse("http://" <> url).host end)
end)
end
@ -197,30 +202,40 @@ defmodule Plausible.Stats.Clickhouse do
order_by: [desc: fragment("count"), asc: fragment("min(start)")],
limit: ^limit,
offset: ^offset
) |> filter_converted_sessions(site, query)
)
|> filter_converted_sessions(site, query)
referrers = if show_noref do
referrers
else
from(s in referrers, where: s.referrer_source != "")
end
referrers =
if show_noref do
referrers
else
from(s in referrers, where: s.referrer_source != "")
end
referrers = if query.filters["page"] do
page = query.filters["page"]
from(s in referrers, where: s.entry_page == ^page)
else
referrers
end
referrers =
if query.filters["page"] do
page = query.filters["page"]
from(s in referrers, where: s.entry_page == ^page)
else
referrers
end
referrers =
if "bounce_rate" in include do
from(
s in referrers,
select: %{
name: fragment("if(empty(?), ?, ?) as name", s.referrer_source, @no_ref, s.referrer_source),
name:
fragment(
"if(empty(?), ?, ?) as name",
s.referrer_source,
@no_ref,
s.referrer_source
),
url: fragment("any(?)", s.referrer),
count: fragment("uniq(user_id) as count"),
bounce_rate: fragment("round(sum(is_bounce * sign) / sum(sign) * 100) as bounce_rate"),
bounce_rate:
fragment("round(sum(is_bounce * sign) / sum(sign) * 100) as bounce_rate"),
visit_duration: fragment("round(avg(duration * sign)) as visit_duration")
}
)
@ -228,53 +243,64 @@ defmodule Plausible.Stats.Clickhouse do
from(
s in referrers,
select: %{
name: fragment("if(empty(?), ?, ?) as name", s.referrer_source, @no_ref, s.referrer_source),
name:
fragment(
"if(empty(?), ?, ?) as name",
s.referrer_source,
@no_ref,
s.referrer_source
),
url: fragment("any(?)", s.referrer),
count: fragment("uniq(user_id) as count")
}
)
end
ClickhouseRepo.all(referrers)
|> Enum.map(fn ref ->
Map.update(ref, :url, nil, fn url -> url && URI.parse("http://" <> url).host end)
end)
ClickhouseRepo.all(referrers)
|> Enum.map(fn ref ->
Map.update(ref, :url, nil, fn url -> url && URI.parse("http://" <> url).host end)
end)
end
defp filter_converted_sessions(db_query, site, %Query{filters: %{"goal" => goal}} = query) when is_binary(goal) do
defp filter_converted_sessions(db_query, site, %Query{filters: %{"goal" => goal}} = query)
when is_binary(goal) do
converted_sessions =
from(e in base_query(site, query),
select: %{session_id: e.session_id})
select: %{session_id: e.session_id}
)
from(s in db_query,
join: cs in subquery(converted_sessions),
on: s.session_id == cs.session_id
)
end
defp filter_converted_sessions(db_query, _site, _query), do: db_query
def utm_mediums(site, query, limit \\ 9, page \\ 1, show_noref \\ false) do
offset = (page - 1) * limit
q = from(
s in base_session_query(site, query),
group_by: s.utm_medium,
order_by: [desc: fragment("count"), asc: fragment("min(start)")],
limit: ^limit,
offset: ^offset,
select: %{
name: fragment("if(empty(?), ?, ?) as name", s.utm_medium, @no_ref, s.utm_medium),
count: fragment("uniq(user_id) as count"),
bounce_rate: fragment("round(sum(is_bounce * sign) / sum(sign) * 100)"),
visit_duration: fragment("round(avg(duration * sign))")
}
)
q =
from(
s in base_session_query(site, query),
group_by: s.utm_medium,
order_by: [desc: fragment("count"), asc: fragment("min(start)")],
limit: ^limit,
offset: ^offset,
select: %{
name: fragment("if(empty(?), ?, ?) as name", s.utm_medium, @no_ref, s.utm_medium),
count: fragment("uniq(user_id) as count"),
bounce_rate: fragment("round(sum(is_bounce * sign) / sum(sign) * 100)"),
visit_duration: fragment("round(avg(duration * sign))")
}
)
q = if show_noref do
q
else
from(s in q, where: s.utm_medium != "")
end
q =
if show_noref do
q
else
from(s in q, where: s.utm_medium != "")
end
q
|> filter_converted_sessions(site, query)
@ -284,25 +310,27 @@ defmodule Plausible.Stats.Clickhouse do
def utm_campaigns(site, query, limit \\ 9, page \\ 1, show_noref \\ false) do
offset = (page - 1) * limit
q = from(
s in base_session_query(site, query),
group_by: s.utm_campaign,
order_by: [desc: fragment("count"), asc: fragment("min(start)")],
limit: ^limit,
offset: ^offset,
select: %{
name: fragment("if(empty(?), ?, ?) as name", s.utm_campaign, @no_ref, s.utm_campaign),
count: fragment("uniq(user_id) as count"),
bounce_rate: fragment("round(sum(is_bounce * sign) / sum(sign) * 100)"),
visit_duration: fragment("round(avg(duration * sign))")
}
)
q =
from(
s in base_session_query(site, query),
group_by: s.utm_campaign,
order_by: [desc: fragment("count"), asc: fragment("min(start)")],
limit: ^limit,
offset: ^offset,
select: %{
name: fragment("if(empty(?), ?, ?) as name", s.utm_campaign, @no_ref, s.utm_campaign),
count: fragment("uniq(user_id) as count"),
bounce_rate: fragment("round(sum(is_bounce * sign) / sum(sign) * 100)"),
visit_duration: fragment("round(avg(duration * sign))")
}
)
q = if show_noref do
q
else
from(s in q, where: s.utm_campaign != "")
end
q =
if show_noref do
q
else
from(s in q, where: s.utm_campaign != "")
end
q
|> filter_converted_sessions(site, query)
@ -312,25 +340,27 @@ defmodule Plausible.Stats.Clickhouse do
def utm_sources(site, query, limit \\ 9, page \\ 1, show_noref \\ false) do
offset = (page - 1) * limit
q = from(
s in base_session_query(site, query),
group_by: s.utm_source,
order_by: [desc: fragment("count"), asc: fragment("min(start)")],
limit: ^limit,
offset: ^offset,
select: %{
name: fragment("if(empty(?), ?, ?) as name", s.utm_source, @no_ref, s.utm_source),
count: fragment("uniq(user_id) as count"),
bounce_rate: fragment("round(sum(is_bounce * sign) / sum(sign) * 100)"),
visit_duration: fragment("round(avg(duration * sign))")
}
)
q =
from(
s in base_session_query(site, query),
group_by: s.utm_source,
order_by: [desc: fragment("count"), asc: fragment("min(start)")],
limit: ^limit,
offset: ^offset,
select: %{
name: fragment("if(empty(?), ?, ?) as name", s.utm_source, @no_ref, s.utm_source),
count: fragment("uniq(user_id) as count"),
bounce_rate: fragment("round(sum(is_bounce * sign) / sum(sign) * 100)"),
visit_duration: fragment("round(avg(duration * sign))")
}
)
q = if show_noref do
q
else
from(s in q, where: s.utm_source != "")
end
q =
if show_noref do
q
else
from(s in q, where: s.utm_source != "")
end
q
|> filter_converted_sessions(site, query)
@ -346,10 +376,10 @@ defmodule Plausible.Stats.Clickhouse do
ClickhouseRepo.one(
from s in Plausible.ClickhouseSession,
join: cs in subquery(converted_sessions),
on: s.session_id == cs.session_id,
where: s.referrer_source == ^referrer,
select: fragment("uniq(user_id) as visitors")
join: cs in subquery(converted_sessions),
on: s.session_id == cs.session_id,
where: s.referrer_source == ^referrer,
select: fragment("uniq(user_id) as visitors")
)
end
@ -363,7 +393,8 @@ defmodule Plausible.Stats.Clickhouse do
where: s.referrer_source == ^referrer,
order_by: [desc: fragment("count")],
limit: ^limit
) |> filter_converted_sessions(site, query)
)
|> filter_converted_sessions(site, query)
q =
if "bounce_rate" in include do
@ -372,9 +403,11 @@ defmodule Plausible.Stats.Clickhouse do
select: %{
name: fragment("if(empty(?), ?, ?) as name", s.referrer, @no_ref, s.referrer),
count: fragment("uniq(user_id) as count"),
bounce_rate: fragment("round(sum(is_bounce * sign) / sum(sign) * 100) as bounce_rate"),
bounce_rate:
fragment("round(sum(is_bounce * sign) / sum(sign) * 100) as bounce_rate"),
visit_duration: fragment("round(avg(duration * sign)) as visit_duration")
})
}
)
else
from(s in q,
select: %{
@ -412,35 +445,37 @@ defmodule Plausible.Stats.Clickhouse do
def referrer_drilldown_for_goal(site, query, referrer) do
Plausible.ClickhouseRepo.all(
from s in base_query_w_sessions(site, query),
where: s.referrer_source == ^referrer,
group_by: s.referrer,
order_by: [desc: fragment("count")],
limit: 100,
select: %{
name: s.referrer,
count: fragment("uniq(user_id) as count")
}
where: s.referrer_source == ^referrer,
group_by: s.referrer,
order_by: [desc: fragment("count")],
limit: 100,
select: %{
name: s.referrer,
count: fragment("uniq(user_id) as count")
}
)
end
def entry_pages(site, query, limit, include) do
q = from(
s in base_session_query(site, query),
group_by: s.entry_page,
order_by: [desc: fragment("count")],
limit: ^limit,
select: %{
name: s.entry_page,
count: fragment("uniq(?) as count", s.user_id)
}
)
q =
from(
s in base_session_query(site, query),
group_by: s.entry_page,
order_by: [desc: fragment("count")],
limit: ^limit,
select: %{
name: s.entry_page,
count: fragment("uniq(?) as count", s.user_id)
}
)
q = if query.filters["page"] do
page = query.filters["page"]
from(s in q, where: s.entry_page == ^page)
else
q
end
q =
if query.filters["page"] do
page = query.filters["page"]
from(s in q, where: s.entry_page == ^page)
else
q
end
pages = ClickhouseRepo.all(q)
@ -455,13 +490,13 @@ defmodule Plausible.Stats.Clickhouse do
def top_pages(site, %Query{period: "realtime"} = query, limit, _include) do
ClickhouseRepo.all(
from s in base_session_query(site, query),
group_by: s.exit_page,
order_by: [desc: fragment("count")],
limit: ^limit,
select: %{
name: fragment("? as name", s.exit_page),
count: fragment("uniq(?) as count", s.user_id)
}
group_by: s.exit_page,
order_by: [desc: fragment("count")],
limit: ^limit,
select: %{
name: fragment("? as name", s.exit_page),
count: fragment("uniq(?) as count", s.user_id)
}
)
end
@ -492,14 +527,14 @@ defmodule Plausible.Stats.Clickhouse do
defp bounce_rates_by_page_url(site, query) do
ClickhouseRepo.all(
from s in base_session_query(site, query),
group_by: s.entry_page,
order_by: [desc: fragment("total")],
limit: 100,
select: %{
entry_page: s.entry_page,
total: fragment("count(*) as total"),
bounce_rate: fragment("round(sum(is_bounce * sign) / sum(sign) * 100) as bounce_rate")
}
group_by: s.entry_page,
order_by: [desc: fragment("total")],
limit: 100,
select: %{
entry_page: s.entry_page,
total: fragment("count(*) as total"),
bounce_rate: fragment("round(sum(is_bounce * sign) / sum(sign) * 100) as bounce_rate")
}
)
|> Enum.map(fn row -> {row[:entry_page], row[:bounce_rate]} end)
|> Enum.into(%{})
@ -516,26 +551,27 @@ defmodule Plausible.Stats.Clickhouse do
def top_screen_sizes(site, query) do
ClickhouseRepo.all(
from e in base_query_w_sessions(site, query),
group_by: e.screen_size,
where: e.screen_size != "",
order_by: [desc: fragment("count")],
select: %{
name: e.screen_size,
count: fragment("uniq(user_id) as count")
}
) |> add_percentages
group_by: e.screen_size,
where: e.screen_size != "",
order_by: [desc: fragment("count")],
select: %{
name: e.screen_size,
count: fragment("uniq(user_id) as count")
}
)
|> add_percentages
end
def countries(site, query) do
ClickhouseRepo.all(
from e in base_query_w_sessions(site, query),
group_by: e.country_code,
where: e.country_code != "\0\0",
order_by: [desc: fragment("count")],
select: %{
name: e.country_code,
count: fragment("uniq(user_id) as count")
}
group_by: e.country_code,
where: e.country_code != "\0\0",
order_by: [desc: fragment("count")],
select: %{
name: e.country_code,
count: fragment("uniq(user_id) as count")
}
)
|> Enum.map(fn stat ->
two_letter_code = stat[:name]
@ -543,19 +579,20 @@ defmodule Plausible.Stats.Clickhouse do
stat
|> Map.put(:name, Plausible.Stats.CountryName.to_alpha3(two_letter_code))
|> Map.put(:full_country_name, Plausible.Stats.CountryName.from_iso3166(two_letter_code))
end) |> add_percentages
end)
|> add_percentages
end
def browsers(site, query, limit \\ 5) do
ClickhouseRepo.all(
from e in base_query_w_sessions(site, query),
group_by: e.browser,
where: e.browser != "",
order_by: [desc: fragment("count")],
select: %{
name: e.browser,
count: fragment("uniq(user_id) as count")
}
group_by: e.browser,
where: e.browser != "",
order_by: [desc: fragment("count")],
select: %{
name: e.browser,
count: fragment("uniq(user_id) as count")
}
)
|> add_percentages
|> Enum.take(limit)
@ -564,23 +601,23 @@ defmodule Plausible.Stats.Clickhouse do
def operating_systems(site, query, limit \\ 5) do
ClickhouseRepo.all(
from e in base_query_w_sessions(site, query),
group_by: e.operating_system,
where: e.operating_system != "",
order_by: [desc: fragment("count")],
select: %{
name: e.operating_system,
count: fragment("uniq(user_id) as count")
}
group_by: e.operating_system,
where: e.operating_system != "",
order_by: [desc: fragment("count")],
select: %{
name: e.operating_system,
count: fragment("uniq(user_id) as count")
}
)
|> add_percentages
|> Enum.take(limit)
end
def current_visitors(site, query) do
Plausible.ClickhouseRepo.one(
from s in base_query(site, query),
select: fragment("uniq(user_id)")
)
Plausible.ClickhouseRepo.one(
from s in base_query(site, query),
select: fragment("uniq(user_id)")
)
end
def has_pageviews?([]), do: false
@ -588,8 +625,8 @@ defmodule Plausible.Stats.Clickhouse do
def has_pageviews?(domains) when is_list(domains) do
ClickhouseRepo.exists?(
from e in "events",
select: e.timestamp,
where: fragment("? IN tuple(?)", e.domain, ^domains)
select: e.timestamp,
where: fragment("? IN tuple(?)", e.domain, ^domains)
)
end
@ -606,9 +643,10 @@ defmodule Plausible.Stats.Clickhouse do
else
ClickhouseRepo.all(
from [e, meta: meta] in base_query_w_sessions_bare(site, query),
select: {e.name, meta.key},
distinct: true
) |> Enum.reduce(%{}, fn {goal_name, meta_key}, acc ->
select: {e.name, meta.key},
distinct: true
)
|> Enum.reduce(%{}, fn {goal_name, meta_key}, acc ->
Map.update(acc, goal_name, [meta_key], fn list -> [meta_key | list] end)
end)
end
@ -617,67 +655,71 @@ defmodule Plausible.Stats.Clickhouse do
def all_props(site, query) do
ClickhouseRepo.all(
from e in base_query_w_sessions_bare(site, query),
inner_lateral_join: meta in fragment("meta as m"),
select: {e.name, meta.key},
distinct: true
) |> Enum.reduce(%{}, fn {goal_name, meta_key}, acc ->
inner_lateral_join: meta in fragment("meta as m"),
select: {e.name, meta.key},
distinct: true
)
|> Enum.reduce(%{}, fn {goal_name, meta_key}, acc ->
Map.update(acc, goal_name, [meta_key], fn list -> [meta_key | list] end)
end)
end
def property_breakdown(site, %Query{filters: %{"props" => meta}} = query, key) when is_map(meta) do
def property_breakdown(site, %Query{filters: %{"props" => meta}} = query, key)
when is_map(meta) do
[{_key, val}] = meta |> Enum.into([])
if val == "(none)" do
ClickhouseRepo.all(
from e in base_query_w_sessions(site, query),
where: fragment("not has(meta.key, ?)", ^key),
order_by: [desc: fragment("count")],
select: %{
name: "(none)",
count: fragment("uniq(user_id) as count"),
total_count: fragment("count(*) as total_count")
}
)
ClickhouseRepo.all(
from e in base_query_w_sessions(site, query),
where: fragment("not has(meta.key, ?)", ^key),
order_by: [desc: fragment("count")],
select: %{
name: "(none)",
count: fragment("uniq(user_id) as count"),
total_count: fragment("count(*) as total_count")
}
)
else
ClickhouseRepo.all(
from [e, meta: meta] in base_query_w_sessions(site, query),
group_by: meta.value,
order_by: [desc: fragment("count")],
select: %{
name: meta.value,
count: fragment("uniq(user_id) as count"),
total_count: fragment("count(*) as total_count")
}
)
ClickhouseRepo.all(
from [e, meta: meta] in base_query_w_sessions(site, query),
group_by: meta.value,
order_by: [desc: fragment("count")],
select: %{
name: meta.value,
count: fragment("uniq(user_id) as count"),
total_count: fragment("count(*) as total_count")
}
)
end
end
def property_breakdown(site, query, key) do
none = ClickhouseRepo.all(
from e in base_query_w_sessions(site, query),
where: fragment("not has(meta.key, ?)", ^key),
select: %{
name: "(none)",
count: fragment("uniq(?) as count", e.user_id),
total_count: fragment("count(*) as total_count")
}
)
none =
ClickhouseRepo.all(
from e in base_query_w_sessions(site, query),
where: fragment("not has(meta.key, ?)", ^key),
select: %{
name: "(none)",
count: fragment("uniq(?) as count", e.user_id),
total_count: fragment("count(*) as total_count")
}
)
values = ClickhouseRepo.all(
from e in base_query_w_sessions(site, query),
inner_lateral_join: meta in fragment("meta as m"),
where: meta.key == ^key,
group_by: meta.value,
order_by: [desc: fragment("count")],
select: %{
name: meta.value,
count: fragment("uniq(user_id) as count"),
total_count: fragment("count(*) as total_count")
}
)
values =
ClickhouseRepo.all(
from e in base_query_w_sessions(site, query),
inner_lateral_join: meta in fragment("meta as m"),
where: meta.key == ^key,
group_by: meta.value,
order_by: [desc: fragment("count")],
select: %{
name: meta.value,
count: fragment("uniq(user_id) as count"),
total_count: fragment("count(*) as total_count")
}
)
values ++ none
(values ++ none)
|> Enum.sort(fn row1, row2 -> row1[:count] >= row2[:count] end)
|> Enum.filter(fn row -> row[:count] > 0 end)
end
@ -685,13 +727,13 @@ defmodule Plausible.Stats.Clickhouse do
def goal_conversions(site, %Query{filters: %{"goal" => goal}} = query) when is_binary(goal) do
ClickhouseRepo.all(
from e in base_query_w_sessions(site, query),
group_by: e.name,
order_by: [desc: fragment("count")],
select: %{
name: ^goal,
count: fragment("uniq(user_id) as count"),
total_count: fragment("count(*) as total_count")
}
group_by: e.name,
order_by: [desc: fragment("count")],
select: %{
name: ^goal,
count: fragment("uniq(user_id) as count"),
total_count: fragment("count(*) as total_count")
}
)
end
@ -710,16 +752,17 @@ defmodule Plausible.Stats.Clickhouse do
|> Enum.filter(& &1)
if Enum.count(events) > 0 do
q = from(
e in base_query_w_sessions_bare(site, query),
where: fragment("? IN tuple(?)", e.name, ^events),
group_by: e.name,
select: %{
name: e.name,
count: fragment("uniq(user_id) as count"),
total_count: fragment("count(*) as total_count")
}
)
q =
from(
e in base_query_w_sessions_bare(site, query),
where: fragment("? IN tuple(?)", e.name, ^events),
group_by: e.name,
select: %{
name: e.name,
count: fragment("uniq(user_id) as count"),
total_count: fragment("count(*) as total_count")
}
)
ClickhouseRepo.all(q)
else
@ -733,16 +776,17 @@ defmodule Plausible.Stats.Clickhouse do
|> Enum.filter(& &1)
if Enum.count(pages) > 0 do
q = from(
e in base_query_w_sessions(site, query),
where: fragment("? IN tuple(?)", e.pathname, ^pages),
group_by: e.pathname,
select: %{
name: fragment("concat('Visit ', ?) as name", e.pathname),
count: fragment("uniq(user_id) as count"),
total_count: fragment("count(*) as total_count")
}
)
q =
from(
e in base_query_w_sessions(site, query),
where: fragment("? IN tuple(?)", e.pathname, ^pages),
group_by: e.pathname,
select: %{
name: fragment("concat('Visit ', ?) as name", e.pathname),
count: fragment("uniq(user_id) as count"),
total_count: fragment("count(*) as total_count")
}
)
ClickhouseRepo.all(q)
else
@ -757,11 +801,12 @@ defmodule Plausible.Stats.Clickhouse do
defp base_query_w_sessions_bare(site, query) do
{first_datetime, last_datetime} = utc_boundaries(query, site.timezone)
sessions_q = from(s in "sessions",
where: s.domain == ^site.domain,
where: s.timestamp >= ^first_datetime and s.start < ^last_datetime,
select: %{session_id: s.session_id}
)
sessions_q =
from(s in "sessions",
where: s.domain == ^site.domain,
where: s.timestamp >= ^first_datetime and s.start < ^last_datetime,
select: %{session_id: s.session_id}
)
sessions_q =
if query.filters["source"] do
@ -828,12 +873,13 @@ defmodule Plausible.Stats.Clickhouse do
sessions_q
end
sessions_q = if query.filters["referrer"] do
ref = query.filters["referrer"]
from(s in sessions_q, where: s.referrer == ^ref)
else
sessions_q
end
sessions_q =
if query.filters["referrer"] do
ref = query.filters["referrer"]
from(s in sessions_q, where: s.referrer == ^ref)
else
sessions_q
end
q =
from(e in "events",
@ -841,22 +887,26 @@ defmodule Plausible.Stats.Clickhouse do
where: e.timestamp >= ^first_datetime and e.timestamp < ^last_datetime
)
q = if query.filters["source"] || query.filters['referrer'] || query.filters["utm_medium"] || query.filters["utm_source"] || query.filters["utm_campaign"] || query.filters["screen"] || query.filters["browser"] || query.filters["os"] || query.filters["country"] do
from(
e in q,
join: sq in subquery(sessions_q),
on: e.session_id == sq.session_id
)
else
q
end
q =
if query.filters["source"] || query.filters['referrer'] || query.filters["utm_medium"] ||
query.filters["utm_source"] || query.filters["utm_campaign"] || query.filters["screen"] ||
query.filters["browser"] || query.filters["os"] || query.filters["country"] do
from(
e in q,
join: sq in subquery(sessions_q),
on: e.session_id == sq.session_id
)
else
q
end
q = if query.filters["page"] do
page = query.filters["page"]
from(e in q, where: e.pathname == ^page)
else
q
end
q =
if query.filters["page"] do
page = query.filters["page"]
from(e in q, where: e.pathname == ^page)
else
q
end
if query.filters["props"] do
[{key, val}] = query.filters["props"] |> Enum.into([])
@ -871,7 +921,7 @@ defmodule Plausible.Stats.Clickhouse do
e in q,
inner_lateral_join: meta in fragment("meta as m"),
as: :meta,
where: meta.key == ^key and meta.value == ^val,
where: meta.key == ^key and meta.value == ^val
)
end
else
@ -884,11 +934,12 @@ defmodule Plausible.Stats.Clickhouse do
{goal_event, path} = event_name_for_goal(query)
q = if goal_event do
from(e in q, where: e.name == ^goal_event)
else
from(e in q, where: e.name == "pageview")
end
q =
if goal_event do
from(e in q, where: e.name == ^goal_event)
else
from(e in q, where: e.name == "pageview")
end
if path do
from(e in q, where: e.pathname == ^path)
@ -897,7 +948,6 @@ defmodule Plausible.Stats.Clickhouse do
end
end
defp base_session_query(site, query) do
{first_datetime, last_datetime} = utc_boundaries(query, site.timezone)
@ -1070,25 +1120,25 @@ defmodule Plausible.Stats.Clickhouse do
q
end
q = if query.filters["props"] do
[{key, val}] = query.filters["props"] |> Enum.into([])
q =
if query.filters["props"] do
[{key, val}] = query.filters["props"] |> Enum.into([])
if val == "(none)" do
from(
e in q,
where: fragment("not has(meta.key, ?)", ^key)
)
if val == "(none)" do
from(
e in q,
where: fragment("not has(meta.key, ?)", ^key)
)
else
from(
e in q,
inner_lateral_join: meta in fragment("meta as m"),
where: meta.key == ^key and meta.value == ^val
)
end
else
from(
e in q,
inner_lateral_join: meta in fragment("meta as m"),
where: meta.key == ^key and meta.value == ^val,
)
q
end
else
q
end
q =
if path do

View File

@ -494,8 +494,8 @@ defmodule Plausible.Stats.CountryName do
}
@alpha2_codes @alpha3_codes
|> Enum.map(fn {k, v} -> {v, k} end)
|> Enum.into(%{})
|> Enum.map(fn {k, v} -> {v, k} end)
|> Enum.into(%{})
def to_alpha3(code) do
Map.get(@alpha3_codes, code, code)

View File

@ -9,6 +9,7 @@ defmodule Plausible.Release do
def init_admin do
prepare()
{admin_email, admin_user, admin_pwd} =
validate_admin(
{Application.get_env(:plausible, :admin_email),
@ -55,6 +56,7 @@ defmodule Plausible.Release do
for repo <- repos() do
:ok = ensure_repo_created(repo)
end
IO.puts("Creation of Db successful!")
end

View File

@ -12,7 +12,9 @@ defmodule PlausibleWeb.Captcha do
def verify(token) do
if enabled?() do
res = HTTPoison.post!(@verify_endpoint, {:form, [{"response", token}, {"secret", secret()}]})
res =
HTTPoison.post!(@verify_endpoint, {:form, [{"response", token}, {"secret", secret()}]})
json = Jason.decode!(res.body)
json["success"]
else

View File

@ -72,6 +72,7 @@ defmodule PlausibleWeb.Api.ExternalController do
{:ok, nil}
else
query = if uri && uri.query, do: URI.decode_query(uri.query), else: %{}
ua =
if user_agent do
UAInspector.Parser.parse(user_agent)
@ -94,8 +95,8 @@ defmodule PlausibleWeb.Api.ExternalController do
utm_source: query["utm_source"] || "",
utm_campaign: query["utm_campaign"] || "",
country_code: country_code || "",
operating_system: ua && os_name(ua) || "",
browser: ua && browser_name(ua) || "",
operating_system: (ua && os_name(ua)) || "",
browser: (ua && browser_name(ua)) || "",
screen_size: calculate_screen_size(params["screen_width"]) || "",
"meta.key": Map.keys(params["meta"]),
"meta.value": Map.values(params["meta"])
@ -118,6 +119,7 @@ defmodule PlausibleWeb.Api.ExternalController do
defp parse_meta(params) do
raw_meta = params["m"] || params["meta"] || params["p"] || params["props"]
if raw_meta do
Jason.decode!(raw_meta)
else
@ -126,8 +128,10 @@ defmodule PlausibleWeb.Api.ExternalController do
end
defp get_pathname(nil, _), do: "/"
defp get_pathname(uri, hash_mode) do
pathname = uri.path || "/"
if hash_mode && uri.fragment do
pathname <> "#" <> uri.fragment
else

View File

@ -13,6 +13,6 @@ defmodule PlausibleWeb.Api.InternalController do
def sites(conn, _) do
user = Repo.preload(conn.assigns[:current_user], :sites)
json(conn, Enum.map(user.sites, &(&1.domain)))
json(conn, Enum.map(user.sites, & &1.domain))
end
end

View File

@ -79,16 +79,18 @@ defmodule PlausibleWeb.Api.StatsController do
bounce_rate = Stats.bounce_rate(site, query)
prev_bounce_rate = Stats.bounce_rate(site, prev_query)
change_bounce_rate = if prev_bounce_rate > 0, do: bounce_rate - prev_bounce_rate
visit_duration = if !query.filters["page"] do
duration = Stats.visit_duration(site, query)
prev_duration = Stats.visit_duration(site, prev_query)
%{
name: "Visit duration",
count: duration,
change: percent_change(prev_duration, duration)
}
end
visit_duration =
if !query.filters["page"] do
duration = Stats.visit_duration(site, query)
prev_duration = Stats.visit_duration(site, prev_query)
%{
name: "Visit duration",
count: duration,
change: percent_change(prev_duration, duration)
}
end
[
%{
@ -103,7 +105,8 @@ defmodule PlausibleWeb.Api.StatsController do
},
%{name: "Bounce rate", percentage: bounce_rate, change: change_bounce_rate},
visit_duration
] |> Enum.filter(&(&1))
]
|> Enum.filter(& &1)
end
defp percent_change(old_count, new_count) do
@ -253,7 +256,7 @@ defmodule PlausibleWeb.Api.StatsController do
defp calculate_cr(unique_visitors, converted_visitors) do
if unique_visitors > 0,
do: Float.round(converted_visitors / unique_visitors * 100, 1),
else: 0.0
else: 0.0
end
def conversions(conn, params) do
@ -262,12 +265,14 @@ defmodule PlausibleWeb.Api.StatsController do
total_filter = Map.merge(query.filters, %{"goal" => nil, "props" => nil})
unique_visitors = Stats.unique_visitors(site, %{query | filters: total_filter})
prop_names = Stats.all_props(site, query)
conversions = Stats.goal_conversions(site, query)
|> Enum.map(fn goal ->
goal
|> Map.put(:prop_names, prop_names[goal[:name]])
|> Map.put(:conversion_rate, calculate_cr(unique_visitors, goal[:count]))
end)
conversions =
Stats.goal_conversions(site, query)
|> Enum.map(fn goal ->
goal
|> Map.put(:prop_names, prop_names[goal[:name]])
|> Map.put(:conversion_rate, calculate_cr(unique_visitors, goal[:count]))
end)
json(conn, conversions)
end
@ -277,10 +282,12 @@ defmodule PlausibleWeb.Api.StatsController do
query = Query.from(site.timezone, params)
total_filter = Map.merge(query.filters, %{"goal" => nil, "props" => nil})
unique_visitors = Stats.unique_visitors(site, %{query | filters: total_filter})
props = Stats.property_breakdown(site, query, params["prop_name"])
|> Enum.map(fn prop ->
Map.put(prop, :conversion_rate, calculate_cr(unique_visitors, prop[:count]))
end)
props =
Stats.property_breakdown(site, query, params["prop_name"])
|> Enum.map(fn prop ->
Map.put(prop, :conversion_rate, calculate_cr(unique_visitors, prop[:count]))
end)
json(conn, props)
end

View File

@ -66,9 +66,11 @@ defmodule PlausibleWeb.AuthController do
|> Plausible.Mailer.send_email()
user_activated_account(conn, user)
{:error, %Ecto.Changeset{errors: [email: {"has already been taken", _}]}} ->
user = Auth.find_user_by(email: email)
user_activated_account(conn, user)
{:error, changeset} ->
send_resp(conn, 400, inspect(changeset.errors))
end

View File

@ -7,6 +7,7 @@ defmodule PlausibleWeb.Firewall do
def call(conn, _opts) do
blocklist = Keyword.fetch!(Application.get_env(:plausible, __MODULE__), :blocklist)
if PlausibleWeb.RemoteIp.get(conn) in blocklist do
send_resp(conn, 404, "Not found") |> halt
else

View File

@ -1,5 +1,6 @@
defmodule PlausibleWeb.Tracker do
import Plug.Conn
@templates [
"plausible.js",
"plausible.hash.js",
@ -16,14 +17,20 @@ defmodule PlausibleWeb.Tracker do
@max_age 3600
def init(_) do
templates = Enum.reduce(@templates, %{}, fn template_filename, rendered_templates ->
rendered = EEx.eval_file("priv/tracker/js/" <> template_filename, base_url: PlausibleWeb.Endpoint.url())
aliases = Map.get(@aliases, template_filename, [])
[template_filename | aliases]
|> Enum.map(fn filename -> {"/js/" <> filename, rendered} end)
|> Enum.into(%{})
|> Map.merge(rendered_templates)
end)
templates =
Enum.reduce(@templates, %{}, fn template_filename, rendered_templates ->
rendered =
EEx.eval_file("priv/tracker/js/" <> template_filename,
base_url: PlausibleWeb.Endpoint.url()
)
aliases = Map.get(@aliases, template_filename, [])
[template_filename | aliases]
|> Enum.map(fn filename -> {"/js/" <> filename, rendered} end)
|> Enum.into(%{})
|> Map.merge(rendered_templates)
end)
[templates: templates]
end

View File

@ -91,7 +91,7 @@ defmodule Plausible.MixProject do
{:geolix, "~> 1.0"},
{:clickhouse_ecto, git: "https://github.com/plausible/clickhouse_ecto.git"},
{:geolix_adapter_mmdb2, "~> 0.5.0"},
{:logflare_logger_backend, "~> 0.7.6"},
{:logflare_logger_backend, "~> 0.7.6"}
]
end

View File

@ -213,7 +213,9 @@ defmodule Plausible.BillingTest do
"status" => "deleted"
})
assert_email_delivered_with(subject: "Your Plausible Analytics subscription has been canceled")
assert_email_delivered_with(
subject: "Your Plausible Analytics subscription has been canceled"
)
end
end

View File

@ -10,10 +10,12 @@ defmodule PlausibleWeb.AdminAuthControllerTest do
test "logs admin user in automatically when authentication is disabled", %{conn: conn} do
set_config(disable_authentication: true)
admin_user = insert(:user,
email: Application.get_env(:plausible, :admin_email),
password: Application.get_env(:plausible, :admin_pwd)
)
admin_user =
insert(:user,
email: Application.get_env(:plausible, :admin_email),
password: Application.get_env(:plausible, :admin_pwd)
)
# goto landing page
conn = get(conn, "/")

View File

@ -7,8 +7,8 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
ClickhouseRepo.one(
from e in Plausible.ClickhouseEvent,
where: e.domain == ^domain,
order_by: [desc: e.timestamp]
where: e.domain == ^domain,
order_by: [desc: e.timestamp]
)
end
@ -259,7 +259,8 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
test "utm tags are stored", %{conn: conn} do
params = %{
name: "pageview",
url: "http://www.example.com/?utm_medium=ads&utm_source=instagram&utm_campaign=video_story",
url:
"http://www.example.com/?utm_medium=ads&utm_source=instagram&utm_campaign=video_story",
domain: "external-controller-test-utm-tags.com"
}
@ -414,7 +415,8 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
test "URL is decoded", %{conn: conn} do
params = %{
name: "pageview",
url: "http://www.example.com/opportunity/category/%D8%AC%D9%88%D8%A7%D8%A6%D8%B2-%D9%88%D9%85%D8%B3%D8%A7%D8%A8%D9%82%D8%A7%D8%AA",
url:
"http://www.example.com/opportunity/category/%D8%AC%D9%88%D8%A7%D8%A6%D8%B2-%D9%88%D9%85%D8%B3%D8%A7%D8%A8%D9%82%D8%A7%D8%AA",
domain: "external-controller-test-21.com"
}

View File

@ -12,8 +12,20 @@ defmodule PlausibleWeb.Api.StatsController.ConversionsTest do
conn = get(conn, "/api/stats/#{site.domain}/conversions?period=day&date=2019-01-01")
assert json_response(conn, 200) == [
%{"name" => "Signup", "count" => 3, "total_count" => 3, "prop_names" => ["variant"], "conversion_rate" => 50.0},
%{"name" => "Visit /register", "count" => 2, "total_count" => 2, "prop_names" => nil, "conversion_rate" => 33.3}
%{
"name" => "Signup",
"count" => 3,
"total_count" => 3,
"prop_names" => ["variant"],
"conversion_rate" => 50.0
},
%{
"name" => "Visit /register",
"count" => 2,
"total_count" => 2,
"prop_names" => nil,
"conversion_rate" => 33.3
}
]
end
end
@ -34,8 +46,14 @@ defmodule PlausibleWeb.Api.StatsController.ConversionsTest do
)
assert json_response(conn, 200) == [
%{"name" => "Signup", "count" => 3, "total_count" => 3, "prop_names" => ["variant"], "conversion_rate" => 50.0}
]
%{
"name" => "Signup",
"count" => 3,
"total_count" => 3,
"prop_names" => ["variant"],
"conversion_rate" => 50.0
}
]
end
end
@ -50,13 +68,15 @@ defmodule PlausibleWeb.Api.StatsController.ConversionsTest do
conn =
get(
conn,
"/api/stats/#{site.domain}/property/#{prop_key}?period=day&date=2019-01-01&filters=#{filters}"
"/api/stats/#{site.domain}/property/#{prop_key}?period=day&date=2019-01-01&filters=#{
filters
}"
)
assert json_response(conn, 200) == [
%{"count" => 2, "name" => "B", "total_count" => 2, "conversion_rate" => 33.3},
%{"count" => 1, "name" => "A", "total_count" => 1, "conversion_rate" => 16.7}
]
%{"count" => 2, "name" => "B", "total_count" => 2, "conversion_rate" => 33.3},
%{"count" => 1, "name" => "A", "total_count" => 1, "conversion_rate" => 16.7}
]
end
end
end

View File

@ -24,30 +24,31 @@ defmodule PlausibleWeb.Api.StatsController.PagesTest do
)
assert json_response(conn, 200) == [
%{
"bounce_rate" => 33.0,
"count" => 2,
"pageviews" => 2,
"name" => "/"},
%{
"bounce_rate" => nil,
"count" => 2,
"pageviews" => 2,
"name" => "/register"
},
%{
"bounce_rate" => nil,
"count" => 1,
"pageviews" => 1,
"name" => "/contact"
},
%{
"bounce_rate" => nil,
"count" => 1,
"pageviews" => 1,
"name" => "/irrelevant"
}
]
%{
"bounce_rate" => 33.0,
"count" => 2,
"pageviews" => 2,
"name" => "/"
},
%{
"bounce_rate" => nil,
"count" => 2,
"pageviews" => 2,
"name" => "/register"
},
%{
"bounce_rate" => nil,
"count" => 1,
"pageviews" => 1,
"name" => "/contact"
},
%{
"bounce_rate" => nil,
"count" => 1,
"pageviews" => 1,
"name" => "/irrelevant"
}
]
end
test "returns top pages in realtime report", %{conn: conn, site: site} do
@ -67,7 +68,7 @@ defmodule PlausibleWeb.Api.StatsController.PagesTest do
conn = get(conn, "/api/stats/#{site.domain}/entry-pages?period=day&date=2019-01-01")
assert json_response(conn, 200) == [
%{"count" => 3, "name" => "/"},
%{"count" => 3, "name" => "/"}
]
end
@ -79,12 +80,12 @@ defmodule PlausibleWeb.Api.StatsController.PagesTest do
)
assert json_response(conn, 200) == [
%{
"bounce_rate" => 33.0,
"count" => 3,
"name" => "/"
}
]
%{
"bounce_rate" => 33.0,
"count" => 3,
"name" => "/"
}
]
end
end
end

View File

@ -49,7 +49,8 @@ defmodule PlausibleWeb.Api.StatsController.SourcesTest do
end
test "can paginate the results", %{conn: conn, site: site} do
conn = get(conn, "/api/stats/#{site.domain}/sources?period=day&date=2019-01-01&limit=1&page=2")
conn =
get(conn, "/api/stats/#{site.domain}/sources?period=day&date=2019-01-01&limit=1&page=2")
assert json_response(conn, 200) == [
%{"name" => "Bing", "count" => 1, "url" => ""}
@ -64,8 +65,18 @@ defmodule PlausibleWeb.Api.StatsController.SourcesTest do
conn = get(conn, "/api/stats/#{site.domain}/utm_mediums?period=day&date=2019-01-01")
assert json_response(conn, 200) == [
%{"name" => "listing", "count" => 2, "bounce_rate" => 50.0, "visit_duration" => 50.0},
%{"name" => "search", "count" => 1, "bounce_rate" => 0.0, "visit_duration" => 100.0}
%{
"name" => "listing",
"count" => 2,
"bounce_rate" => 50.0,
"visit_duration" => 50.0
},
%{
"name" => "search",
"count" => 1,
"bounce_rate" => 0.0,
"visit_duration" => 100.0
}
]
end
end
@ -107,7 +118,14 @@ defmodule PlausibleWeb.Api.StatsController.SourcesTest do
test "returns top referrers for a particular source", %{conn: conn, site: site} do
filters = Jason.encode!(%{source: "10words"})
conn = get(conn, "/api/stats/#{site.domain}/referrers/10words?period=day&date=2019-01-01&filters=#{filters}")
conn =
get(
conn,
"/api/stats/#{site.domain}/referrers/10words?period=day&date=2019-01-01&filters=#{
filters
}"
)
assert json_response(conn, 200) == %{
"total_visitors" => 3,
@ -119,10 +137,13 @@ defmodule PlausibleWeb.Api.StatsController.SourcesTest do
test "calculates bounce rate and visit duration for referrer urls", %{conn: conn, site: site} do
filters = Jason.encode!(%{source: "10words"})
conn =
get(
conn,
"/api/stats/#{site.domain}/referrers/10words?period=day&date=2019-01-01&filters=#{filters}&include=bounce_rate,visit_duration"
"/api/stats/#{site.domain}/referrers/10words?period=day&date=2019-01-01&filters=#{
filters
}&include=bounce_rate,visit_duration"
)
assert json_response(conn, 200) == %{

View File

@ -8,7 +8,7 @@ defmodule PlausibleWeb.FirewallTest do
@opts [blocklist: [@blocked_ip]]
setup do
Application.put_env(:plausible, PlausibleWeb.Firewall, [blocklist: [@blocked_ip]])
Application.put_env(:plausible, PlausibleWeb.Firewall, blocklist: [@blocked_ip])
:ok
end

View File

@ -12,25 +12,28 @@ defmodule Plausible.TestUtils do
end
def create_pageviews(pageviews) do
pageviews = Enum.map(pageviews, fn pageview ->
Factory.build(:pageview, pageview) |> Map.from_struct() |> Map.delete(:__meta__)
end)
pageviews =
Enum.map(pageviews, fn pageview ->
Factory.build(:pageview, pageview) |> Map.from_struct() |> Map.delete(:__meta__)
end)
Plausible.ClickhouseRepo.insert_all("events", pageviews)
end
def create_events(events) do
events = Enum.map(events, fn event ->
Factory.build(:event, event) |> Map.from_struct() |> Map.delete(:__meta__)
end)
events =
Enum.map(events, fn event ->
Factory.build(:event, event) |> Map.from_struct() |> Map.delete(:__meta__)
end)
Plausible.ClickhouseRepo.insert_all("events", events)
end
def create_sessions(sessions) do
sessions = Enum.map(sessions, fn session ->
Factory.build(:ch_session, session) |> Map.from_struct() |> Map.delete(:__meta__)
end)
sessions =
Enum.map(sessions, fn session ->
Factory.build(:ch_session, session) |> Map.from_struct() |> Map.delete(:__meta__)
end)
Plausible.ClickhouseRepo.insert_all("sessions", sessions)
end