analytics / test /plausible_web /controllers /stats_controller_test.exs
Leon4gr45's picture
Upload folder using huggingface_hub (part 6)
6778ee0 verified
Raw
History Blame Contribute Delete
34.9 kB
defmodule PlausibleWeb.StatsControllerTest do
use PlausibleWeb.ConnCase, async: false
use Plausible.Repo
@react_container "div#stats-react-container"
describe "GET /:domain - anonymous user" do
test "public site - shows site stats", %{conn: conn} do
site = new_site(public: true)
populate_stats(site, [build(:pageview)])
conn = get(conn, "/#{site.domain}")
resp = html_response(conn, 200)
assert element_exists?(resp, @react_container)
assert text_of_attr(resp, @react_container, "data-domain") == site.domain
assert text_of_attr(resp, @react_container, "data-is-dbip") == "false"
assert text_of_attr(resp, @react_container, "data-has-goals") == "false"
assert text_of_attr(resp, @react_container, "data-conversions-opted-out") == "false"
assert text_of_attr(resp, @react_container, "data-funnels-opted-out") == "false"
assert text_of_attr(resp, @react_container, "data-props-opted-out") == "false"
assert text_of_attr(resp, @react_container, "data-props-available") == "true"
assert text_of_attr(resp, @react_container, "data-site-segments-available") == "true"
assert text_of_attr(resp, @react_container, "data-funnels-available") == "true"
assert text_of_attr(resp, @react_container, "data-exploration-available") == "true"
assert text_of_attr(resp, @react_container, "data-has-props") == "false"
assert text_of_attr(resp, @react_container, "data-logged-in") == "false"
assert text_of_attr(resp, @react_container, "data-current-user-role") == "public"
assert text_of_attr(resp, @react_container, "data-current-user-id") == "null"
assert text_of_attr(resp, @react_container, "data-embedded") == ""
assert text_of_attr(resp, @react_container, "data-is-consolidated-view") == "false"
assert text_of_attr(resp, @react_container, "data-consolidated-view-available") == "false"
assert text_of_attr(resp, @react_container, "data-team-identifier") == site.team.identifier
assert "noindex, nofollow" ==
resp
|> find("meta[name=robots]")
|> text_of_attr("content")
assert to_string(Plausible.InternalStatsApiVersion.api_version()) ==
resp
|> find("meta[name=x-api-version]")
|> text_of_attr("content")
assert text_of_element(resp, "title") == "Plausible · #{site.domain}"
end
test "public site - all segments (personal or site) are stuffed into dataset, without their owner_id and owner_name",
%{conn: conn} do
user = new_user()
site = new_site(owner: user, public: true)
populate_stats(site, [build(:pageview)])
emea_site_segment =
insert(:segment,
site: site,
owner: user,
type: :site,
name: "EMEA region"
)
foo_personal_segment =
insert(:segment,
site: site,
owner: user,
type: :personal,
name: "FOO"
)
conn = get(conn, "/#{site.domain}")
resp = html_response(conn, 200)
assert element_exists?(resp, @react_container)
assert text_of_attr(resp, @react_container, "data-segments") ==
Jason.encode!([
Plausible.Segments.to_response_map(
%{foo_personal_segment | owner_id: nil},
site
),
Plausible.Segments.to_response_map(%{emea_site_segment | owner_id: nil}, site)
])
end
@tag :ee_only
test "plausible.io live demo - shows site stats, header and footer", %{conn: conn} do
site = new_site(domain: "plausible.io", public: true)
populate_stats(site, [build(:pageview)])
conn = get(conn, "/#{site.domain}")
resp = html_response(conn, 200)
assert element_exists?(resp, @react_container)
assert "index, nofollow" ==
resp
|> find("meta[name=robots]")
|> text_of_attr("content")
assert text_of_element(resp, "title") == "Plausible Analytics: Live Demo"
assert resp =~ "Login"
assert resp =~ "You just saw how Plausible tracks plausible.io"
assert resp =~ "Start free trial"
assert resp =~ "See pricing"
assert resp =~ "Getting started"
end
test "public site - redirect to /login when no stats because verification requires it", %{
conn: conn
} do
new_site(domain: "some-other-public-site.io", public: true)
conn = get(conn, conn |> get("/some-other-public-site.io") |> redirected_to())
assert redirected_to(conn) ==
Routes.auth_path(conn, :login_form,
return_to: "/some-other-public-site.io/verification"
)
end
test "public site - no stats with skip_to_dashboard", %{
conn: conn
} do
new_site(domain: "some-other-public-site.io", public: true)
conn = get(conn, "/some-other-public-site.io?skip_to_dashboard=true")
resp = html_response(conn, 200)
assert text_of_attr(resp, @react_container, "data-logged-in") == "false"
end
test "can not view stats of a private website", %{conn: conn} do
_ = insert(:user)
conn = get(conn, "/test-site.com")
assert html_response(conn, 404) =~ "There's nothing here"
end
end
describe "GET /:domain - as a logged in user" do
setup [:create_user, :log_in, :create_site]
test "can view stats of a website I've created", %{conn: conn, site: site, user: user} do
populate_stats(site, [build(:pageview)])
conn = get(conn, "/" <> site.domain)
resp = html_response(conn, 200)
assert text_of_attr(resp, @react_container, "data-logged-in") == "true"
assert text_of_attr(resp, @react_container, "data-current-user-role") == "owner"
assert text_of_attr(resp, @react_container, "data-current-user-id") == "#{user.id}"
end
test "can view stats of a website I've created, enforcing pageviews check skip", %{
conn: conn,
site: site
} do
resp = conn |> get(conn |> get("/" <> site.domain) |> redirected_to()) |> html_response(200)
refute text_of_attr(resp, @react_container, "data-logged-in") == "true"
resp = conn |> get("/" <> site.domain <> "?skip_to_dashboard=true") |> html_response(200)
assert text_of_attr(resp, @react_container, "data-logged-in") == "true"
end
on_ee do
test "can't see exploration funnel UI if funnels feature unavailable", %{
conn: conn,
site: site,
user: user
} do
subscribe_to_growth_plan(user)
populate_stats(site, [build(:pageview)])
conn = get(conn, "/" <> site.domain)
resp = html_response(conn, 200)
assert text_of_attr(resp, @react_container, "data-exploration-available") == "false"
end
test "can see exploration funnel UI on trial", %{conn: conn, site: site} do
populate_stats(site, [build(:pageview)])
conn = get(conn, "/" <> site.domain)
resp = html_response(conn, 200)
assert text_of_attr(resp, @react_container, "data-exploration-available") == "true"
end
test "can see exploration funnel UI past trial with funnels feature enabled", %{
conn: conn,
site: site,
user: user
} do
populate_stats(site, [build(:pageview)])
site.team
|> Plausible.Teams.Team.end_trial()
|> Plausible.Repo.update!()
subscribe_to_enterprise_plan(user, features: [Plausible.Billing.Feature.Funnels])
conn = get(conn, "/" <> site.domain)
resp = html_response(conn, 200)
assert text_of_attr(resp, @react_container, "data-exploration-available") == "true"
end
end
on_ee do
test "first view of a consolidated dashboard sets stats_start_date and native_stats_start_at according to native_stats_start_at of the earliest team site",
%{
conn: conn,
site: site,
user: user
} do
team = team_of(user)
now = NaiveDateTime.utc_now(:second)
ten_days_ago = NaiveDateTime.add(now, -10, :day)
twenty_days_ago = NaiveDateTime.add(now, -20, :day)
site
|> Plausible.Site.set_native_stats_start_at(ten_days_ago)
|> Plausible.Repo.update!()
new_site(team: team, native_stats_start_at: twenty_days_ago)
cv = new_consolidated_view(team)
conn = get(conn, "/" <> cv.domain)
resp = html_response(conn, 200)
assert text_of_attr(resp, @react_container, "data-domain") == cv.domain
assert text_of_attr(resp, @react_container, "data-logged-in") == "true"
assert text_of_attr(resp, @react_container, "data-current-user-role") == "owner"
assert text_of_attr(resp, @react_container, "data-current-user-id") == "#{user.id}"
cv = Plausible.Repo.reload(cv)
assert cv.stats_start_date == NaiveDateTime.to_date(twenty_days_ago)
assert cv.native_stats_start_at == twenty_days_ago
end
test "does not redirect consolidated views to verification", %{
conn: conn,
user: user
} do
new_site(owner: user)
new_site(owner: user)
cv = user |> team_of() |> new_consolidated_view()
conn = get(conn, "/" <> cv.domain)
resp = html_response(conn, 200)
assert text_of_attr(resp, @react_container, "data-domain") == cv.domain
assert text_of_attr(resp, @react_container, "data-logged-in") == "true"
assert text_of_attr(resp, @react_container, "data-current-user-role") == "owner"
assert text_of_attr(resp, @react_container, "data-current-user-id") == "#{user.id}"
end
test "redirects to /sites if for some reason ineligible anymore", %{
conn: conn,
user: user
} do
new_site(owner: user)
new_site(owner: user)
cv = user |> team_of() |> new_consolidated_view()
user
|> team_of()
|> Plausible.Teams.Team.end_trial()
|> Plausible.Repo.update!()
conn = get(conn, "/" <> cv.domain)
assert redirected_to(conn, 302) == "/sites"
end
end
@tag :ee_only
test "header, stats are shown; footer is not shown", %{conn: conn, site: site, user: user} do
populate_stats(site, [build(:pageview)])
conn = get(conn, "/" <> site.domain)
resp = html_response(conn, 200)
assert resp =~ user.name
assert text_of_attr(resp, @react_container, "data-logged-in") == "true"
refute resp =~ "Getting started"
end
@tag :ce_build_only
test "header, stats, footer are shown", %{conn: conn, site: site, user: user} do
populate_stats(site, [build(:pageview)])
conn = get(conn, "/" <> site.domain)
resp = html_response(conn, 200)
assert resp =~ user.name
assert text_of_attr(resp, @react_container, "data-logged-in") == "true"
assert resp =~ "Getting started"
end
test "shows locked page if site is locked", %{conn: conn, user: user} do
locked_site = new_site(owner: user)
locked_site.team |> Ecto.Changeset.change(locked: true) |> Repo.update!()
conn = get(conn, "/" <> locked_site.domain)
resp = html_response(conn, 200)
assert resp =~ "Your dashboard is unavailable"
assert resp =~ "Upgrade to the appropriate plan to restore access"
end
test "shows locked page if site is locked for billing role", %{conn: conn, user: user} do
other_user = new_user()
locked_site = new_site(owner: other_user)
locked_site.team |> Ecto.Changeset.change(locked: true) |> Repo.update!()
add_member(team_of(other_user), user: user, role: :billing)
conn = get(conn, "/" <> locked_site.domain)
resp = html_response(conn, 200)
assert resp =~ "Your dashboard is unavailable"
assert resp =~ "Upgrade to the appropriate plan to restore access"
end
test "shows locked page if site is locked for viewer role", %{conn: conn, user: user} do
other_user = new_user()
locked_site = new_site(owner: other_user)
locked_site.team |> Ecto.Changeset.change(locked: true) |> Repo.update!()
add_member(team_of(other_user), user: user, role: :viewer)
conn = get(conn, "/" <> locked_site.domain)
resp = html_response(conn, 200)
assert resp =~ "Your dashboard is unavailable"
refute resp =~ "Upgrade to the appropriate plan to restore access"
assert resp =~ "The owner of this site must upgrade their subscription plan"
end
test "shows locked page for anonymous" do
locked_site = new_site(public: true)
locked_site.team |> Ecto.Changeset.change(locked: true) |> Repo.update!()
conn = get(build_conn(), "/" <> locked_site.domain)
resp = html_response(conn, 200)
assert resp =~ "Your dashboard is unavailable"
assert resp =~ "You can check back later or contact the site owner"
end
test "can not view stats of someone else's website", %{conn: conn} do
site = new_site()
conn = get(conn, "/" <> site.domain)
assert html_response(conn, 404) =~ "There's nothing here"
end
test "does not show CRM link to the site", %{conn: conn, site: site} do
conn = get(conn, conn |> get("/" <> site.domain) |> redirected_to())
refute html_response(conn, 200) =~ "/cs/sites"
end
test "all segments (personal or site) are stuffed into dataset, with their associated owner_id and owner_name",
%{conn: conn, site: site, user: user} do
populate_stats(site, [build(:pageview)])
emea_site_segment =
insert(:segment,
site: site,
owner: user,
type: :site,
name: "EMEA region"
)
foo_personal_segment =
insert(:segment,
site: site,
owner: user,
type: :personal,
name: "FOO"
)
conn = get(conn, "/#{site.domain}")
resp = html_response(conn, 200)
assert element_exists?(resp, @react_container)
assert text_of_attr(resp, @react_container, "data-segments") ==
Jason.encode!([
Plausible.Segments.to_response_map(foo_personal_segment, site),
Plausible.Segments.to_response_map(emea_site_segment, site)
])
end
end
describe "GET /:domain - as a super admin" do
@describetag :ee_only
setup [:create_user, :make_user_super_admin, :log_in]
test "can view a private dashboard with stats", %{conn: conn, user: user} do
site = new_site()
populate_stats(site, [build(:pageview)])
conn = get(conn, "/" <> site.domain)
resp = html_response(conn, 200)
assert resp =~ "stats-react-container"
assert text_of_attr(resp, @react_container, "data-logged-in") == "true"
assert text_of_attr(resp, @react_container, "data-current-user-role") == "super_admin"
assert text_of_attr(resp, @react_container, "data-current-user-id") == "#{user.id}"
end
test "can enter verification when site is without stats", %{conn: conn} do
site = new_site()
conn = get(conn, conn |> get("/" <> site.domain) |> redirected_to())
assert html_response(conn, 200) =~ "Verifying your installation"
end
test "can view a private locked dashboard with stats", %{conn: conn} do
user = new_user()
site = new_site(owner: user)
site.team |> Ecto.Changeset.change(locked: true) |> Repo.update!()
populate_stats(site, [build(:pageview)])
conn = get(conn, "/" <> site.domain)
resp = html_response(conn, 200)
assert resp =~ "This dashboard is actually locked"
end
test "can view private locked verification without stats", %{conn: conn} do
user = new_user()
site = new_site(owner: user)
site.team |> Ecto.Changeset.change(locked: true) |> Repo.update!()
conn = get(conn, conn |> get("/#{site.domain}") |> redirected_to())
assert html_response(conn, 200) =~ "Verifying your installation"
end
test "can view a locked public dashboard", %{conn: conn} do
site = new_site(public: true)
site.team |> Ecto.Changeset.change(locked: true) |> Repo.update!()
populate_stats(site, [build(:pageview)])
conn = get(conn, "/" <> site.domain)
resp = html_response(conn, 200)
assert resp =~ "This dashboard is actually locked"
end
on_ee do
test "shows CRM link to the site", %{conn: conn} do
site = new_site()
conn = get(conn, conn |> get("/" <> site.domain) |> redirected_to())
assert html_response(conn, 200) =~
Routes.customer_support_site_path(PlausibleWeb.Endpoint, :show, site.id)
end
end
end
defp make_user_super_admin(%{user: user}) do
Application.put_env(:plausible, :super_admin_user_ids, [user.id])
end
describe "GET /share/:domain?auth=:auth" do
test "prompts a password for a password-protected link", %{conn: conn} do
site = new_site()
link =
insert(:shared_link, site: site, password_hash: Plausible.Auth.Password.hash("password"))
conn = get(conn, "/share/#{site.domain}?auth=#{link.slug}")
assert response(conn, 200) =~ "Enter password"
end
test "if the shared link is not protected with a password, passes user immediately to dashboard",
%{
conn: conn
} do
site = new_site(domain: "test-site.com")
link = insert(:shared_link, site: site)
conn = get(conn, "/share/test-site.com/?auth=#{link.slug}")
resp = html_response(conn, 200)
assert resp =~ "stats-react-container"
assert text_of_attr(resp, @react_container, "data-logged-in") == "false"
assert text_of_attr(resp, @react_container, "data-current-user-id") == "null"
assert text_of_attr(resp, @react_container, "data-current-user-role") == "public"
end
test "if the shared link is limited to a segment, only that segment is stuffed into data-segments",
%{
conn: conn
} do
site = new_site(domain: "test-site.com")
emea_site_segment = insert(:segment, name: "EMEA", site: site, type: :site)
apac_site_segment = insert(:segment, name: "APAC", site: site, type: :site)
link = insert(:shared_link, site: site, segment: emea_site_segment)
conn = get(conn, "/share/test-site.com/?auth=#{link.slug}")
resp = html_response(conn, 200)
assert resp =~ "stats-react-container"
assert text_of_attr(resp, @react_container, "data-limited-to-segment-id") ==
"#{emea_site_segment.id}"
assert text_of_attr(resp, @react_container, "data-segments") ==
emea_site_segment
|> Plausible.Segments.to_response_map(site)
|> List.wrap()
|> Jason.encode!()
refute resp =~ apac_site_segment.name
assert text_of_attr(resp, @react_container, "data-current-user-role") == "public"
end
test "footer and header are shown when accessing shared link dashboard", %{
conn: conn
} do
site = new_site(domain: "test-site.com")
link = insert(:shared_link, site: site)
conn = get(conn, "/share/test-site.com/?auth=#{link.slug}")
resp = html_response(conn, 200)
assert resp =~ "stats-react-container"
assert text_of_attr(resp, @react_container, "data-logged-in") == "false"
assert text_of_attr(resp, @react_container, "data-current-user-id") == "null"
assert text_of_attr(resp, @react_container, "data-current-user-role") == "public"
assert resp =~ "Login"
assert resp =~ "Getting started"
end
test "returns page with X-Frame-Options disabled so it can be embedded in an iframe", %{
conn: conn
} do
site = new_site(domain: "test-site.com")
link = insert(:shared_link, site: site)
conn = get(conn, "/share/test-site.com/?auth=#{link.slug}")
resp = html_response(conn, 200)
assert text_of_attr(resp, @react_container, "data-embedded") == "false"
assert Plug.Conn.get_resp_header(conn, "x-frame-options") == []
end
test "returns page embedded page", %{
conn: conn
} do
site = new_site(domain: "test-site.com")
link = insert(:shared_link, site: site)
conn = get(conn, "/share/test-site.com/?auth=#{link.slug}&embed=true")
resp = html_response(conn, 200)
assert text_of_attr(resp, @react_container, "data-embedded") == "true"
assert text_of_attr(resp, @react_container, "data-logged-in") == "false"
assert text_of_attr(resp, @react_container, "data-current-user-id") == "null"
assert text_of_attr(resp, @react_container, "data-current-user-role") == "public"
assert Plug.Conn.get_resp_header(conn, "x-frame-options") == []
end
test "does not show header, does not show footer on embedded pages", %{conn: conn} do
site = new_site(domain: "test-site.com")
link = insert(:shared_link, site: site)
conn = get(conn, "/share/test-site.com/?auth=#{link.slug}&embed=true")
resp = html_response(conn, 200)
assert text_of_attr(resp, @react_container, "data-embedded") == "true"
refute resp =~ "Login"
refute resp =~ "Getting started"
end
test "shows locked page if page is locked", %{conn: conn} do
site = new_site(domain: "test-site.com")
site.team |> Ecto.Changeset.change(locked: true) |> Repo.update!()
link = insert(:shared_link, site: site)
conn = get(conn, "/share/test-site.com/?auth=#{link.slug}")
assert html_response(conn, 200) =~ "Your dashboard is unavailable"
refute String.contains?(html_response(conn, 200), "Back to my sites")
end
test "shows locked page if shared link is locked due to insufficient team subscription", %{
conn: conn
} do
site = new_site(domain: "test-site.com")
link = insert(:shared_link, site: site)
insert(:starter_subscription, team: site.team)
conn = get(conn, "/share/test-site.com/?auth=#{link.slug}")
assert html_response(conn, 200) =~ "Shared link unavailable"
refute String.contains?(html_response(conn, 200), "Back to my sites")
end
for special_name <- Plausible.Sites.shared_link_special_names() do
test "shows dashboard if team subscription insufficient but shared link name is '#{special_name}'",
%{conn: conn} do
site = new_site(domain: "test-site.com")
link = insert(:shared_link, site: site, name: unquote(special_name))
insert(:starter_subscription, team: site.team)
html =
conn
|> get("/share/test-site.com/?auth=#{link.slug}")
|> html_response(200)
assert element_exists?(html, @react_container)
refute html =~ "Shared Link Unavailable"
end
end
test "renders 404 not found when no auth parameter supplied", %{conn: conn} do
conn = get(conn, "/share/example.com")
assert response(conn, 404) =~ "nothing here"
end
test "renders 404 not found when non-existent auth parameter is supplied", %{conn: conn} do
conn = get(conn, "/share/example.com?auth=bad-token")
assert response(conn, 404) =~ "nothing here"
end
test "renders 404 not found when auth parameter for another site is supplied", %{conn: conn} do
site1 = insert(:site, domain: "test-site-1.com")
site2 = insert(:site, domain: "test-site-2.com")
site1_link = insert(:shared_link, site: site1)
conn = get(conn, "/share/#{site2.domain}/?auth=#{site1_link.slug}")
assert response(conn, 404) =~ "nothing here"
end
test "all segments (personal or site) are stuffed into dataset, without their owner_id and owner_name",
%{conn: conn} do
user = new_user()
site = new_site(domain: "test-site.com", owner: user)
link = insert(:shared_link, site: site)
emea_site_segment =
insert(:segment,
site: site,
owner: user,
type: :site,
name: "EMEA region"
)
foo_personal_segment =
insert(:segment,
site: site,
owner: user,
type: :personal,
name: "FOO"
)
conn = get(conn, "/share/#{site.domain}/?auth=#{link.slug}")
resp = html_response(conn, 200)
assert text_of_attr(resp, @react_container, "data-segments") ==
Jason.encode!([
Plausible.Segments.to_response_map(
%{foo_personal_segment | owner_id: nil},
site
),
Plausible.Segments.to_response_map(%{emea_site_segment | owner_id: nil}, site)
])
end
end
describe "GET /share/:slug - backwards compatibility" do
test "it redirects to new shared link format for historical links", %{conn: conn} do
site = insert(:site, domain: "test-site.com")
site_link = insert(:shared_link, site: site, inserted_at: ~N[2021-12-31 00:00:00])
conn = get(conn, "/share/#{site_link.slug}")
assert redirected_to(conn, 302) == "/share/#{site.domain}/?auth=#{site_link.slug}"
end
test "it does nothing for newer links", %{conn: conn} do
site = insert(:site, domain: "test-site.com")
site_link = insert(:shared_link, site: site, inserted_at: ~N[2022-01-01 00:00:00])
conn = get(conn, "/share/#{site_link.slug}")
assert response(conn, 404) =~ "nothing here"
end
end
describe "POST /share/:slug/authenticate" do
test "logs anonymous user in with correct password", %{conn: conn} do
site = new_site(domain: "test-site.com")
link =
insert(:shared_link, site: site, password_hash: Plausible.Auth.Password.hash("password"))
conn = post(conn, "/share/#{link.slug}/authenticate", %{password: "password"})
assert redirected_to(conn, 302) == "/share/#{site.domain}/?auth=#{link.slug}"
conn = get(conn, "/share/#{site.domain}?auth=#{link.slug}")
assert html_response(conn, 200) =~ "stats-react-container"
end
test "shows form again with wrong password", %{conn: conn} do
site = insert(:site, domain: "test-site.com")
link =
insert(:shared_link, site: site, password_hash: Plausible.Auth.Password.hash("password"))
conn = post(conn, "/share/#{link.slug}/authenticate", %{password: "WRONG!"})
assert html_response(conn, 200) =~ "Enter password"
end
test "only gives access to the correct dashboard", %{conn: conn} do
site = new_site(domain: "test-site.com")
site2 = new_site(domain: "test-site2.com")
link =
insert(:shared_link, site: site, password_hash: Plausible.Auth.Password.hash("password"))
link2 =
insert(:shared_link,
site: site2,
password_hash: Plausible.Auth.Password.hash("password1")
)
conn = post(conn, "/share/#{link.slug}/authenticate", %{password: "password"})
assert redirected_to(conn, 302) == "/share/#{site.domain}/?auth=#{link.slug}"
conn = get(conn, "/share/#{site2.domain}?auth=#{link2.slug}")
assert html_response(conn, 200) =~ "Enter password"
end
test "preserves query parameters during password authentication", %{conn: conn} do
site = new_site()
link =
insert(:shared_link, site: site, password_hash: Plausible.Auth.Password.hash("password"))
filters = "f=is,country,EE&l=EE,Estonia&f=is,browser,Firefox"
conn =
get(
conn,
"/share/#{URI.encode_www_form(site.domain)}?auth=#{link.slug}&#{filters}"
)
assert html_response(conn, 200) =~ "Enter password"
html = html_response(conn, 200)
expected_action_string =
"/share/#{URI.encode_www_form(link.slug)}/authenticate?auth=#{link.slug}&#{filters}"
assert text_of_attr(html, "form", "action") == expected_action_string
conn =
post(
conn,
expected_action_string,
%{password: "WRONG!"}
)
html = html_response(conn, 200)
assert html =~ "Enter password"
assert html =~ "Incorrect password"
assert text_of_attr(html, "form", "action") == expected_action_string
conn =
post(
conn,
expected_action_string,
%{password: "password"}
)
expected_redirect =
"/share/#{URI.encode_www_form(site.domain)}/?auth=#{link.slug}&#{filters}"
assert redirected_to(conn, 302) == expected_redirect
conn = get(conn, expected_redirect)
assert html_response(conn, 200) =~ "stats-react-container"
end
end
test "handles return_to during password authentication", %{conn: conn} do
site = new_site()
link =
insert(:shared_link, site: site, password_hash: Plausible.Auth.Password.hash("password"))
filters = "f=is,country,EE&l=EE,Estonia&f=is,browser,Firefox"
deep_path = "/filter/source"
conn =
get(
conn,
"/share/#{URI.encode_www_form(site.domain)}#{deep_path}?auth=#{link.slug}&#{filters}"
)
assert html_response(conn, 200) =~ "Enter password"
html = html_response(conn, 200)
expected_action_string =
"/share/#{link.slug}/authenticate?auth=#{link.slug}&#{filters}&#{URI.encode_query(%{"return_to" => deep_path})}"
assert text_of_attr(html, "form", "action") == expected_action_string
conn =
post(
conn,
expected_action_string,
%{password: "password"}
)
assert redirected_to(conn, 302) ==
"/share/#{URI.encode_www_form(site.domain)}#{deep_path}?auth=#{link.slug}&#{filters}"
end
test "return_to from query_params is discarded", %{conn: conn} do
site = new_site()
link =
insert(:shared_link, site: site, password_hash: Plausible.Auth.Password.hash("password"))
conn =
get(
conn,
"/share/#{URI.encode_www_form(site.domain)}/pages?auth=#{link.slug}&return_to=%2Ffoobar"
)
assert html_response(conn, 200) =~ "Enter password"
html = html_response(conn, 200)
expected_action_string =
"/share/#{link.slug}/authenticate?auth=#{link.slug}&return_to=%2Fpages"
assert text_of_attr(html, "form", "action") == expected_action_string
conn =
post(
conn,
expected_action_string,
%{password: "password"}
)
assert redirected_to(conn, 302) ==
"/share/#{URI.encode_www_form(site.domain)}/pages?auth=#{link.slug}"
end
test "return_to doesn't allow navigating out of dashboard context", %{conn: conn} do
site = new_site()
link =
insert(:shared_link, site: site, password_hash: Plausible.Auth.Password.hash("password"))
deep_path = "/../../settings/api-keys"
cleaned_deep_path = "/settings/api-keys"
conn =
get(
conn,
"/share/#{URI.encode_www_form(site.domain)}#{deep_path}?auth=#{link.slug}&theme=dark"
)
assert html_response(conn, 200) =~ "Enter password"
html = html_response(conn, 200)
expected_action_string =
"/share/#{link.slug}/authenticate?auth=#{link.slug}&theme=dark&#{URI.encode_query(%{"return_to" => deep_path})}"
assert text_of_attr(html, "form", "action") == expected_action_string
conn =
post(
conn,
expected_action_string,
%{password: "password"}
)
assert redirected_to(conn, 302) ==
"/share/#{URI.encode_www_form(site.domain)}#{cleaned_deep_path}?auth=#{link.slug}&theme=dark"
end
describe "dogfood tracking" do
@describetag :ee_only
test "does not set domain_to_replace on live demo dashboard", %{conn: conn} do
site = new_site(domain: "plausible.io", public: true)
populate_stats(site, [build(:pageview)])
conn = get(conn, "/#{site.domain}")
script_params = html_response(conn, 200) |> get_script_params()
assert %{
"location_override" => nil,
"domain_to_replace" => nil
} = script_params
end
test "sets domain_to_replace on any other dashboard", %{conn: conn} do
site = new_site(domain: "öö.ee", public: true)
populate_stats(site, [build(:pageview)])
conn = get(conn, "/#{site.domain}")
script_params = html_response(conn, 200) |> get_script_params()
assert %{
"location_override" => nil,
"domain_to_replace" => "%C3%B6%C3%B6.ee"
} = script_params
end
test "sets domain_to_replace on live demo shared link", %{conn: conn} do
site = new_site(domain: "plausible.io", public: true)
link = insert(:shared_link, site: site)
populate_stats(site, [build(:pageview)])
conn = get(conn, "/share/#{site.domain}/?auth=#{link.slug}")
script_params = html_response(conn, 200) |> get_script_params()
assert %{
"location_override" => nil,
"domain_to_replace" => "plausible.io"
} = script_params
end
test "sets location_override on a locked dashboard", %{conn: conn} do
locked_site = new_site(public: true)
locked_site.team |> Ecto.Changeset.change(locked: true) |> Repo.update!()
conn = get(conn, "/" <> locked_site.domain)
html = html_response(conn, 200)
script_params = html |> get_script_params()
assert html =~ "Your dashboard is unavailable"
assert script_params["location_override"] == PlausibleWeb.Endpoint.url() <> "/:dashboard"
end
test "sets location_override on a locked shared link", %{conn: conn} do
locked_site = new_site()
link = insert(:shared_link, site: locked_site)
insert(:starter_subscription, team: locked_site.team)
conn = get(conn, "/share/#{locked_site.domain}/?auth=#{link.slug}")
html = html_response(conn, 200)
script_params = get_script_params(html)
assert html =~ "Shared link unavailable"
assert script_params["location_override"] ==
PlausibleWeb.Endpoint.url() <> "/share/:dashboard"
end
test "sets location_override on shared_link_password.html", %{conn: conn} do
site = new_site()
link =
insert(:shared_link, site: site, password_hash: Plausible.Auth.Password.hash("password"))
conn = get(conn, "/share/#{site.domain}?auth=#{link.slug}")
html = html_response(conn, 200)
script_params = get_script_params(html)
assert html =~ "Enter password"
assert script_params["location_override"] ==
PlausibleWeb.Endpoint.url() <> "/share/:dashboard"
end
end
defp get_script_params(html) do
html
|> find("#dogfood-script")
|> text_of_attr("data-script-params")
|> JSON.decode!()
end
end