Apply feature gates to dashboard queries (#3424)
* Read feature status from Billing.Feature instead of %Site{}
This commit changes data attributes passed to React. Previously the
controller read feature statuses directly from the %Site{} schema. The
Billing.Feature context is aware of the user plan and the features
available.
* Limit funnels internal API based on site owner plan
* Limit props internal API based on site owner plan
* Use site factory in QueryTest
* Limit custom property filter based on site owner plan
* Limit revenue goals queries based on site owner plan
This commit is contained in:
parent
9b912f3d89
commit
896d78d8fd
|
|
@ -94,8 +94,10 @@ function DropdownContent({ history, site, query, wrapped }) {
|
||||||
const [addingFilter, setAddingFilter] = useState(false);
|
const [addingFilter, setAddingFilter] = useState(false);
|
||||||
|
|
||||||
if (wrapped === 0 || addingFilter) {
|
if (wrapped === 0 || addingFilter) {
|
||||||
return Object.keys(FILTER_GROUPS)
|
let filterGroups = {...FILTER_GROUPS}
|
||||||
.map((option) => filterDropdownOption(site, option))
|
if (!site.propsEnabled) delete filterGroups.props
|
||||||
|
|
||||||
|
return Object.keys(filterGroups).map((option) => filterDropdownOption(site, option))
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ defmodule Plausible.Stats.Query do
|
||||||
|> put_parsed_filters(params)
|
|> put_parsed_filters(params)
|
||||||
|> put_imported_opts(site, params)
|
|> put_imported_opts(site, params)
|
||||||
|> put_sample_threshold(params)
|
|> put_sample_threshold(params)
|
||||||
|
|> maybe_drop_prop_filter(site)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp query_by_period(site, %{"period" => "realtime"}) do
|
defp query_by_period(site, %{"period" => "realtime"}) do
|
||||||
|
|
@ -228,6 +229,19 @@ defmodule Plausible.Stats.Query do
|
||||||
|> Map.put(:include_imported, include_imported?(query, site, requested?))
|
|> Map.put(:include_imported, include_imported?(query, site, requested?))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp maybe_drop_prop_filter(query, site) do
|
||||||
|
prop_filter? = Map.has_key?(query.filters, "props")
|
||||||
|
|
||||||
|
props_available? = fn ->
|
||||||
|
site = Plausible.Repo.preload(site, :owner)
|
||||||
|
Plausible.Billing.Feature.Props.check_availability(site.owner) == :ok
|
||||||
|
end
|
||||||
|
|
||||||
|
if prop_filter? && !props_available?.(),
|
||||||
|
do: %__MODULE__{query | filters: Map.drop(query.filters, ["props"])},
|
||||||
|
else: query
|
||||||
|
end
|
||||||
|
|
||||||
@spec include_imported?(t(), Plausible.Site.t(), boolean()) :: boolean()
|
@spec include_imported?(t(), Plausible.Site.t(), boolean()) :: boolean()
|
||||||
def include_imported?(query, site, requested?) do
|
def include_imported?(query, site, requested?) do
|
||||||
cond do
|
cond do
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,8 @@ defmodule Plausible.Stats.Util do
|
||||||
{atom() | nil, [atom()]}
|
{atom() | nil, [atom()]}
|
||||||
@doc """
|
@doc """
|
||||||
Returns the common currency for the goal filters in a query. If there are no
|
Returns the common currency for the goal filters in a query. If there are no
|
||||||
goal filters, or multiple currencies, `nil` is returned and revenue metrics
|
goal filters, multiple currencies or the site owner does not have access to
|
||||||
are dropped.
|
revenue goals, `nil` is returned and revenue metrics are dropped.
|
||||||
|
|
||||||
Aggregating revenue data works only for same currency goals. If the query is
|
Aggregating revenue data works only for same currency goals. If the query is
|
||||||
filtered by goals with different currencies, for example, one USD and other
|
filtered by goals with different currencies, for example, one USD and other
|
||||||
|
|
@ -44,7 +44,15 @@ defmodule Plausible.Stats.Util do
|
||||||
_any -> []
|
_any -> []
|
||||||
end
|
end
|
||||||
|
|
||||||
if Enum.any?(metrics, &(&1 in @revenue_metrics)) && Enum.any?(goal_filters) do
|
requested_revenue_metrics? = Enum.any?(metrics, &(&1 in @revenue_metrics))
|
||||||
|
filtering_by_goal? = Enum.any?(goal_filters)
|
||||||
|
|
||||||
|
revenue_goals_available? = fn ->
|
||||||
|
site = Plausible.Repo.preload(site, :owner)
|
||||||
|
Plausible.Billing.Feature.RevenueGoals.check_availability(site.owner) == :ok
|
||||||
|
end
|
||||||
|
|
||||||
|
if requested_revenue_metrics? && filtering_by_goal? && revenue_goals_available?.() do
|
||||||
revenue_goals_currencies =
|
revenue_goals_currencies =
|
||||||
Plausible.Repo.all(
|
Plausible.Repo.all(
|
||||||
from rg in Ecto.assoc(site, :revenue_goals),
|
from rg in Ecto.assoc(site, :revenue_goals),
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ defmodule PlausibleWeb.Api.StatsController do
|
||||||
use Plug.ErrorHandler
|
use Plug.ErrorHandler
|
||||||
alias Plausible.Stats
|
alias Plausible.Stats
|
||||||
alias Plausible.Stats.{Query, Filters, Comparisons}
|
alias Plausible.Stats.{Query, Filters, Comparisons}
|
||||||
|
alias PlausibleWeb.Api.Helpers, as: H
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
|
|
@ -513,9 +514,10 @@ defmodule PlausibleWeb.Api.StatsController do
|
||||||
end
|
end
|
||||||
|
|
||||||
def funnel(conn, %{"id" => funnel_id} = params) do
|
def funnel(conn, %{"id" => funnel_id} = params) do
|
||||||
site = conn.assigns[:site]
|
site = Plausible.Repo.preload(conn.assigns.site, :owner)
|
||||||
|
|
||||||
with :ok <- validate_params(site, params),
|
with :ok <- Plausible.Billing.Feature.Funnels.check_availability(site.owner),
|
||||||
|
:ok <- validate_params(site, params),
|
||||||
query <- Query.from(site, params) |> Filters.add_prefix(),
|
query <- Query.from(site, params) |> Filters.add_prefix(),
|
||||||
:ok <- validate_funnel_query(query),
|
:ok <- validate_funnel_query(query),
|
||||||
{funnel_id, ""} <- Integer.parse(funnel_id),
|
{funnel_id, ""} <- Integer.parse(funnel_id),
|
||||||
|
|
@ -537,6 +539,12 @@ defmodule PlausibleWeb.Api.StatsController do
|
||||||
|> json(%{error: "Funnel not found"})
|
|> json(%{error: "Funnel not found"})
|
||||||
|> halt()
|
|> halt()
|
||||||
|
|
||||||
|
{:error, :upgrade_required} ->
|
||||||
|
H.payment_required(
|
||||||
|
conn,
|
||||||
|
"#{Plausible.Billing.Feature.Funnels.display_name()} is part of the Plausible Business plan. To get access to this feature, please upgrade your account."
|
||||||
|
)
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
bad_request(conn, "There was an error with your request")
|
bad_request(conn, "There was an error with your request")
|
||||||
end
|
end
|
||||||
|
|
@ -1206,13 +1214,23 @@ defmodule PlausibleWeb.Api.StatsController do
|
||||||
end
|
end
|
||||||
|
|
||||||
def custom_prop_values(conn, params) do
|
def custom_prop_values(conn, params) do
|
||||||
site = conn.assigns[:site]
|
site = Plausible.Repo.preload(conn.assigns.site, :owner)
|
||||||
props = breakdown_custom_prop_values(site, params)
|
|
||||||
json(conn, props)
|
case Plausible.Billing.Feature.Props.check_availability(site.owner) do
|
||||||
|
:ok ->
|
||||||
|
props = breakdown_custom_prop_values(site, params)
|
||||||
|
json(conn, props)
|
||||||
|
|
||||||
|
{:error, :upgrade_required} ->
|
||||||
|
H.payment_required(
|
||||||
|
conn,
|
||||||
|
"#{Plausible.Billing.Feature.Props.display_name()} is part of the Plausible Business plan. To get access to this feature, please upgrade your account."
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def all_custom_prop_values(conn, params) do
|
def all_custom_prop_values(conn, params) do
|
||||||
site = conn.assigns[:site]
|
site = conn.assigns.site
|
||||||
query = Query.from(site, params) |> Filters.add_prefix()
|
query = Query.from(site, params) |> Filters.add_prefix()
|
||||||
|
|
||||||
prop_names = Plausible.Stats.CustomProps.fetch_prop_names(site, query)
|
prop_names = Plausible.Stats.CustomProps.fetch_prop_names(site, query)
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ defmodule PlausibleWeb.StatsController do
|
||||||
plug(PlausibleWeb.AuthorizeSiteAccess when action in [:stats, :csv_export])
|
plug(PlausibleWeb.AuthorizeSiteAccess when action in [:stats, :csv_export])
|
||||||
|
|
||||||
def stats(%{assigns: %{site: site}} = conn, _params) do
|
def stats(%{assigns: %{site: site}} = conn, _params) do
|
||||||
|
site = Plausible.Repo.preload(site, :owner)
|
||||||
stats_start_date = Plausible.Sites.stats_start_date(site)
|
stats_start_date = Plausible.Sites.stats_start_date(site)
|
||||||
can_see_stats? = not Sites.locked?(site) or conn.assigns[:current_user_role] == :super_admin
|
can_see_stats? = not Sites.locked?(site) or conn.assigns[:current_user_role] == :super_admin
|
||||||
demo = site.domain == PlausibleWeb.Endpoint.host()
|
demo = site.domain == PlausibleWeb.Endpoint.host()
|
||||||
|
|
@ -95,7 +96,7 @@ defmodule PlausibleWeb.StatsController do
|
||||||
"""
|
"""
|
||||||
def csv_export(conn, params) do
|
def csv_export(conn, params) do
|
||||||
if is_nil(params["interval"]) or Plausible.Stats.Interval.valid?(params["interval"]) do
|
if is_nil(params["interval"]) or Plausible.Stats.Interval.valid?(params["interval"]) do
|
||||||
site = conn.assigns[:site]
|
site = Plausible.Repo.preload(conn.assigns.site, :owner)
|
||||||
query = Query.from(site, params) |> Filters.add_prefix()
|
query = Query.from(site, params) |> Filters.add_prefix()
|
||||||
|
|
||||||
metrics =
|
metrics =
|
||||||
|
|
@ -144,10 +145,18 @@ defmodule PlausibleWeb.StatsController do
|
||||||
'operating_systems.csv' => fn -> Api.StatsController.operating_systems(conn, params) end,
|
'operating_systems.csv' => fn -> Api.StatsController.operating_systems(conn, params) end,
|
||||||
'devices.csv' => fn -> Api.StatsController.screen_sizes(conn, params) end,
|
'devices.csv' => fn -> Api.StatsController.screen_sizes(conn, params) end,
|
||||||
'conversions.csv' => fn -> Api.StatsController.conversions(conn, params) end,
|
'conversions.csv' => fn -> Api.StatsController.conversions(conn, params) end,
|
||||||
'referrers.csv' => fn -> Api.StatsController.referrers(conn, params) end,
|
'referrers.csv' => fn -> Api.StatsController.referrers(conn, params) end
|
||||||
'custom_props.csv' => fn -> Api.StatsController.all_custom_prop_values(conn, params) end
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
csvs =
|
||||||
|
if Plausible.Billing.Feature.Props.enabled?(site) do
|
||||||
|
Map.put(csvs, 'custom_props.csv', fn ->
|
||||||
|
Api.StatsController.all_custom_prop_values(conn, params)
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
csvs
|
||||||
|
end
|
||||||
|
|
||||||
csv_values =
|
csv_values =
|
||||||
Map.values(csvs)
|
Map.values(csvs)
|
||||||
|> Plausible.ClickhouseRepo.parallel_tasks()
|
|> Plausible.ClickhouseRepo.parallel_tasks()
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,9 @@
|
||||||
data-domain="<%= @site.domain %>"
|
data-domain="<%= @site.domain %>"
|
||||||
data-offset="<%= Plausible.Site.tz_offset(@site) %>"
|
data-offset="<%= Plausible.Site.tz_offset(@site) %>"
|
||||||
data-has-goals="<%= @has_goals %>"
|
data-has-goals="<%= @has_goals %>"
|
||||||
data-conversions-enabled="<%= @site.conversions_enabled %>"
|
data-conversions-enabled="<%= Plausible.Billing.Feature.Goals.enabled?(@site) %>"
|
||||||
data-funnels-enabled="<%= @site.funnels_enabled %>"
|
data-funnels-enabled="<%= Plausible.Billing.Feature.Funnels.enabled?(@site) %>"
|
||||||
data-props-enabled="<%= @site.props_enabled %>"
|
data-props-enabled="<%= Plausible.Billing.Feature.Props.enabled?(@site) %>"
|
||||||
data-funnels="<%= Jason.encode!(@funnels) %>"
|
data-funnels="<%= Jason.encode!(@funnels) %>"
|
||||||
data-has-props="<%= @has_props %>"
|
data-has-props="<%= @has_props %>"
|
||||||
data-logged-in="<%= !!@conn.assigns[:current_user] %>"
|
data-logged-in="<%= !!@conn.assigns[:current_user] %>"
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ defmodule Plausible.DebugReplayInfoTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "adds replayable sentry context" do
|
test "adds replayable sentry context" do
|
||||||
site = build(:site)
|
site = insert(:site)
|
||||||
query = Plausible.Stats.Query.from(site, %{"period" => "day"})
|
query = Plausible.Stats.Query.from(site, %{"period" => "day"})
|
||||||
{:ok, {^site, ^query}} = SampleModule.task(site, query, self())
|
{:ok, {^site, ^query}} = SampleModule.task(site, query, self())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ defmodule Plausible.Stats.ComparisonsTest do
|
||||||
|
|
||||||
describe "with period set to this month" do
|
describe "with period set to this month" do
|
||||||
test "shifts back this month period when mode is previous_period" do
|
test "shifts back this month period when mode is previous_period" do
|
||||||
site = build(:site)
|
site = insert(:site)
|
||||||
query = Query.from(site, %{"period" => "month", "date" => "2023-03-02"})
|
query = Query.from(site, %{"period" => "month", "date" => "2023-03-02"})
|
||||||
now = ~N[2023-03-02 14:00:00]
|
now = ~N[2023-03-02 14:00:00]
|
||||||
|
|
||||||
|
|
@ -16,7 +16,7 @@ defmodule Plausible.Stats.ComparisonsTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "shifts back this month period when it's the first day of the month and mode is previous_period" do
|
test "shifts back this month period when it's the first day of the month and mode is previous_period" do
|
||||||
site = build(:site)
|
site = insert(:site)
|
||||||
query = Query.from(site, %{"period" => "month", "date" => "2023-03-01"})
|
query = Query.from(site, %{"period" => "month", "date" => "2023-03-01"})
|
||||||
now = ~N[2023-03-01 14:00:00]
|
now = ~N[2023-03-01 14:00:00]
|
||||||
|
|
||||||
|
|
@ -27,7 +27,7 @@ defmodule Plausible.Stats.ComparisonsTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "matches the day of the week when nearest day is original query start date and mode is previous_period" do
|
test "matches the day of the week when nearest day is original query start date and mode is previous_period" do
|
||||||
site = build(:site)
|
site = insert(:site)
|
||||||
query = Query.from(site, %{"period" => "month", "date" => "2023-03-02"})
|
query = Query.from(site, %{"period" => "month", "date" => "2023-03-02"})
|
||||||
now = ~N[2023-03-02 14:00:00]
|
now = ~N[2023-03-02 14:00:00]
|
||||||
|
|
||||||
|
|
@ -41,7 +41,7 @@ defmodule Plausible.Stats.ComparisonsTest do
|
||||||
|
|
||||||
describe "with period set to previous month" do
|
describe "with period set to previous month" do
|
||||||
test "shifts back using the same number of days when mode is previous_period" do
|
test "shifts back using the same number of days when mode is previous_period" do
|
||||||
site = build(:site)
|
site = insert(:site)
|
||||||
query = Query.from(site, %{"period" => "month", "date" => "2023-02-01"})
|
query = Query.from(site, %{"period" => "month", "date" => "2023-02-01"})
|
||||||
now = ~N[2023-03-01 14:00:00]
|
now = ~N[2023-03-01 14:00:00]
|
||||||
|
|
||||||
|
|
@ -52,7 +52,7 @@ defmodule Plausible.Stats.ComparisonsTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "shifts back the full month when mode is year_over_year" do
|
test "shifts back the full month when mode is year_over_year" do
|
||||||
site = build(:site)
|
site = insert(:site)
|
||||||
query = Query.from(site, %{"period" => "month", "date" => "2023-02-01"})
|
query = Query.from(site, %{"period" => "month", "date" => "2023-02-01"})
|
||||||
now = ~N[2023-03-01 14:00:00]
|
now = ~N[2023-03-01 14:00:00]
|
||||||
|
|
||||||
|
|
@ -63,7 +63,7 @@ defmodule Plausible.Stats.ComparisonsTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "shifts back whole month plus one day when mode is year_over_year and a leap year" do
|
test "shifts back whole month plus one day when mode is year_over_year and a leap year" do
|
||||||
site = build(:site)
|
site = insert(:site)
|
||||||
query = Query.from(site, %{"period" => "month", "date" => "2020-02-01"})
|
query = Query.from(site, %{"period" => "month", "date" => "2020-02-01"})
|
||||||
now = ~N[2023-03-01 14:00:00]
|
now = ~N[2023-03-01 14:00:00]
|
||||||
|
|
||||||
|
|
@ -74,7 +74,7 @@ defmodule Plausible.Stats.ComparisonsTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "matches the day of the week when mode is previous_period keeping the same day" do
|
test "matches the day of the week when mode is previous_period keeping the same day" do
|
||||||
site = build(:site)
|
site = insert(:site)
|
||||||
query = Query.from(site, %{"period" => "month", "date" => "2023-02-01"})
|
query = Query.from(site, %{"period" => "month", "date" => "2023-02-01"})
|
||||||
now = ~N[2023-03-01 14:00:00]
|
now = ~N[2023-03-01 14:00:00]
|
||||||
|
|
||||||
|
|
@ -86,7 +86,7 @@ defmodule Plausible.Stats.ComparisonsTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "matches the day of the week when mode is previous_period" do
|
test "matches the day of the week when mode is previous_period" do
|
||||||
site = build(:site)
|
site = insert(:site)
|
||||||
query = Query.from(site, %{"period" => "month", "date" => "2023-01-01"})
|
query = Query.from(site, %{"period" => "month", "date" => "2023-01-01"})
|
||||||
now = ~N[2023-03-01 14:00:00]
|
now = ~N[2023-03-01 14:00:00]
|
||||||
|
|
||||||
|
|
@ -100,7 +100,7 @@ defmodule Plausible.Stats.ComparisonsTest do
|
||||||
|
|
||||||
describe "with period set to year to date" do
|
describe "with period set to year to date" do
|
||||||
test "shifts back by the same number of days when mode is previous_period" do
|
test "shifts back by the same number of days when mode is previous_period" do
|
||||||
site = build(:site)
|
site = insert(:site)
|
||||||
query = Query.from(site, %{"period" => "year", "date" => "2023-03-01"})
|
query = Query.from(site, %{"period" => "year", "date" => "2023-03-01"})
|
||||||
now = ~N[2023-03-01 14:00:00]
|
now = ~N[2023-03-01 14:00:00]
|
||||||
|
|
||||||
|
|
@ -111,7 +111,7 @@ defmodule Plausible.Stats.ComparisonsTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "shifts back by the same number of days when mode is year_over_year" do
|
test "shifts back by the same number of days when mode is year_over_year" do
|
||||||
site = build(:site)
|
site = insert(:site)
|
||||||
query = Query.from(site, %{"period" => "year", "date" => "2023-03-01"})
|
query = Query.from(site, %{"period" => "year", "date" => "2023-03-01"})
|
||||||
now = ~N[2023-03-01 14:00:00]
|
now = ~N[2023-03-01 14:00:00]
|
||||||
|
|
||||||
|
|
@ -122,7 +122,7 @@ defmodule Plausible.Stats.ComparisonsTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "matches the day of the week when mode is year_over_year" do
|
test "matches the day of the week when mode is year_over_year" do
|
||||||
site = build(:site)
|
site = insert(:site)
|
||||||
query = Query.from(site, %{"period" => "year", "date" => "2023-03-01"})
|
query = Query.from(site, %{"period" => "year", "date" => "2023-03-01"})
|
||||||
now = ~N[2023-03-01 14:00:00]
|
now = ~N[2023-03-01 14:00:00]
|
||||||
|
|
||||||
|
|
@ -136,7 +136,7 @@ defmodule Plausible.Stats.ComparisonsTest do
|
||||||
|
|
||||||
describe "with period set to previous year" do
|
describe "with period set to previous year" do
|
||||||
test "shifts back a whole year when mode is year_over_year" do
|
test "shifts back a whole year when mode is year_over_year" do
|
||||||
site = build(:site)
|
site = insert(:site)
|
||||||
query = Query.from(site, %{"period" => "year", "date" => "2022-03-02"})
|
query = Query.from(site, %{"period" => "year", "date" => "2022-03-02"})
|
||||||
|
|
||||||
{:ok, comparison} = Comparisons.compare(site, query, "year_over_year")
|
{:ok, comparison} = Comparisons.compare(site, query, "year_over_year")
|
||||||
|
|
@ -146,7 +146,7 @@ defmodule Plausible.Stats.ComparisonsTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "shifts back a whole year when mode is previous_period" do
|
test "shifts back a whole year when mode is previous_period" do
|
||||||
site = build(:site)
|
site = insert(:site)
|
||||||
query = Query.from(site, %{"period" => "year", "date" => "2022-03-02"})
|
query = Query.from(site, %{"period" => "year", "date" => "2022-03-02"})
|
||||||
|
|
||||||
{:ok, comparison} = Comparisons.compare(site, query, "previous_period")
|
{:ok, comparison} = Comparisons.compare(site, query, "previous_period")
|
||||||
|
|
@ -158,7 +158,7 @@ defmodule Plausible.Stats.ComparisonsTest do
|
||||||
|
|
||||||
describe "with period set to custom" do
|
describe "with period set to custom" do
|
||||||
test "shifts back by the same number of days when mode is previous_period" do
|
test "shifts back by the same number of days when mode is previous_period" do
|
||||||
site = build(:site)
|
site = insert(:site)
|
||||||
query = Query.from(site, %{"period" => "custom", "date" => "2023-01-01,2023-01-07"})
|
query = Query.from(site, %{"period" => "custom", "date" => "2023-01-01,2023-01-07"})
|
||||||
|
|
||||||
{:ok, comparison} = Comparisons.compare(site, query, "previous_period")
|
{:ok, comparison} = Comparisons.compare(site, query, "previous_period")
|
||||||
|
|
@ -168,7 +168,7 @@ defmodule Plausible.Stats.ComparisonsTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "shifts back to last year when mode is year_over_year" do
|
test "shifts back to last year when mode is year_over_year" do
|
||||||
site = build(:site)
|
site = insert(:site)
|
||||||
query = Query.from(site, %{"period" => "custom", "date" => "2023-01-01,2023-01-07"})
|
query = Query.from(site, %{"period" => "custom", "date" => "2023-01-01,2023-01-07"})
|
||||||
|
|
||||||
{:ok, comparison} = Comparisons.compare(site, query, "year_over_year")
|
{:ok, comparison} = Comparisons.compare(site, query, "year_over_year")
|
||||||
|
|
@ -180,7 +180,7 @@ defmodule Plausible.Stats.ComparisonsTest do
|
||||||
|
|
||||||
describe "with mode set to custom" do
|
describe "with mode set to custom" do
|
||||||
test "sets first and last dates" do
|
test "sets first and last dates" do
|
||||||
site = build(:site)
|
site = insert(:site)
|
||||||
query = Query.from(site, %{"period" => "custom", "date" => "2023-01-01,2023-01-07"})
|
query = Query.from(site, %{"period" => "custom", "date" => "2023-01-01,2023-01-07"})
|
||||||
|
|
||||||
{:ok, comparison} =
|
{:ok, comparison} =
|
||||||
|
|
@ -191,7 +191,7 @@ defmodule Plausible.Stats.ComparisonsTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "validates from and to dates" do
|
test "validates from and to dates" do
|
||||||
site = build(:site)
|
site = insert(:site)
|
||||||
query = Query.from(site, %{"period" => "custom", "date" => "2023-01-01,2023-01-07"})
|
query = Query.from(site, %{"period" => "custom", "date" => "2023-01-01,2023-01-07"})
|
||||||
|
|
||||||
assert {:error, :invalid_dates} ==
|
assert {:error, :invalid_dates} ==
|
||||||
|
|
|
||||||
|
|
@ -1,48 +1,56 @@
|
||||||
defmodule Plausible.Stats.QueryTest do
|
defmodule Plausible.Stats.QueryTest do
|
||||||
use ExUnit.Case, async: true
|
use Plausible.DataCase, async: true
|
||||||
alias Plausible.Stats.Query
|
alias Plausible.Stats.Query
|
||||||
|
@v4_growth_plan_id "change-me-749342"
|
||||||
|
@v4_business_plan_id "change-me-b749342"
|
||||||
|
|
||||||
@site_inserted_at ~D[2020-01-01]
|
setup do
|
||||||
@site %Plausible.Site{
|
user = insert(:user)
|
||||||
timezone: "UTC",
|
|
||||||
inserted_at: @site_inserted_at,
|
|
||||||
stats_start_date: @site_inserted_at
|
|
||||||
}
|
|
||||||
|
|
||||||
test "parses day format" do
|
site =
|
||||||
q = Query.from(@site, %{"period" => "day", "date" => "2019-01-01"})
|
insert(:site,
|
||||||
|
members: [user],
|
||||||
|
inserted_at: ~N[2020-01-01T00:00:00],
|
||||||
|
stats_start_date: ~D[2020-01-01]
|
||||||
|
)
|
||||||
|
|
||||||
|
{:ok, site: site, user: user}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "parses day format", %{site: site} do
|
||||||
|
q = Query.from(site, %{"period" => "day", "date" => "2019-01-01"})
|
||||||
|
|
||||||
assert q.date_range.first == ~D[2019-01-01]
|
assert q.date_range.first == ~D[2019-01-01]
|
||||||
assert q.date_range.last == ~D[2019-01-01]
|
assert q.date_range.last == ~D[2019-01-01]
|
||||||
assert q.interval == "hour"
|
assert q.interval == "hour"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "day format defaults to today" do
|
test "day format defaults to today", %{site: site} do
|
||||||
q = Query.from(@site, %{"period" => "day"})
|
q = Query.from(site, %{"period" => "day"})
|
||||||
|
|
||||||
assert q.date_range.first == Timex.today()
|
assert q.date_range.first == Timex.today()
|
||||||
assert q.date_range.last == Timex.today()
|
assert q.date_range.last == Timex.today()
|
||||||
assert q.interval == "hour"
|
assert q.interval == "hour"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "parses realtime format" do
|
test "parses realtime format", %{site: site} do
|
||||||
q = Query.from(@site, %{"period" => "realtime"})
|
q = Query.from(site, %{"period" => "realtime"})
|
||||||
|
|
||||||
assert q.date_range.first == Timex.today()
|
assert q.date_range.first == Timex.today()
|
||||||
assert q.date_range.last == Timex.today()
|
assert q.date_range.last == Timex.today()
|
||||||
assert q.period == "realtime"
|
assert q.period == "realtime"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "parses month format" do
|
test "parses month format", %{site: site} do
|
||||||
q = Query.from(@site, %{"period" => "month", "date" => "2019-01-01"})
|
q = Query.from(site, %{"period" => "month", "date" => "2019-01-01"})
|
||||||
|
|
||||||
assert q.date_range.first == ~D[2019-01-01]
|
assert q.date_range.first == ~D[2019-01-01]
|
||||||
assert q.date_range.last == ~D[2019-01-31]
|
assert q.date_range.last == ~D[2019-01-31]
|
||||||
assert q.interval == "date"
|
assert q.interval == "date"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "parses 6 month format" do
|
test "parses 6 month format", %{site: site} do
|
||||||
q = Query.from(@site, %{"period" => "6mo"})
|
q = Query.from(site, %{"period" => "6mo"})
|
||||||
|
|
||||||
assert q.date_range.first ==
|
assert q.date_range.first ==
|
||||||
Timex.shift(Timex.today(), months: -5) |> Timex.beginning_of_month()
|
Timex.shift(Timex.today(), months: -5) |> Timex.beginning_of_month()
|
||||||
|
|
@ -51,8 +59,8 @@ defmodule Plausible.Stats.QueryTest do
|
||||||
assert q.interval == "month"
|
assert q.interval == "month"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "parses 12 month format" do
|
test "parses 12 month format", %{site: site} do
|
||||||
q = Query.from(@site, %{"period" => "12mo"})
|
q = Query.from(site, %{"period" => "12mo"})
|
||||||
|
|
||||||
assert q.date_range.first ==
|
assert q.date_range.first ==
|
||||||
Timex.shift(Timex.today(), months: -11) |> Timex.beginning_of_month()
|
Timex.shift(Timex.today(), months: -11) |> Timex.beginning_of_month()
|
||||||
|
|
@ -61,37 +69,37 @@ defmodule Plausible.Stats.QueryTest do
|
||||||
assert q.interval == "month"
|
assert q.interval == "month"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "parses year to date format" do
|
test "parses year to date format", %{site: site} do
|
||||||
q = Query.from(@site, %{"period" => "year"})
|
q = Query.from(site, %{"period" => "year"})
|
||||||
|
|
||||||
assert q.date_range.first ==
|
assert q.date_range.first ==
|
||||||
Timex.now(@site.timezone) |> Timex.to_date() |> Timex.beginning_of_year()
|
Timex.now(site.timezone) |> Timex.to_date() |> Timex.beginning_of_year()
|
||||||
|
|
||||||
assert q.date_range.last ==
|
assert q.date_range.last ==
|
||||||
Timex.now(@site.timezone) |> Timex.to_date() |> Timex.end_of_year()
|
Timex.now(site.timezone) |> Timex.to_date() |> Timex.end_of_year()
|
||||||
|
|
||||||
assert q.interval == "month"
|
assert q.interval == "month"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "parses all time" do
|
test "parses all time", %{site: site} do
|
||||||
q = Query.from(@site, %{"period" => "all"})
|
q = Query.from(site, %{"period" => "all"})
|
||||||
|
|
||||||
assert q.date_range.first == @site_inserted_at
|
assert q.date_range.first == NaiveDateTime.to_date(site.inserted_at)
|
||||||
assert q.date_range.last == Timex.today()
|
assert q.date_range.last == Timex.today()
|
||||||
assert q.period == "all"
|
assert q.period == "all"
|
||||||
assert q.interval == "month"
|
assert q.interval == "month"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "parses all time in correct timezone" do
|
test "parses all time in correct timezone", %{site: site} do
|
||||||
site = Map.put(@site, :timezone, "America/Cancun")
|
site = Map.put(site, :timezone, "America/Cancun")
|
||||||
q = Query.from(site, %{"period" => "all"})
|
q = Query.from(site, %{"period" => "all"})
|
||||||
|
|
||||||
assert q.date_range.first == ~D[2019-12-31]
|
assert q.date_range.first == ~D[2019-12-31]
|
||||||
assert q.date_range.last == Timex.today("America/Cancun")
|
assert q.date_range.last == Timex.today("America/Cancun")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "all time shows today if site has no start date" do
|
test "all time shows today if site has no start date", %{site: site} do
|
||||||
site = Map.put(@site, :stats_start_date, nil)
|
site = Map.put(site, :stats_start_date, nil)
|
||||||
q = Query.from(site, %{"period" => "all"})
|
q = Query.from(site, %{"period" => "all"})
|
||||||
|
|
||||||
assert q.date_range.first == Timex.today()
|
assert q.date_range.first == Timex.today()
|
||||||
|
|
@ -100,8 +108,8 @@ defmodule Plausible.Stats.QueryTest do
|
||||||
assert q.interval == "hour"
|
assert q.interval == "hour"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "all time shows hourly if site is completely new" do
|
test "all time shows hourly if site is completely new", %{site: site} do
|
||||||
site = Map.put(@site, :stats_start_date, Timex.now())
|
site = Map.put(site, :stats_start_date, Timex.now())
|
||||||
q = Query.from(site, %{"period" => "all"})
|
q = Query.from(site, %{"period" => "all"})
|
||||||
|
|
||||||
assert q.date_range.first == Timex.today()
|
assert q.date_range.first == Timex.today()
|
||||||
|
|
@ -110,8 +118,8 @@ defmodule Plausible.Stats.QueryTest do
|
||||||
assert q.interval == "hour"
|
assert q.interval == "hour"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "all time shows daily if site is more than a day old" do
|
test "all time shows daily if site is more than a day old", %{site: site} do
|
||||||
site = Map.put(@site, :stats_start_date, Timex.now() |> Timex.shift(days: -1))
|
site = Map.put(site, :stats_start_date, Timex.now() |> Timex.shift(days: -1))
|
||||||
q = Query.from(site, %{"period" => "all"})
|
q = Query.from(site, %{"period" => "all"})
|
||||||
|
|
||||||
assert q.date_range.first == Timex.today() |> Timex.shift(days: -1)
|
assert q.date_range.first == Timex.today() |> Timex.shift(days: -1)
|
||||||
|
|
@ -120,8 +128,8 @@ defmodule Plausible.Stats.QueryTest do
|
||||||
assert q.interval == "date"
|
assert q.interval == "date"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "all time shows monthly if site is more than a month old" do
|
test "all time shows monthly if site is more than a month old", %{site: site} do
|
||||||
site = Map.put(@site, :stats_start_date, Timex.now() |> Timex.shift(months: -1))
|
site = Map.put(site, :stats_start_date, Timex.now() |> Timex.shift(months: -1))
|
||||||
q = Query.from(site, %{"period" => "all"})
|
q = Query.from(site, %{"period" => "all"})
|
||||||
|
|
||||||
assert q.date_range.first == Timex.today() |> Timex.shift(months: -1)
|
assert q.date_range.first == Timex.today() |> Timex.shift(months: -1)
|
||||||
|
|
@ -130,8 +138,8 @@ defmodule Plausible.Stats.QueryTest do
|
||||||
assert q.interval == "month"
|
assert q.interval == "month"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "all time uses passed interval different from the default interval" do
|
test "all time uses passed interval different from the default interval", %{site: site} do
|
||||||
site = Map.put(@site, :stats_start_date, Timex.now() |> Timex.shift(months: -1))
|
site = Map.put(site, :stats_start_date, Timex.now() |> Timex.shift(months: -1))
|
||||||
q = Query.from(site, %{"period" => "all", "interval" => "week"})
|
q = Query.from(site, %{"period" => "all", "interval" => "week"})
|
||||||
|
|
||||||
assert q.date_range.first == Timex.today() |> Timex.shift(months: -1)
|
assert q.date_range.first == Timex.today() |> Timex.shift(months: -1)
|
||||||
|
|
@ -140,41 +148,57 @@ defmodule Plausible.Stats.QueryTest do
|
||||||
assert q.interval == "week"
|
assert q.interval == "week"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "defaults to 30 days format" do
|
test "defaults to 30 days format", %{site: site} do
|
||||||
assert Query.from(@site, %{}) == Query.from(@site, %{"period" => "30d"})
|
assert Query.from(site, %{}) == Query.from(site, %{"period" => "30d"})
|
||||||
end
|
end
|
||||||
|
|
||||||
test "parses custom format" do
|
test "parses custom format", %{site: site} do
|
||||||
q = Query.from(@site, %{"period" => "custom", "from" => "2019-01-01", "to" => "2019-01-15"})
|
q = Query.from(site, %{"period" => "custom", "from" => "2019-01-01", "to" => "2019-01-15"})
|
||||||
|
|
||||||
assert q.date_range.first == ~D[2019-01-01]
|
assert q.date_range.first == ~D[2019-01-01]
|
||||||
assert q.date_range.last == ~D[2019-01-15]
|
assert q.date_range.last == ~D[2019-01-15]
|
||||||
assert q.interval == "date"
|
assert q.interval == "date"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "adds sample_threshold :infinite to query struct" do
|
test "adds sample_threshold :infinite to query struct", %{site: site} do
|
||||||
q = Query.from(@site, %{"period" => "30d", "sample_threshold" => "infinite"})
|
q = Query.from(site, %{"period" => "30d", "sample_threshold" => "infinite"})
|
||||||
assert q.sample_threshold == :infinite
|
assert q.sample_threshold == :infinite
|
||||||
end
|
end
|
||||||
|
|
||||||
test "casts sample_threshold to integer in query struct" do
|
test "casts sample_threshold to integer in query struct", %{site: site} do
|
||||||
q = Query.from(@site, %{"period" => "30d", "sample_threshold" => "30000000"})
|
q = Query.from(site, %{"period" => "30d", "sample_threshold" => "30000000"})
|
||||||
assert q.sample_threshold == 30_000_000
|
assert q.sample_threshold == 30_000_000
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "filters" do
|
describe "filters" do
|
||||||
test "parses goal filter" do
|
test "parses goal filter", %{site: site} do
|
||||||
filters = Jason.encode!(%{"goal" => "Signup"})
|
filters = Jason.encode!(%{"goal" => "Signup"})
|
||||||
q = Query.from(@site, %{"period" => "6mo", "filters" => filters})
|
q = Query.from(site, %{"period" => "6mo", "filters" => filters})
|
||||||
|
|
||||||
assert q.filters["goal"] == "Signup"
|
assert q.filters["goal"] == "Signup"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "parses source filter" do
|
test "parses source filter", %{site: site} do
|
||||||
filters = Jason.encode!(%{"source" => "Twitter"})
|
filters = Jason.encode!(%{"source" => "Twitter"})
|
||||||
q = Query.from(@site, %{"period" => "6mo", "filters" => filters})
|
q = Query.from(site, %{"period" => "6mo", "filters" => filters})
|
||||||
|
|
||||||
assert q.filters["source"] == "Twitter"
|
assert q.filters["source"] == "Twitter"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "allows prop filters when site owner is on a business plan", %{site: site, user: user} do
|
||||||
|
insert(:subscription, user: user, paddle_plan_id: @v4_business_plan_id)
|
||||||
|
filters = Jason.encode!(%{"props" => %{"author" => "!John Doe"}})
|
||||||
|
query = Query.from(site, %{"period" => "6mo", "filters" => filters})
|
||||||
|
|
||||||
|
assert Map.has_key?(query.filters, "props")
|
||||||
|
end
|
||||||
|
|
||||||
|
test "drops prop filter when site owner is on a growth plan", %{site: site, user: user} do
|
||||||
|
insert(:subscription, user: user, paddle_plan_id: @v4_growth_plan_id)
|
||||||
|
filters = Jason.encode!(%{"props" => %{"author" => "!John Doe"}})
|
||||||
|
query = Query.from(site, %{"period" => "6mo", "filters" => filters})
|
||||||
|
|
||||||
|
refute Map.has_key?(query.filters, "props")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
defmodule PlausibleWeb.Api.StatsController.CustomPropBreakdownTest do
|
defmodule PlausibleWeb.Api.StatsController.CustomPropBreakdownTest do
|
||||||
use PlausibleWeb.ConnCase
|
use PlausibleWeb.ConnCase
|
||||||
|
@v4_growth_plan_id "change-me-749342"
|
||||||
|
|
||||||
describe "GET /api/stats/:domain/custom-prop-values/:prop_key" do
|
describe "GET /api/stats/:domain/custom-prop-values/:prop_key" do
|
||||||
setup [:create_user, :log_in, :create_new_site, :add_imported_data]
|
setup [:create_user, :log_in, :create_new_site, :add_imported_data]
|
||||||
|
|
@ -177,6 +178,17 @@ defmodule PlausibleWeb.Api.StatsController.CustomPropBreakdownTest do
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "errors when site owner is on a growth plan", %{conn: conn, site: site, user: user} do
|
||||||
|
insert(:subscription, user: user, paddle_plan_id: @v4_growth_plan_id)
|
||||||
|
|
||||||
|
conn = get(conn, "/api/stats/#{site.domain}/custom-prop-values/prop?period=day")
|
||||||
|
|
||||||
|
assert json_response(conn, 402) == %{
|
||||||
|
"error" =>
|
||||||
|
"Custom Properties is part of the Plausible Business plan. To get access to this feature, please upgrade your account."
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "GET /api/stats/:domain/custom-prop-values/:prop_key - with goal filter" do
|
describe "GET /api/stats/:domain/custom-prop-values/:prop_key - with goal filter" do
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ defmodule PlausibleWeb.Api.StatsController.FunnelsTest do
|
||||||
|
|
||||||
@user_id 123
|
@user_id 123
|
||||||
@other_user_id 456
|
@other_user_id 456
|
||||||
|
@v4_growth_plan_id "change-me-749342"
|
||||||
|
|
||||||
@build_funnel_with [
|
@build_funnel_with [
|
||||||
{"page_path", "/blog/announcement"},
|
{"page_path", "/blog/announcement"},
|
||||||
|
|
@ -219,6 +220,25 @@ defmodule PlausibleWeb.Api.StatsController.FunnelsTest do
|
||||||
]
|
]
|
||||||
} = resp
|
} = resp
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "returns HTTP 402 when site owner is on a growth plan", %{
|
||||||
|
conn: conn,
|
||||||
|
user: user,
|
||||||
|
site: site
|
||||||
|
} do
|
||||||
|
insert(:subscription, user: user, paddle_plan_id: @v4_growth_plan_id)
|
||||||
|
{:ok, funnel} = setup_funnel(site, @build_funnel_with)
|
||||||
|
|
||||||
|
resp =
|
||||||
|
conn
|
||||||
|
|> get("/api/stats/#{site.domain}/funnels/#{funnel.id}/?period=day")
|
||||||
|
|> json_response(402)
|
||||||
|
|
||||||
|
assert %{
|
||||||
|
"error" =>
|
||||||
|
"Funnels is part of the Plausible Business plan. To get access to this feature, please upgrade your account."
|
||||||
|
} == resp
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "GET /api/stats/funnel - disallowed filters" do
|
describe "GET /api/stats/funnel - disallowed filters" do
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
defmodule PlausibleWeb.Api.StatsController.TopStatsTest do
|
defmodule PlausibleWeb.Api.StatsController.TopStatsTest do
|
||||||
use PlausibleWeb.ConnCase
|
use PlausibleWeb.ConnCase
|
||||||
|
|
||||||
|
@v4_growth_plan_id "change-me-749342"
|
||||||
@user_id 123
|
@user_id 123
|
||||||
|
|
||||||
describe "GET /api/stats/top-stats - default" do
|
describe "GET /api/stats/top-stats - default" do
|
||||||
|
|
@ -825,6 +826,28 @@ defmodule PlausibleWeb.Api.StatsController.TopStatsTest do
|
||||||
refute "Average revenue" in metrics
|
refute "Average revenue" in metrics
|
||||||
refute "Total revenue" in metrics
|
refute "Total revenue" in metrics
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "does not return average and total when site owner is on a growth plan",
|
||||||
|
%{conn: conn, site: site, user: user} do
|
||||||
|
insert(:subscription, user: user, paddle_plan_id: @v4_growth_plan_id)
|
||||||
|
insert(:goal, site: site, event_name: "Payment", currency: "USD")
|
||||||
|
|
||||||
|
populate_stats(site, [
|
||||||
|
build(:event,
|
||||||
|
name: "Payment",
|
||||||
|
revenue_reporting_amount: Decimal.new(13_29),
|
||||||
|
revenue_reporting_currency: "USD"
|
||||||
|
)
|
||||||
|
])
|
||||||
|
|
||||||
|
filters = Jason.encode!(%{goal: "Payment"})
|
||||||
|
conn = get(conn, "/api/stats/#{site.domain}/top-stats?period=all&filters=#{filters}")
|
||||||
|
assert %{"top_stats" => top_stats} = json_response(conn, 200)
|
||||||
|
|
||||||
|
metrics = Enum.map(top_stats, & &1["name"])
|
||||||
|
refute "Average revenue" in metrics
|
||||||
|
refute "Total revenue" in metrics
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "GET /api/stats/top-stats - with comparisons" do
|
describe "GET /api/stats/top-stats - with comparisons" do
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ defmodule PlausibleWeb.StatsControllerTest do
|
||||||
use PlausibleWeb.ConnCase, async: false
|
use PlausibleWeb.ConnCase, async: false
|
||||||
use Plausible.Repo
|
use Plausible.Repo
|
||||||
import Plausible.Test.Support.HTML
|
import Plausible.Test.Support.HTML
|
||||||
|
@v4_growth_plan_id "change-me-749342"
|
||||||
|
|
||||||
describe "GET /:website - anonymous user" do
|
describe "GET /:website - anonymous user" do
|
||||||
test "public site - shows site stats", %{conn: conn} do
|
test "public site - shows site stats", %{conn: conn} do
|
||||||
|
|
@ -154,6 +155,20 @@ defmodule PlausibleWeb.StatsControllerTest do
|
||||||
assert 'utm_terms.csv' in zip
|
assert 'utm_terms.csv' in zip
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "does not export custom properties when site owner is on a growth plan", %{
|
||||||
|
conn: conn,
|
||||||
|
site: site,
|
||||||
|
user: user
|
||||||
|
} do
|
||||||
|
insert(:subscription, user: user, paddle_plan_id: @v4_growth_plan_id)
|
||||||
|
response = conn |> get("/" <> site.domain <> "/export") |> response(200)
|
||||||
|
|
||||||
|
{:ok, zip} = :zip.unzip(response, [:memory])
|
||||||
|
files = Map.new(zip)
|
||||||
|
|
||||||
|
refute Map.has_key?(files, 'custom_props.csv')
|
||||||
|
end
|
||||||
|
|
||||||
test "exports data in zipped csvs", %{conn: conn, site: site} do
|
test "exports data in zipped csvs", %{conn: conn, site: site} do
|
||||||
populate_exported_stats(site)
|
populate_exported_stats(site)
|
||||||
conn = get(conn, "/" <> site.domain <> "/export?date=2021-10-20")
|
conn = get(conn, "/" <> site.domain <> "/export?date=2021-10-20")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue