Analytics without using cookies (#44)

* Use fingerprints instead of user_id

* Fix tests
This commit is contained in:
Uku Taht 2020-03-24 10:50:16 +02:00 committed by GitHub
parent 6d1f7afde5
commit 594b085467
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 175 additions and 130 deletions

View File

@ -4,9 +4,11 @@
try {
const scriptEl = window.document.querySelector('[src*="' + plausibleHost +'"]')
const domainAttr = scriptEl && scriptEl.getAttribute('data-domain')
const trackAcquisitionAttr = scriptEl && scriptEl.getAttribute('data-track-acquisition')
const CONFIG = {
domain: domainAttr || window.location.hostname
domain: domainAttr || window.location.hostname,
trackAcquisition: typeof(trackAcquisitionAttr) === 'string'
}
function setCookie(name,value) {
@ -23,18 +25,6 @@
return matches ? decodeURIComponent(matches[1]) : null;
}
function pseudoUUIDv4() {
var d = new Date().getTime();
if (typeof performance !== 'undefined' && typeof performance.now === 'function'){
d += performance.now(); //use high-precision timer if available
}
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = (d + Math.random() * 16) % 16 | 0;
d = Math.floor(d / 16);
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
}
function ignore(reason) {
console.warn('[Plausible] Ignoring event because ' + reason);
}
@ -52,30 +42,23 @@
var userData = JSON.parse(getCookie('plausible_user'))
if (userData) {
userData.new_visitor = false
if (userData.referrer) {
userData.initial_referrer = userData.referrer && decodeURIComponent(userData.referrer)
} else {
userData.initial_referrer = userData.initial_referrer && decodeURIComponent(userData.initial_referrer)
userData.initial_source = userData.initial_source && decodeURIComponent(userData.initial_source)
}
return userData
} else {
return {
uid: pseudoUUIDv4(),
new_visitor: true,
initial_referrer: window.document.referrer,
initial_referrer: userData.initial_referrer && decodeURIComponent(userData.initial_referrer),
initial_source: userData.initial_source && decodeURIComponent(userData.initial_source)
}
} else {
userData = {
initial_referrer: window.document.referrer || null,
initial_source: getSourceFromQueryParam(),
}
}
}
function setUserData(payload) {
setCookie('plausible_user', JSON.stringify({
uid: payload.uid,
initial_referrer: payload.initial_referrer && encodeURIComponent(payload.initial_referrer),
initial_source: payload.initial_source && encodeURIComponent(payload.initial_source),
}))
setCookie('plausible_user', JSON.stringify({
initial_referrer: userData.initial_referrer && encodeURIComponent(userData.initial_referrer),
initial_source: userData.initial_source && encodeURIComponent(userData.initial_source),
}))
return userData
}
}
function trigger(eventName, options) {
@ -83,11 +66,11 @@
if (window.location.protocol === 'file:') return ignore('website is running locally');
if (window.document.visibilityState === 'prerender') return ignore('document is prerendering');
var payload = getUserData()
var payload = CONFIG['trackAcquisition'] ? getUserData() : {}
payload.name = eventName
payload.url = getUrl()
payload.domain = CONFIG['domain']
payload.referrer = window.document.referrer
payload.referrer = window.document.referrer || null
payload.source = getSourceFromQueryParam()
payload.user_agent = window.navigator.userAgent
payload.screen_width = window.innerWidth
@ -100,7 +83,6 @@
request.onreadystatechange = function() {
if (request.readyState == XMLHttpRequest.DONE) {
setUserData(payload)
options && options.callback && options.callback()
}
}

View File

@ -32,7 +32,7 @@ defmodule Plausible.Stats do
from e in base_query(site, %{query | filters: %{}}),
group_by: 1,
order_by: 1,
select: {fragment("date_trunc('month', ? at time zone 'utc' at time zone ?)", e.timestamp, ^site.timezone), count(e.user_id, :distinct)}
select: {fragment("date_trunc('month', ? at time zone 'utc' at time zone ?)", e.timestamp, ^site.timezone), count(e.fingerprint, :distinct)}
) |> Enum.into(%{})
|> transform_keys(fn dt -> NaiveDateTime.to_date(dt) end)
@ -41,7 +41,7 @@ defmodule Plausible.Stats do
from e in base_query(site, query),
group_by: 1,
order_by: 1,
select: {fragment("date_trunc('month', ? at time zone 'utc' at time zone ?)", e.timestamp, ^site.timezone), count(e.user_id, :distinct)}
select: {fragment("date_trunc('month', ? at time zone 'utc' at time zone ?)", e.timestamp, ^site.timezone), count(e.fingerprint, :distinct)}
) |> Enum.into(%{})
|> transform_keys(fn dt -> NaiveDateTime.to_date(dt) end)
end
@ -61,7 +61,7 @@ defmodule Plausible.Stats do
from e in base_query(site, %{ query | filters: %{} }),
group_by: 1,
order_by: 1,
select: {fragment("date_trunc('day', ? at time zone 'utc' at time zone ?)", e.timestamp, ^site.timezone), count(e.user_id, :distinct)}
select: {fragment("date_trunc('day', ? at time zone 'utc' at time zone ?)", e.timestamp, ^site.timezone), count(e.fingerprint, :distinct)}
) |> Enum.into(%{})
|> transform_keys(fn dt -> NaiveDateTime.to_date(dt) end)
@ -70,7 +70,7 @@ defmodule Plausible.Stats do
from e in base_query(site, query),
group_by: 1,
order_by: 1,
select: {fragment("date_trunc('day', ? at time zone 'utc' at time zone ?)", e.timestamp, ^site.timezone), count(e.user_id, :distinct)}
select: {fragment("date_trunc('day', ? at time zone 'utc' at time zone ?)", e.timestamp, ^site.timezone), count(e.fingerprint, :distinct)}
) |> Enum.into(%{})
|> transform_keys(fn dt -> NaiveDateTime.to_date(dt) end)
end
@ -98,7 +98,7 @@ defmodule Plausible.Stats do
from e in base_query(site, %{query | filters: %{}}),
group_by: 1,
order_by: 1,
select: {fragment("date_trunc('hour', ? at time zone 'utc' at time zone ?)", e.timestamp, ^site.timezone), count(e.user_id, :distinct)}
select: {fragment("date_trunc('hour', ? at time zone 'utc' at time zone ?)", e.timestamp, ^site.timezone), count(e.fingerprint, :distinct)}
)
|> Enum.into(%{})
|> transform_keys(fn dt -> NaiveDateTime.truncate(dt, :second) end)
@ -108,7 +108,7 @@ defmodule Plausible.Stats do
from e in base_query(site, query),
group_by: 1,
order_by: 1,
select: {fragment("date_trunc('hour', ? at time zone 'utc' at time zone ?)", e.timestamp, ^site.timezone), count(e.user_id, :distinct)}
select: {fragment("date_trunc('hour', ? at time zone 'utc' at time zone ?)", e.timestamp, ^site.timezone), count(e.fingerprint, :distinct)}
)
|> Enum.into(%{})
|> transform_keys(fn dt -> NaiveDateTime.truncate(dt, :second) end)
@ -125,7 +125,7 @@ defmodule Plausible.Stats do
def bounce_rate(site, query) do
{first_datetime, last_datetime} = date_range_utc_boundaries(query.date_range, site.timezone)
sessions_query = from(s in Plausible.Session,
sessions_query = from(s in Plausible.FingerprintSession,
where: s.domain == ^site.domain,
where: s.start >= ^first_datetime and s.start < ^last_datetime
)
@ -141,20 +141,20 @@ defmodule Plausible.Stats do
def pageviews_and_visitors(site, query) do
Repo.one(from(
e in base_query(site, query),
select: {count(e.id), count(e.user_id, :distinct)}
select: {count(e.id), count(e.fingerprint, :distinct)}
))
end
def unique_visitors(site, query) do
Repo.one(from(
e in base_query(site, query),
select: count(e.user_id, :distinct)
select: count(e.fingerprint, :distinct)
))
end
def top_referrers_for_goal(site, query, limit \\ 5) do
Repo.all(from e in base_query(site, query),
select: %{name: e.initial_referrer_source, url: min(e.initial_referrer), count: count(e.user_id, :distinct)},
select: %{name: e.initial_referrer_source, url: min(e.initial_referrer), count: count(e.fingerprint, :distinct)},
group_by: e.initial_referrer_source,
where: not is_nil(e.initial_referrer_source),
order_by: [desc: 3],
@ -166,7 +166,7 @@ defmodule Plausible.Stats do
def top_referrers(site, query, limit \\ 5, include \\ []) do
referrers = Repo.all(from e in base_query(site, query),
select: %{name: e.referrer_source, url: min(e.referrer), count: count(e.user_id, :distinct)},
select: %{name: e.referrer_source, url: min(e.referrer), count: count(e.fingerprint, :distinct)},
group_by: e.referrer_source,
where: not is_nil(e.referrer_source),
order_by: [desc: 3],
@ -190,7 +190,7 @@ defmodule Plausible.Stats do
{first_datetime, last_datetime} = date_range_utc_boundaries(query.date_range, site.timezone)
total_sessions_by_referrer = Repo.all(
from s in Plausible.Session,
from s in Plausible.FingerprintSession,
where: s.domain == ^site.domain,
where: s.start >= ^first_datetime and s.start < ^last_datetime,
where: s.referrer_source in ^referrers,
@ -199,7 +199,7 @@ defmodule Plausible.Stats do
) |> Enum.into(%{})
bounced_sessions_by_referrer = Repo.all(
from s in Plausible.Session,
from s in Plausible.FingerprintSession,
where: s.domain == ^site.domain,
where: s.start >= ^first_datetime and s.start < ^last_datetime,
where: s.is_bounce,
@ -223,7 +223,7 @@ defmodule Plausible.Stats do
def visitors_from_referrer(site, query, referrer) do
Repo.one(
from e in base_query(site, query),
select: count(e.user_id, :distinct),
select: count(e.fingerprint, :distinct),
where: e.referrer_source == ^referrer
)
end
@ -231,7 +231,7 @@ defmodule Plausible.Stats do
def conversions_from_referrer(site, query, referrer) do
Repo.one(
from e in base_query(site, query),
select: count(e.user_id, :distinct),
select: count(e.fingerprint, :distinct),
where: e.initial_referrer_source == ^referrer
)
end
@ -239,7 +239,7 @@ defmodule Plausible.Stats do
def referrer_drilldown(site, query, referrer, include \\ []) do
referring_urls = Repo.all(
from e in base_query(site, query),
select: %{name: e.referrer, count: count(e.user_id, :distinct)},
select: %{name: e.referrer, count: count(e.fingerprint, :distinct)},
group_by: e.referrer,
where: e.referrer_source == ^referrer,
order_by: [desc: 2],
@ -275,7 +275,7 @@ defmodule Plausible.Stats do
def referrer_drilldown_for_goal(site, query, referrer) do
Repo.all(
from e in base_query(site, query),
select: %{name: e.initial_referrer, count: count(e.user_id, :distinct)},
select: %{name: e.initial_referrer, count: count(e.fingerprint, :distinct)},
group_by: e.initial_referrer,
where: e.initial_referrer_source == ^referrer,
order_by: [desc: 2],
@ -287,7 +287,7 @@ defmodule Plausible.Stats do
{first_datetime, last_datetime} = date_range_utc_boundaries(query.date_range, site.timezone)
total_sessions_by_url = Repo.all(
from s in Plausible.Session,
from s in Plausible.FingerprintSession,
where: s.domain == ^site.domain,
where: s.start >= ^first_datetime and s.start < ^last_datetime,
where: s.referrer in ^referring_urls,
@ -296,7 +296,7 @@ defmodule Plausible.Stats do
) |> Enum.into(%{})
bounced_sessions_by_url = Repo.all(
from s in Plausible.Session,
from s in Plausible.FingerprintSession,
where: s.domain == ^site.domain,
where: s.start >= ^first_datetime and s.start < ^last_datetime,
where: s.is_bounce,
@ -340,7 +340,7 @@ defmodule Plausible.Stats do
{first_datetime, last_datetime} = date_range_utc_boundaries(query.date_range, site.timezone)
total_sessions_by_url = Repo.all(
from s in Plausible.Session,
from s in Plausible.FingerprintSession,
where: s.domain == ^site.domain,
where: s.start >= ^first_datetime and s.start < ^last_datetime,
where: s.entry_page in ^page_urls,
@ -349,7 +349,7 @@ defmodule Plausible.Stats do
) |> Enum.into(%{})
bounced_sessions_by_url = Repo.all(
from s in Plausible.Session,
from s in Plausible.FingerprintSession,
where: s.domain == ^site.domain,
where: s.start >= ^first_datetime and s.start < ^last_datetime,
where: s.is_bounce,
@ -381,7 +381,7 @@ defmodule Plausible.Stats do
def top_screen_sizes(site, query) do
Repo.all(from e in base_query(site, query),
select: %{name: e.screen_size, count: count(e.user_id, :distinct)},
select: %{name: e.screen_size, count: count(e.fingerprint, :distinct)},
group_by: e.screen_size,
where: not is_nil(e.screen_size)
)
@ -395,7 +395,7 @@ defmodule Plausible.Stats do
def countries(site, query) do
Repo.all(from e in base_query(site, query),
select: %{name: e.country_code, count: count(e.user_id, :distinct)},
select: %{name: e.country_code, count: count(e.fingerprint, :distinct)},
group_by: e.country_code,
where: not is_nil(e.country_code),
order_by: [desc: 2]
@ -411,7 +411,7 @@ defmodule Plausible.Stats do
def browsers(site, query, limit \\ 5) do
Repo.all(from e in base_query(site, query),
select: %{name: e.browser, count: count(e.user_id, :distinct)},
select: %{name: e.browser, count: count(e.fingerprint, :distinct)},
group_by: e.browser,
where: not is_nil(e.browser),
order_by: [desc: 2]
@ -422,7 +422,7 @@ defmodule Plausible.Stats do
def operating_systems(site, query, limit \\ 5) do
Repo.all(from e in base_query(site, query),
select: %{name: e.operating_system, count: count(e.user_id, :distinct)},
select: %{name: e.operating_system, count: count(e.fingerprint, :distinct)},
group_by: e.operating_system,
where: not is_nil(e.operating_system),
order_by: [desc: 2]
@ -436,13 +436,13 @@ defmodule Plausible.Stats do
from e in Plausible.Event,
where: e.timestamp >= fragment("(now() at time zone 'utc') - '5 minutes'::interval"),
where: e.domain == ^site.domain,
select: count(e.user_id, :distinct)
select: count(e.fingerprint, :distinct)
)
end
def goal_conversions(site, %Query{filters: %{"goal" => goal}} = query) when is_binary(goal) do
Repo.all(from e in base_query(site, query),
select: count(e.user_id, :distinct),
select: count(e.fingerprint, :distinct),
group_by: e.name,
order_by: [desc: 1]
) |> Enum.map(fn count -> %{name: goal, count: count} end)
@ -463,7 +463,7 @@ defmodule Plausible.Stats do
Repo.all(
from e in base_query(site, query, events),
group_by: e.name,
select: %{name: e.name, count: count(e.user_id, :distinct)}
select: %{name: e.name, count: count(e.fingerprint, :distinct)}
)
else
[]
@ -479,7 +479,7 @@ defmodule Plausible.Stats do
from e in base_query(site, query),
where: e.pathname in ^pages,
group_by: e.pathname,
select: %{name: fragment("concat('Visit ', ?)", e.pathname), count: count(e.user_id, :distinct)}
select: %{name: fragment("concat('Visit ', ?)", e.pathname), count: count(e.fingerprint, :distinct)}
)
else
[]

View File

@ -9,9 +9,7 @@ defmodule PlausibleWeb.Api.ExternalController do
{:ok, nil} ->
conn |> send_resp(202, "")
{:ok, event} ->
Plausible.Ingest.Session.on_event(event)
Plausible.Ingest.FingerprintSession.on_event(event)
update_fingerprint(event)
conn |> send_resp(202, "")
{:error, changeset} ->
request = Sentry.Plug.build_request_interface_data(conn, [])
@ -23,7 +21,6 @@ defmodule PlausibleWeb.Api.ExternalController do
def unload(conn, _params) do
params = parse_body(conn)
Plausible.Ingest.Session.on_unload(params["uid"], Timex.now())
fingerprint = calculate_fingerprint(conn, params)
Plausible.Ingest.FingerprintSession.on_unload(fingerprint, Timex.now())
conn |> send_resp(202, "")
@ -35,13 +32,6 @@ defmodule PlausibleWeb.Api.ExternalController do
send_resp(conn, 200, "")
end
defp update_fingerprint(%Plausible.Event{new_visitor: true}), do: nil
defp update_fingerprint(event) do
use Plausible.Repo
q = from(e in Plausible.Event, where: e.user_id == ^event.user_id and is_nil(e.fingerprint))
Repo.update_all(q, set: [fingerprint: event.fingerprint])
end
defp create_event(conn, params) do
uri = URI.parse(params["url"])
country_code = Plug.Conn.get_req_header(conn, "cf-ipcountry") |> List.first

View File

@ -1,4 +1,4 @@
<%= if Mix.env() == :prod && !@conn.assigns[:skip_plausible_tracking] do %>
<script async defer src="https://plausible.io/js/plausible.js"></script>
<%= if !@conn.assigns[:skip_plausible_tracking] do %>
<script async defer data-track-acquisition src="http://localtest.me:8000/js/plausible.js"></script>
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>
<% end %>

View File

@ -0,0 +1,14 @@
defmodule Plausible.Repo.Migrations.BackfillFingerprints do
use Ecto.Migration
def change do
execute "UPDATE events set fingerprint=user_id where fingerprint is null"
execute """
INSERT INTO fingerprint_sessions (hostname, domain, fingerprint, start, length, is_bounce, entry_page, exit_page, referrer, referrer_source, country_code, screen_size, operating_system, browser, timestamp)
SELECT hostname, domain, user_id, start, length, is_bounce, entry_page, exit_page, referrer, referrer_source, country_code, screen_size, operating_system, browser, timestamp
FROM sessions
WHERE sessions.timestamp < '2020-02-27 11:40:55';
"""
end
end

View File

@ -0,0 +1,80 @@
defmodule Plausible.Ingest.FingerprintSessionTest do
use Plausible.DataCase
alias Plausible.Ingest
defp capture_session(fingerprint) do
session_pid = :global.whereis_name(fingerprint)
Process.monitor(session_pid)
assert_receive({:DOWN, session_pid, :process, _, :normal})
Repo.one(Plausible.FingerprintSession)
end
describe "on_event/1" do
test "starts a new session if there is no session for user id" do
pageview = insert(:pageview)
refute is_pid(:global.whereis_name(pageview.fingerprint))
Ingest.FingerprintSession.on_event(pageview)
assert is_pid(:global.whereis_name(pageview.fingerprint))
end
test "copies event data to session" do
pageview = insert(:pageview)
Ingest.FingerprintSession.on_event(pageview)
session = capture_session(pageview.fingerprint)
assert session.fingerprint == pageview.fingerprint
assert session.start == pageview.timestamp
end
test "inserts bounced session when timeout fires after one pageview" do
pageview = insert(:pageview)
Ingest.FingerprintSession.on_event(pageview)
session = capture_session(pageview.fingerprint)
assert session.is_bounce
end
test "session with two events is not a bounce" do
pageview = insert(:pageview)
pageview2 = insert(:pageview, fingerprint: pageview.fingerprint)
Ingest.FingerprintSession.on_event(pageview)
Ingest.FingerprintSession.on_event(pageview2)
session = capture_session(pageview.fingerprint)
refute session.is_bounce
end
test "captures the exit page" do
pageview = insert(:pageview)
pageview2 = insert(:pageview, fingerprint: pageview.fingerprint, pathname: "/exit")
Ingest.FingerprintSession.on_event(pageview)
Ingest.FingerprintSession.on_event(pageview2)
session = capture_session(pageview.fingerprint)
assert session.exit_page == "/exit"
end
end
describe "on_unload/1" do
test "uses the unload timestamp to calculate session length" do
pageview = insert(:pageview)
unload_timestamp = Timex.shift(pageview.timestamp, seconds: 30)
Ingest.FingerprintSession.on_event(pageview)
Ingest.FingerprintSession.on_unload(pageview.fingerprint, unload_timestamp)
session = capture_session(pageview.fingerprint)
assert session.length == 30
end
end
end

View File

@ -2,8 +2,8 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
use PlausibleWeb.ConnCase
use Plausible.Repo
defp finalize_session(user_id) do
session_pid = :global.whereis_name(user_id)
defp finalize_session(fingerprint) do
session_pid = :global.whereis_name(fingerprint)
Process.monitor(session_pid)
assert_receive({:DOWN, session_pid, _, _, _})
@ -12,28 +12,6 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
@user_agent "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36"
@country_code "EE"
test "TEMP - adding historical fingerprints", %{conn: conn} do
uid = UUID.uuid4()
insert(:pageview, domain: "gigride.live", user_id: uid, new_visitor: true)
params = %{
name: "pageview",
url: "http://gigride.live/",
new_visitor: false,
uid: uid
}
conn
|> put_req_header("content-type", "text/plain")
|> put_req_header("user-agent", @user_agent)
|> post("/api/event", Jason.encode!(params))
[pageview1, pageview2] = Repo.all(Plausible.Event)
finalize_session(uid)
assert pageview1.fingerprint == pageview2.fingerprint
end
describe "POST /api/event" do
test "records the event", %{conn: conn} do
params = %{
@ -52,7 +30,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
|> post("/api/event", Jason.encode!(params))
pageview = Repo.one(Plausible.Event)
finalize_session(pageview.user_id)
finalize_session(pageview.fingerprint)
assert response(conn, 202) == ""
assert pageview.hostname == "gigride.live"
@ -77,7 +55,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
|> post("/api/event", Jason.encode!(params))
event = Repo.one(Plausible.Event)
finalize_session(event.user_id)
finalize_session(event.fingerprint)
assert response(conn, 202) == ""
assert event.domain == "some_site.com"
@ -97,7 +75,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
|> post("/api/event", Jason.encode!(params))
pageview = Repo.one(Plausible.Event)
finalize_session(pageview.user_id)
finalize_session(pageview.fingerprint)
assert pageview.domain == "some_site.com"
end
@ -115,7 +93,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
|> post("/api/event", Jason.encode!(params))
pageview = Repo.one(Plausible.Event)
finalize_session(pageview.user_id)
finalize_session(pageview.fingerprint)
assert pageview.hostname == "example.com"
end
@ -151,7 +129,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
|> post("/api/event", Jason.encode!(params))
pageview = Repo.one(Plausible.Event)
finalize_session(pageview.user_id)
finalize_session(pageview.fingerprint)
assert response(conn, 202) == ""
assert pageview.operating_system == "Mac"
@ -174,7 +152,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
|> post("/api/event", Jason.encode!(params))
pageview = Repo.one(Plausible.Event)
finalize_session(pageview.user_id)
finalize_session(pageview.fingerprint)
assert response(conn, 202) == ""
assert pageview.referrer_source == "Facebook"
@ -197,7 +175,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
|> post("/api/event", Jason.encode!(params))
pageview = Repo.one(Plausible.Event)
finalize_session(pageview.user_id)
finalize_session(pageview.fingerprint)
assert response(conn, 202) == ""
assert pageview.referrer == "facebook.com/page"
@ -222,7 +200,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
|> post("/api/event", Jason.encode!(params))
pageview = Repo.one(Plausible.Event)
finalize_session(pageview.user_id)
finalize_session(pageview.fingerprint)
assert response(conn, 202) == ""
assert pageview.referrer_source == nil
@ -245,7 +223,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
|> post("/api/event", Jason.encode!(params))
pageview = Repo.one(Plausible.Event)
finalize_session(pageview.user_id)
finalize_session(pageview.fingerprint)
assert response(conn, 202) == ""
assert pageview.referrer_source == nil
@ -268,7 +246,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
|> post("/api/event", Jason.encode!(params))
pageview = Repo.one(Plausible.Event)
finalize_session(pageview.user_id)
finalize_session(pageview.fingerprint)
assert response(conn, 202) == ""
assert pageview.referrer_source == "blog.gigride.live"
@ -290,7 +268,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
|> post("/api/event", Jason.encode!(params))
pageview = Repo.one(Plausible.Event)
finalize_session(pageview.user_id)
finalize_session(pageview.fingerprint)
assert pageview.referrer == "indiehackers.com/page"
assert pageview.initial_referrer == "indiehackers.com"
@ -312,7 +290,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
|> post("/api/event", Jason.encode!(params))
pageview = Repo.one(Plausible.Event)
finalize_session(pageview.user_id)
finalize_session(pageview.fingerprint)
assert pageview.referrer_source == "betalist"
assert pageview.initial_referrer_source == "betalist"
@ -333,7 +311,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
|> post("/api/event", Jason.encode!(params))
pageview = Repo.one(Plausible.Event)
finalize_session(pageview.user_id)
finalize_session(pageview.fingerprint)
assert response(conn, 202) == ""
assert pageview.referrer_source == "indiehackers.com"
@ -354,7 +332,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
|> post("/api/event", Jason.encode!(params))
pageview = Repo.one(Plausible.Event)
finalize_session(pageview.user_id)
finalize_session(pageview.fingerprint)
assert response(conn, 202) == ""
assert is_nil(pageview.referrer_source)
@ -377,7 +355,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
|> post("/api/event", Jason.encode!(params))
pageview = Repo.one(Plausible.Event)
finalize_session(pageview.user_id)
finalize_session(pageview.fingerprint)
assert response(conn, 202) == ""
assert pageview.screen_size == "Mobile"
@ -397,7 +375,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
|> post("/api/event", Jason.encode!(params))
pageview = Repo.one(Plausible.Event)
finalize_session(pageview.user_id)
finalize_session(pageview.fingerprint)
assert response(conn, 202) == ""
assert pageview.screen_size == nil
@ -417,7 +395,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
|> post("/api/event", Jason.encode!(params))
event = Repo.one(Plausible.Event)
finalize_session(event.user_id)
finalize_session(event.fingerprint)
assert response(conn, 202) == ""
assert event.name == "custom event"

View File

@ -8,7 +8,7 @@ defmodule PlausibleWeb.Api.StatsController.CurrentVisitorsTest do
test "returns unique users in the last 5 minutes", %{conn: conn, site: site} do
insert(:pageview, domain: site.domain)
event2 = insert(:pageview, domain: site.domain, timestamp: Timex.now() |> Timex.shift(minutes: -3))
insert(:pageview, domain: site.domain, user_id: event2.user_id, timestamp: Timex.now() |> Timex.shift(minutes: -4))
insert(:pageview, domain: site.domain, fingerprint: event2.fingerprint, timestamp: Timex.now() |> Timex.shift(minutes: -4))
insert(:pageview, domain: site.domain, timestamp: Timex.now() |> Timex.shift(minutes: -6))
conn = get(conn, "/api/stats/#{site.domain}/current-visitors?period=day&date=2019-01-01")

View File

@ -88,8 +88,8 @@ defmodule PlausibleWeb.Api.StatsController.MainGraphTest do
setup [:create_user, :log_in, :create_site]
test "unique users counts distinct user ids", %{conn: conn, site: site} do
insert(:pageview, domain: site.domain, user_id: @user_id, timestamp: ~N[2019-01-01 00:00:00])
insert(:pageview, domain: site.domain, user_id: @user_id, timestamp: ~N[2019-01-01 23:59:00])
insert(:pageview, domain: site.domain, fingerprint: @user_id, timestamp: ~N[2019-01-01 00:00:00])
insert(:pageview, domain: site.domain, fingerprint: @user_id, timestamp: ~N[2019-01-01 23:59:00])
conn = get(conn, "/api/stats/#{site.domain}/main-graph?period=day&date=2019-01-01")
@ -108,8 +108,8 @@ defmodule PlausibleWeb.Api.StatsController.MainGraphTest do
end
test "counts total pageviews even from same user ids", %{conn: conn, site: site} do
insert(:pageview, domain: site.domain, user_id: @user_id, timestamp: ~N[2019-01-01 00:00:00])
insert(:pageview, domain: site.domain, user_id: @user_id, timestamp: ~N[2019-01-01 23:59:00])
insert(:pageview, domain: site.domain, fingerprint: @user_id, timestamp: ~N[2019-01-01 00:00:00])
insert(:pageview, domain: site.domain, fingerprint: @user_id, timestamp: ~N[2019-01-01 23:59:00])
conn = get(conn, "/api/stats/#{site.domain}/main-graph?period=day&date=2019-01-01")
@ -160,8 +160,8 @@ defmodule PlausibleWeb.Api.StatsController.MainGraphTest do
test "returns total unique visitors", %{conn: conn, site: site} do
insert(:pageview, domain: site.domain, timestamp: ~N[2019-01-01 02:00:00])
insert(:pageview, domain: site.domain, user_id: @user_id, timestamp: ~N[2019-01-01 01:00:00])
insert(:event, name: "Signup", domain: site.domain, user_id: @user_id, timestamp: ~N[2019-01-01 02:00:00])
insert(:pageview, domain: site.domain, fingerprint: @user_id, timestamp: ~N[2019-01-01 01:00:00])
insert(:event, name: "Signup", domain: site.domain, fingerprint: @user_id, timestamp: ~N[2019-01-01 02:00:00])
filters = Jason.encode!(%{goal: "Signup"})
conn = get(conn, "/api/stats/#{site.domain}/main-graph?period=day&date=2019-01-01&filters=#{filters}")

View File

@ -7,7 +7,7 @@ defmodule PlausibleWeb.Api.StatsController.ReferrersTest do
test "returns top referrer sources by user ids", %{conn: conn, site: site} do
pageview1 = insert(:pageview, domain: site.domain, referrer_source: "Google", timestamp: ~N[2019-01-01 01:00:00])
insert(:pageview, domain: site.domain, referrer_source: "Google", user_id: pageview1.user_id, timestamp: ~N[2019-01-01 02:00:00])
insert(:pageview, domain: site.domain, referrer_source: "Google", fingerprint: pageview1.fingerprint, timestamp: ~N[2019-01-01 02:00:00])
insert(:pageview, domain: site.domain, referrer_source: "Google", timestamp: ~N[2019-01-01 02:00:00])
insert(:pageview, domain: site.domain, referrer_source: "Bing", timestamp: ~N[2019-01-01 02:00:00])

View File

@ -26,12 +26,11 @@ defmodule Plausible.Factory do
def session_factory do
hostname = sequence(:domain, &"example-#{&1}.com")
%Plausible.Session{
%Plausible.FingerprintSession{
hostname: hostname,
domain: hostname,
new_visitor: true,
entry_page: "/",
user_id: UUID.uuid4(),
fingerprint: UUID.uuid4(),
start: Timex.now(),
is_bounce: false
}
@ -53,7 +52,9 @@ defmodule Plausible.Factory do
hostname: hostname,
domain: hostname,
pathname: "/",
new_visitor: true, user_id: UUID.uuid4(),
new_visitor: true,
user_id: UUID.uuid4(),
fingerprint: UUID.uuid4()
}
end