mirror of
https://github.com/plausible/analytics.git
synced 2024-12-22 17:11:36 +03:00
Switch reads to Teams schemas across the rest of the app (#4860)
* Pre-emptively introduce `site.team_owner` relation
* Drop null constraint on user_id from subscriptions and enterprise_plans
* Temporarily remove populating old schemas in Teams.Test
* Point to site.owner via new schema
* Switch more reads to teams schema WIP
* Fix AuhtorizeSiteAccess test
There's no need to translate `admin`<->`editor` here,
the redundancy is inlined wherever the plug is initialized.
* Fix regions test
* Fix main graph test
* Fix authorization test
* Try to rely on team for subscription/plans where applicable
* Test fixes
* Fix plans test
* Prep for CheckUsage changes
* Skip remaining CheckUsage tests for now
* Fix user deletion to account for team relations
* Fix HelpScout tests
* 💀 Modify ingestion to read team schemas
* Made all tests green except skipped ones
* Mute warnings about transferring site with no order
By making artificial site membership struct,
when reading data off team membership schema.
* Fix site removal test case
* Re-enable locked site tests, that don't have to rely on `SiteLocker`
* Format
* Revert "Mute warnings about transferring site with no order"
This reverts commit 0e45f8c9d9
.
* Re-enable old models and fix remaining tests
* Use new factories in a long running minio test
* FIXME->TODO
* Fix remaining tests in legacy mode (no FF raised)
* oof
cc @zoldar
* Add missing definitions of editor role in FE code
* Remove no longer relevant comment about roles
* Fix JS formatting
* Always prioritize site transfers over memberships in sites list
* Fix misaligned "Reject" invitation button
* Fix site pinning when user is guest in multiple sites in team
* Fix subscription settings controller tests
---------
Co-authored-by: Adam Rutkowski <hq@mtod.org>
This commit is contained in:
parent
badc477048
commit
b86c2e715f
@ -160,7 +160,9 @@ export default class SiteSwitcher extends React.Component {
|
||||
|
||||
renderSettingsLink() {
|
||||
if (
|
||||
['owner', 'admin', 'super_admin'].includes(this.props.currentUserRole)
|
||||
['owner', 'admin', 'editor', 'super_admin'].includes(
|
||||
this.props.currentUserRole
|
||||
)
|
||||
) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
|
@ -43,7 +43,7 @@ export default function Behaviours({ importedDataInView }) {
|
||||
const site = useSiteContext();
|
||||
const user = useUserContext();
|
||||
|
||||
const adminAccess = ['owner', 'admin', 'super_admin'].includes(user.role)
|
||||
const adminAccess = ['owner', 'admin', 'editor', 'super_admin'].includes(user.role)
|
||||
const tabKey = storage.getDomainScopedStorageKey('behavioursTab', site.domain)
|
||||
const funnelKey = storage.getDomainScopedStorageKey('behavioursTabFunnel', site.domain)
|
||||
const [enabledModes, setEnabledModes] = useState(getEnabledModes())
|
||||
|
@ -4,7 +4,8 @@ import React, { createContext, ReactNode, useContext } from 'react'
|
||||
export enum Role {
|
||||
owner = 'owner',
|
||||
admin = 'admin',
|
||||
viewer = 'viewer'
|
||||
viewer = 'viewer',
|
||||
editor = 'editor'
|
||||
}
|
||||
|
||||
const userContextDefaultValue = {
|
||||
|
@ -82,19 +82,28 @@ defmodule Plausible.HelpScout do
|
||||
def get_details_for_emails(emails, customer_id) do
|
||||
with {:ok, user} <- get_user(emails) do
|
||||
set_mapping(customer_id, user.email)
|
||||
user = Plausible.Users.with_subscription(user.id)
|
||||
plan = Billing.Plans.get_subscription_plan(user.subscription)
|
||||
|
||||
{team, subscription, plan} =
|
||||
case Plausible.Teams.get_by_owner(user) do
|
||||
{:ok, team} ->
|
||||
team = Plausible.Teams.with_subscription(team)
|
||||
plan = Billing.Plans.get_subscription_plan(team.subscription)
|
||||
{team, team.subscription, plan}
|
||||
|
||||
{:error, :no_team} ->
|
||||
{nil, nil, nil}
|
||||
end
|
||||
|
||||
{:ok,
|
||||
%{
|
||||
email: user.email,
|
||||
notes: user.notes,
|
||||
status_label: status_label(user),
|
||||
status_label: status_label(team, subscription),
|
||||
status_link:
|
||||
Routes.kaffy_resource_url(PlausibleWeb.Endpoint, :show, :auth, :user, user.id),
|
||||
plan_label: plan_label(user.subscription, plan),
|
||||
plan_link: plan_link(user.subscription),
|
||||
sites_count: Plausible.Sites.owned_sites_count(user),
|
||||
plan_label: plan_label(subscription, plan),
|
||||
plan_link: plan_link(subscription),
|
||||
sites_count: Plausible.Teams.owned_sites_count(team),
|
||||
sites_link:
|
||||
Routes.kaffy_resource_url(PlausibleWeb.Endpoint, :index, :sites, :site,
|
||||
search: user.email
|
||||
@ -111,8 +120,9 @@ defmodule Plausible.HelpScout do
|
||||
|
||||
domain_query =
|
||||
from(s in Plausible.Site,
|
||||
inner_join: sm in assoc(s, :memberships),
|
||||
where: sm.user_id == parent_as(:user).id and sm.role == :owner,
|
||||
inner_join: t in assoc(s, :team),
|
||||
inner_join: tm in assoc(t, :team_memberships),
|
||||
where: tm.user_id == parent_as(:user).id and tm.role == :owner,
|
||||
where: ilike(s.domain, ^search_term) or ilike(s.domain_changed_from, ^search_term),
|
||||
select: 1
|
||||
)
|
||||
@ -123,7 +133,7 @@ defmodule Plausible.HelpScout do
|
||||
like(u.email, ^search_term) or exists(domain_query)
|
||||
)
|
||||
|> limit(5)
|
||||
|> select([user: u, site_membership: sm], %{email: u.email, sites_count: count(sm.id)})
|
||||
|> select([user: u, sites: s], %{email: u.email, sites_count: count(s.id)})
|
||||
|> Repo.all()
|
||||
end
|
||||
|
||||
@ -137,31 +147,31 @@ defmodule Plausible.HelpScout do
|
||||
])
|
||||
end
|
||||
|
||||
defp status_label(user) do
|
||||
subscription_active? = Billing.Subscriptions.active?(user.subscription)
|
||||
trial? = Plausible.Users.on_trial?(user)
|
||||
defp status_label(team, subscription) do
|
||||
subscription_active? = Billing.Subscriptions.active?(subscription)
|
||||
trial? = Plausible.Teams.on_trial?(team)
|
||||
|
||||
cond do
|
||||
not subscription_active? and not trial? and is_nil(user.trial_expiry_date) ->
|
||||
not subscription_active? and not trial? and (is_nil(team) or is_nil(team.trial_expiry_date)) ->
|
||||
"None"
|
||||
|
||||
is_nil(user.subscription) and not trial? ->
|
||||
is_nil(subscription) and not trial? ->
|
||||
"Expired trial"
|
||||
|
||||
trial? ->
|
||||
"Trial"
|
||||
|
||||
user.subscription.status == Subscription.Status.deleted() ->
|
||||
subscription.status == Subscription.Status.deleted() ->
|
||||
if subscription_active? do
|
||||
"Pending cancellation"
|
||||
else
|
||||
"Canceled"
|
||||
end
|
||||
|
||||
user.subscription.status == Subscription.Status.paused() ->
|
||||
subscription.status == Subscription.Status.paused() ->
|
||||
"Paused"
|
||||
|
||||
Plausible.Sites.owned_sites_locked?(user) ->
|
||||
Plausible.Teams.owned_sites_locked?(team) ->
|
||||
"Dashboard locked"
|
||||
|
||||
subscription_active? ->
|
||||
@ -228,13 +238,14 @@ defmodule Plausible.HelpScout do
|
||||
defp users_query() do
|
||||
from(u in Plausible.Auth.User,
|
||||
as: :user,
|
||||
left_join: sm in assoc(u, :site_memberships),
|
||||
on: sm.role == :owner,
|
||||
as: :site_membership,
|
||||
left_join: s in assoc(sm, :site),
|
||||
as: :site,
|
||||
left_join: tm in assoc(u, :team_memberships),
|
||||
on: tm.role == :owner,
|
||||
as: :team_memberships,
|
||||
left_join: t in assoc(tm, :team),
|
||||
left_join: s in assoc(t, :sites),
|
||||
as: :sites,
|
||||
group_by: u.id,
|
||||
order_by: [desc: count(sm.id)]
|
||||
order_by: [desc: count(s.id)]
|
||||
)
|
||||
end
|
||||
|
||||
|
@ -95,23 +95,24 @@ defmodule Plausible.Auth do
|
||||
|
||||
def delete_user(user) do
|
||||
Repo.transaction(fn ->
|
||||
user = Repo.preload(user, site_memberships: :site)
|
||||
case Plausible.Teams.get_by_owner(user) do
|
||||
{:ok, team} ->
|
||||
for site <- Plausible.Teams.owned_sites(team) do
|
||||
Plausible.Site.Removal.run(site)
|
||||
end
|
||||
|
||||
for membership <- user.site_memberships do
|
||||
if membership.role == :owner do
|
||||
Plausible.Site.Removal.run(membership.site)
|
||||
end
|
||||
Repo.delete_all(from s in Plausible.Billing.Subscription, where: s.team_id == ^team.id)
|
||||
|
||||
Repo.delete_all(
|
||||
from(
|
||||
sm in Plausible.Site.Membership,
|
||||
where: sm.id == ^membership.id
|
||||
Repo.delete_all(
|
||||
from ep in Plausible.Billing.EnterprisePlan, where: ep.team_id == ^team.id
|
||||
)
|
||||
)
|
||||
|
||||
Repo.delete!(team)
|
||||
|
||||
_ ->
|
||||
:skip
|
||||
end
|
||||
|
||||
{:ok, team} = Plausible.Teams.get_or_create(user)
|
||||
Repo.delete!(team)
|
||||
Repo.delete!(user)
|
||||
end)
|
||||
end
|
||||
|
@ -123,18 +123,27 @@ defmodule Plausible.Auth.UserAdmin do
|
||||
end
|
||||
|
||||
defp subscription_status(user) do
|
||||
cond do
|
||||
user.subscription ->
|
||||
status_str =
|
||||
PlausibleWeb.SettingsView.present_subscription_status(user.subscription.status)
|
||||
team =
|
||||
case Plausible.Teams.get_by_owner(user) do
|
||||
{:ok, team} ->
|
||||
Plausible.Teams.with_subscription(team)
|
||||
|
||||
if user.subscription.paddle_subscription_id do
|
||||
{:safe, ~s(<a href="#{manage_url(user.subscription)}">#{status_str}</a>)}
|
||||
{:error, :no_team} ->
|
||||
nil
|
||||
end
|
||||
|
||||
cond do
|
||||
team && team.subscription ->
|
||||
status_str =
|
||||
PlausibleWeb.SettingsView.present_subscription_status(team.subscription.status)
|
||||
|
||||
if team.subscription.paddle_subscription_id do
|
||||
{:safe, ~s(<a href="#{manage_url(team.subscription)}">#{status_str}</a>)}
|
||||
else
|
||||
status_str
|
||||
end
|
||||
|
||||
Plausible.Users.on_trial?(user) ->
|
||||
Plausible.Teams.on_trial?(team) ->
|
||||
"On trial"
|
||||
|
||||
true ->
|
||||
|
@ -280,8 +280,8 @@ defmodule Plausible.Billing do
|
||||
|
||||
def paddle_api(), do: Application.fetch_env!(:plausible, :paddle_api)
|
||||
|
||||
def cancelled_subscription_notice_dismiss_id(%User{} = user) do
|
||||
"subscription_cancelled__#{user.id}"
|
||||
def cancelled_subscription_notice_dismiss_id(id) do
|
||||
"subscription_cancelled__#{id}"
|
||||
end
|
||||
|
||||
defp active_subscription_query(user) do
|
||||
|
@ -188,7 +188,7 @@ defmodule Plausible.Billing.Plans do
|
||||
|
||||
defp get_enterprise_plan(%Subscription{} = subscription) do
|
||||
Repo.get_by(EnterprisePlan,
|
||||
user_id: subscription.user_id,
|
||||
team_id: subscription.team_id,
|
||||
paddle_plan_id: subscription.paddle_plan_id
|
||||
)
|
||||
end
|
||||
|
@ -16,11 +16,11 @@ defmodule Plausible.Billing.Subscription do
|
||||
:status,
|
||||
:next_bill_amount,
|
||||
:next_bill_date,
|
||||
:user_id,
|
||||
# :team_id,
|
||||
:currency_code
|
||||
]
|
||||
|
||||
@optional_fields [:last_bill_date, :team_id]
|
||||
@optional_fields [:last_bill_date, :team_id, :user_id]
|
||||
|
||||
schema "subscriptions" do
|
||||
field :paddle_subscription_id, :string
|
||||
|
@ -51,7 +51,8 @@ defmodule Plausible.Site do
|
||||
has_one :weekly_report, Plausible.Site.WeeklyReport
|
||||
has_one :monthly_report, Plausible.Site.MonthlyReport
|
||||
has_one :ownership, Plausible.Site.Membership, where: [role: :owner]
|
||||
has_one :owner, through: [:ownership, :user]
|
||||
has_one :legacy_owner, through: [:ownership, :user]
|
||||
has_one :owner, through: [:team, :owner]
|
||||
|
||||
# If `from_cache?` is set, the struct might be incomplete - see `Plausible.Site.Cache`.
|
||||
# Use `Plausible.Repo.reload!(cached_site)` to pre-fill missing fields if
|
||||
|
@ -48,13 +48,13 @@ defmodule Plausible.Site.Cache do
|
||||
def base_db_query() do
|
||||
from s in Site,
|
||||
left_join: rg in assoc(s, :revenue_goals),
|
||||
inner_join: owner in assoc(s, :owner),
|
||||
inner_join: team in assoc(s, :team),
|
||||
select: {
|
||||
s.domain,
|
||||
s.domain_changed_from,
|
||||
%{struct(s, ^@cached_schema_fields) | from_cache?: true}
|
||||
},
|
||||
preload: [revenue_goals: rg, owner: owner]
|
||||
preload: [revenue_goals: rg, team: team]
|
||||
end
|
||||
|
||||
@impl true
|
||||
|
@ -44,7 +44,7 @@ defmodule Plausible.Site.GateKeeper do
|
||||
|
||||
defp policy(domain, opts) when is_binary(domain) do
|
||||
with from_cache <- Cache.get(domain, Keyword.get(opts, :cache_opts, [])),
|
||||
site = %Site{owner: %{accept_traffic_until: accept_traffic_until}} <- from_cache do
|
||||
site = %Site{team: %{accept_traffic_until: accept_traffic_until}} <- from_cache do
|
||||
if not is_nil(accept_traffic_until) and
|
||||
Date.after?(Date.utc_today(), accept_traffic_until) do
|
||||
:payment_required
|
||||
|
@ -2,7 +2,7 @@ defmodule Plausible.Site.Membership do
|
||||
use Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
|
||||
@roles [:owner, :admin, :viewer]
|
||||
@roles [:owner, :admin, :editor, :viewer]
|
||||
|
||||
@type t() :: %__MODULE__{}
|
||||
|
||||
|
@ -54,6 +54,29 @@ defmodule Plausible.Teams do
|
||||
)
|
||||
end
|
||||
|
||||
def owned_sites_locked?(nil) do
|
||||
false
|
||||
end
|
||||
|
||||
def owned_sites_locked?(team) do
|
||||
Repo.exists?(
|
||||
from s in Plausible.Site,
|
||||
where: s.team_id == ^team.id,
|
||||
where: s.locked == true
|
||||
)
|
||||
end
|
||||
|
||||
def owned_sites_count(nil), do: 0
|
||||
|
||||
def owned_sites_count(team) do
|
||||
Repo.aggregate(
|
||||
from(s in Plausible.Site,
|
||||
where: s.team_id == ^team.id
|
||||
),
|
||||
:count
|
||||
)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Create (when necessary) and load team relation for provided site.
|
||||
|
||||
@ -107,11 +130,11 @@ defmodule Plausible.Teams do
|
||||
|> Repo.update!()
|
||||
end
|
||||
|
||||
def get_by_owner(user) do
|
||||
def get_by_owner(user_id) when is_integer(user_id) do
|
||||
result =
|
||||
from(tm in Teams.Membership,
|
||||
inner_join: t in assoc(tm, :team),
|
||||
where: tm.user_id == ^user.id and tm.role == :owner,
|
||||
where: tm.user_id == ^user_id and tm.role == :owner,
|
||||
select: t,
|
||||
order_by: t.id
|
||||
)
|
||||
@ -126,6 +149,10 @@ defmodule Plausible.Teams do
|
||||
end
|
||||
end
|
||||
|
||||
def get_by_owner(%Plausible.Auth.User{} = user) do
|
||||
get_by_owner(user.id)
|
||||
end
|
||||
|
||||
def last_subscription_join_query() do
|
||||
from(subscription in last_subscription_query(),
|
||||
where: subscription.team_id == parent_as(:team).id
|
||||
|
@ -18,7 +18,9 @@ defmodule Plausible.Teams.Adapter do
|
||||
)
|
||||
end
|
||||
|
||||
def switch(user, opts \\ []) do
|
||||
def switch(switch_on, opts \\ [])
|
||||
|
||||
def switch(%Plausible.Auth.User{} = user, opts) do
|
||||
team_fn = Keyword.fetch!(opts, :team_fn)
|
||||
user_fn = Keyword.fetch!(opts, :user_fn)
|
||||
|
||||
@ -37,4 +39,10 @@ defmodule Plausible.Teams.Adapter do
|
||||
user_fn.(user)
|
||||
end
|
||||
end
|
||||
|
||||
def switch(team_or_nil, opts) do
|
||||
team_fn = Keyword.fetch!(opts, :team_fn)
|
||||
team = Plausible.Teams.with_subscription(team_or_nil)
|
||||
team_fn.(team)
|
||||
end
|
||||
end
|
||||
|
@ -259,6 +259,7 @@ defmodule Plausible.Teams.Adapter.Read.Sites do
|
||||
where: tm.user_id == ^user_id,
|
||||
where: coalesce(gm.role, tm.role) in ^roles,
|
||||
where: s.domain == ^domain or s.domain_changed_from == ^domain,
|
||||
where: is_nil(gm.id) or gm.site_id == s.id,
|
||||
select: s
|
||||
)
|
||||
end
|
||||
|
@ -324,6 +324,8 @@ defmodule Plausible.Teams.Billing do
|
||||
|
||||
def features_usage(team, site_ids \\ nil)
|
||||
|
||||
def features_usage(nil, nil), do: []
|
||||
|
||||
def features_usage(%Teams.Team{} = team, nil) do
|
||||
owned_site_ids = team |> Teams.owned_sites() |> Enum.map(& &1.id)
|
||||
features_usage(team, owned_site_ids)
|
||||
|
@ -56,6 +56,8 @@ defmodule Plausible.Teams.Memberships do
|
||||
end
|
||||
end
|
||||
|
||||
def site_role(_site, nil), do: {:error, :not_a_member}
|
||||
|
||||
def site_role(site, user) do
|
||||
result =
|
||||
from(u in Auth.User,
|
||||
@ -74,6 +76,13 @@ defmodule Plausible.Teams.Memberships do
|
||||
end
|
||||
end
|
||||
|
||||
def site_member?(site, user) do
|
||||
case site_role(site, user) do
|
||||
{:ok, _} -> true
|
||||
_ -> false
|
||||
end
|
||||
end
|
||||
|
||||
def update_role_sync(site_membership) do
|
||||
site_id = site_membership.site_id
|
||||
user_id = site_membership.user_id
|
||||
|
@ -129,8 +129,17 @@ defmodule Plausible.Teams.Sites do
|
||||
team_membership_query =
|
||||
from tm in Teams.Membership,
|
||||
inner_join: t in assoc(tm, :team),
|
||||
inner_join: u in assoc(tm, :user),
|
||||
as: :user,
|
||||
inner_join: s in assoc(t, :sites),
|
||||
as: :site,
|
||||
where: tm.user_id == ^user.id and tm.role != :guest,
|
||||
where:
|
||||
not exists(
|
||||
from st in Teams.SiteTransfer,
|
||||
where: st.email == parent_as(:user).email,
|
||||
where: st.site_id == parent_as(:site).id
|
||||
),
|
||||
select: %{
|
||||
site_id: s.id,
|
||||
entry_type: "site",
|
||||
@ -142,9 +151,18 @@ defmodule Plausible.Teams.Sites do
|
||||
|
||||
guest_membership_query =
|
||||
from(tm in Teams.Membership,
|
||||
inner_join: u in assoc(tm, :user),
|
||||
as: :user,
|
||||
inner_join: gm in assoc(tm, :guest_memberships),
|
||||
inner_join: s in assoc(gm, :site),
|
||||
as: :site,
|
||||
where: tm.user_id == ^user.id and tm.role == :guest,
|
||||
where:
|
||||
not exists(
|
||||
from st in Teams.SiteTransfer,
|
||||
where: st.email == parent_as(:user).email,
|
||||
where: st.site_id == parent_as(:site).id
|
||||
),
|
||||
select: %{
|
||||
site_id: s.id,
|
||||
entry_type: "site",
|
||||
@ -251,12 +269,14 @@ defmodule Plausible.Teams.Sites do
|
||||
fragment(
|
||||
"""
|
||||
CASE
|
||||
WHEN ? IS NOT NULL THEN 'invitation'
|
||||
WHEN ? IS NOT NULL THEN 'invitation'
|
||||
WHEN ? IS NOT NULL THEN 'pinned_site'
|
||||
ELSE ?
|
||||
END
|
||||
""",
|
||||
gi.id,
|
||||
st.id,
|
||||
up.pinned_at,
|
||||
u.entry_type
|
||||
),
|
||||
|
@ -26,6 +26,9 @@ defmodule Plausible.Teams.Team do
|
||||
has_one :subscription, Plausible.Billing.Subscription
|
||||
has_one :enterprise_plan, Plausible.Billing.EnterprisePlan
|
||||
|
||||
has_one :ownership, Plausible.Teams.Membership, where: [role: :owner]
|
||||
has_one :owner, through: [:ownership, :user]
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
|
@ -63,6 +63,7 @@ defmodule PlausibleWeb.Components.Billing.Notice do
|
||||
|
||||
attr(:billable_user, User, required: true)
|
||||
attr(:current_user, User, required: true)
|
||||
attr(:current_team, Plausible.Teams.Team, required: true)
|
||||
attr(:feature_mod, :atom, required: true, values: Feature.list())
|
||||
attr(:grandfathered?, :boolean, default: false)
|
||||
attr(:rest, :global)
|
||||
@ -76,13 +77,18 @@ defmodule PlausibleWeb.Components.Billing.Notice do
|
||||
{@rest}
|
||||
>
|
||||
<%= account_label(@current_user, @billable_user) %> does not have access to <%= @feature_mod.display_name() %>. To get access to this feature,
|
||||
<.upgrade_call_to_action current_user={@current_user} billable_user={@billable_user} />.
|
||||
<.upgrade_call_to_action
|
||||
current_team={@current_team}
|
||||
current_user={@current_user}
|
||||
billable_user={@billable_user}
|
||||
/>.
|
||||
</.notice>
|
||||
"""
|
||||
end
|
||||
|
||||
attr(:billable_user, User, required: true)
|
||||
attr(:current_user, User, required: true)
|
||||
attr(:current_team, Plausible.Teams.Team, required: true)
|
||||
attr(:limit, :integer, required: true)
|
||||
attr(:resource, :string, required: true)
|
||||
attr(:rest, :global)
|
||||
@ -91,12 +97,16 @@ defmodule PlausibleWeb.Components.Billing.Notice do
|
||||
~H"""
|
||||
<.notice {@rest} title="Notice">
|
||||
<%= account_label(@current_user, @billable_user) %> is limited to <%= @limit %> <%= @resource %>. To increase this limit,
|
||||
<.upgrade_call_to_action current_user={@current_user} billable_user={@billable_user} />.
|
||||
<.upgrade_call_to_action
|
||||
current_team={@current_team}
|
||||
current_user={@current_user}
|
||||
billable_user={@billable_user}
|
||||
/>.
|
||||
</.notice>
|
||||
"""
|
||||
end
|
||||
|
||||
attr(:user, :map, required: true)
|
||||
attr(:subscription, :map, required: true)
|
||||
attr(:dismissable, :boolean, default: true)
|
||||
|
||||
@doc """
|
||||
@ -117,18 +127,18 @@ defmodule PlausibleWeb.Components.Billing.Notice do
|
||||
def subscription_cancelled(
|
||||
%{
|
||||
dismissable: true,
|
||||
user: %User{subscription: %Subscription{status: Subscription.Status.deleted()}}
|
||||
subscription: %Subscription{status: Subscription.Status.deleted()}
|
||||
} = assigns
|
||||
) do
|
||||
~H"""
|
||||
<aside id="global-subscription-cancelled-notice" class="container">
|
||||
<.notice
|
||||
dismissable_id={Plausible.Billing.cancelled_subscription_notice_dismiss_id(@user)}
|
||||
dismissable_id={Plausible.Billing.cancelled_subscription_notice_dismiss_id(@subscription.id)}
|
||||
title="Subscription cancelled"
|
||||
theme={:red}
|
||||
class="shadow-md dark:shadow-none"
|
||||
>
|
||||
<.subscription_cancelled_notice_body user={@user} />
|
||||
<.subscription_cancelled_notice_body subscription={@subscription} />
|
||||
</.notice>
|
||||
</aside>
|
||||
"""
|
||||
@ -137,7 +147,7 @@ defmodule PlausibleWeb.Components.Billing.Notice do
|
||||
def subscription_cancelled(
|
||||
%{
|
||||
dismissable: false,
|
||||
user: %User{subscription: %Subscription{status: Subscription.Status.deleted()}}
|
||||
subscription: %Subscription{status: Subscription.Status.deleted()}
|
||||
} = assigns
|
||||
) do
|
||||
assigns = assign(assigns, :container_id, "local-subscription-cancelled-notice")
|
||||
@ -145,11 +155,11 @@ defmodule PlausibleWeb.Components.Billing.Notice do
|
||||
~H"""
|
||||
<aside id={@container_id} class="hidden">
|
||||
<.notice title="Subscription cancelled" theme={:red} class="shadow-md dark:shadow-none">
|
||||
<.subscription_cancelled_notice_body user={@user} />
|
||||
<.subscription_cancelled_notice_body subscription={@subscription} />
|
||||
</.notice>
|
||||
</aside>
|
||||
<script
|
||||
data-localstorage-key={"notice_dismissed__#{Plausible.Billing.cancelled_subscription_notice_dismiss_id(assigns.user)}"}
|
||||
data-localstorage-key={"notice_dismissed__#{Plausible.Billing.cancelled_subscription_notice_dismiss_id(@subscription.id)}"}
|
||||
data-container-id={@container_id}
|
||||
>
|
||||
const dataset = document.currentScript.dataset
|
||||
@ -251,7 +261,7 @@ defmodule PlausibleWeb.Components.Billing.Notice do
|
||||
end
|
||||
|
||||
defp subscription_cancelled_notice_body(assigns) do
|
||||
if Subscriptions.expired?(assigns.user.subscription) do
|
||||
if Subscriptions.expired?(assigns.subscription) do
|
||||
~H"""
|
||||
<.link
|
||||
class="underline inline-block"
|
||||
@ -264,7 +274,7 @@ defmodule PlausibleWeb.Components.Billing.Notice do
|
||||
else
|
||||
~H"""
|
||||
<p>
|
||||
You have access to your stats until <span class="font-semibold inline"><%= Calendar.strftime(@user.subscription.next_bill_date, "%b %-d, %Y") %></span>.
|
||||
You have access to your stats until <span class="font-semibold inline"><%= Calendar.strftime(@subscription.next_bill_date, "%b %-d, %Y") %></span>.
|
||||
<.link
|
||||
class="underline inline-block"
|
||||
href={Routes.billing_path(PlausibleWeb.Endpoint, :choose_plan)}
|
||||
@ -273,12 +283,12 @@ defmodule PlausibleWeb.Components.Billing.Notice do
|
||||
</.link>
|
||||
to make sure you don't lose access.
|
||||
</p>
|
||||
<.lose_grandfathering_warning user={@user} />
|
||||
<.lose_grandfathering_warning subscription={@subscription} />
|
||||
"""
|
||||
end
|
||||
end
|
||||
|
||||
defp lose_grandfathering_warning(%{user: %{subscription: subscription}} = assigns) do
|
||||
defp lose_grandfathering_warning(%{subscription: subscription} = assigns) do
|
||||
plan = Plans.get_regular_plan(subscription, only_non_expired: true)
|
||||
loses_grandfathering = plan && plan.generation < 4
|
||||
|
||||
@ -297,13 +307,14 @@ defmodule PlausibleWeb.Components.Billing.Notice do
|
||||
end
|
||||
|
||||
attr(:current_user, :map)
|
||||
attr(:current_team, :map)
|
||||
attr(:billable_user, :map)
|
||||
|
||||
defp upgrade_call_to_action(assigns) do
|
||||
billable_user = Plausible.Users.with_subscription(assigns.billable_user)
|
||||
team = Plausible.Teams.with_subscription(assigns.current_team)
|
||||
|
||||
upgrade_assistance_required? =
|
||||
case Plans.get_subscription_plan(billable_user.subscription) do
|
||||
case Plans.get_subscription_plan(team.subscription) do
|
||||
%Plausible.Billing.Plan{kind: :business} -> true
|
||||
%Plausible.Billing.EnterprisePlan{} -> true
|
||||
_ -> false
|
||||
|
@ -225,7 +225,7 @@ defmodule PlausibleWeb.Components.Billing.PlanBox do
|
||||
|> assign(:confirm_message, losing_features_message(feature_usage_check))
|
||||
|
||||
~H"""
|
||||
<%= if @owned_plan && Plausible.Billing.Subscriptions.resumable?(@current_user.subscription) do %>
|
||||
<%= if @owned_plan && Plausible.Billing.Subscriptions.resumable?(@current_team.subscription) do %>
|
||||
<.change_plan_link {assigns} />
|
||||
<% else %>
|
||||
<PlausibleWeb.Components.Billing.paddle_button
|
||||
|
@ -1,23 +1,29 @@
|
||||
defmodule PlausibleWeb.AdminController do
|
||||
use PlausibleWeb, :controller
|
||||
|
||||
alias Plausible.Billing.Quota
|
||||
alias Plausible.Teams
|
||||
|
||||
def usage(conn, params) do
|
||||
user =
|
||||
params["user_id"]
|
||||
|> String.to_integer()
|
||||
|> Plausible.Users.with_subscription()
|
||||
user_id = String.to_integer(params["user_id"])
|
||||
|
||||
usage = Quota.Usage.usage(user, with_features: true)
|
||||
team =
|
||||
case Teams.get_by_owner(user_id) do
|
||||
{:ok, team} ->
|
||||
Teams.with_subscription(team)
|
||||
|
||||
{:error, :no_team} ->
|
||||
nil
|
||||
end
|
||||
|
||||
usage = Teams.Billing.quota_usage(team, with_features: true)
|
||||
|
||||
limits = %{
|
||||
monthly_pageviews: Quota.Limits.monthly_pageview_limit(user.subscription),
|
||||
sites: Quota.Limits.site_limit(user),
|
||||
team_members: Quota.Limits.team_member_limit(user)
|
||||
monthly_pageviews: Teams.Billing.monthly_pageview_limit(team),
|
||||
sites: Teams.Billing.site_limit(team),
|
||||
team_members: Teams.Billing.team_member_limit(team)
|
||||
}
|
||||
|
||||
html_response = usage_and_limits_html(user, usage, limits, params["embed"] == "true")
|
||||
html_response = usage_and_limits_html(team, usage, limits, params["embed"] == "true")
|
||||
|
||||
conn
|
||||
|> put_resp_content_type("text/html")
|
||||
@ -25,14 +31,20 @@ defmodule PlausibleWeb.AdminController do
|
||||
end
|
||||
|
||||
def current_plan(conn, params) do
|
||||
user =
|
||||
params["user_id"]
|
||||
|> String.to_integer()
|
||||
|> Plausible.Users.with_subscription()
|
||||
user_id = String.to_integer(params["user_id"])
|
||||
|
||||
team =
|
||||
case Teams.get_by_owner(user_id) do
|
||||
{:ok, team} ->
|
||||
Teams.with_subscription(team)
|
||||
|
||||
{:error, :no_team} ->
|
||||
nil
|
||||
end
|
||||
|
||||
plan =
|
||||
case user && user.subscription &&
|
||||
Plausible.Billing.Plans.get_subscription_plan(user.subscription) do
|
||||
case team && team.subscription &&
|
||||
Plausible.Billing.Plans.get_subscription_plan(team.subscription) do
|
||||
%{} = plan ->
|
||||
plan
|
||||
|> Map.take([
|
||||
@ -56,9 +68,10 @@ defmodule PlausibleWeb.AdminController do
|
||||
|> send_resp(200, json_response)
|
||||
end
|
||||
|
||||
defp usage_and_limits_html(user, usage, limits, embed?) do
|
||||
defp usage_and_limits_html(team, usage, limits, embed?) do
|
||||
content = """
|
||||
<ul>
|
||||
<li>Team: <b>#{team && team.name}</b></li>
|
||||
<li>Sites: <b>#{usage.sites}</b> / #{limits.sites}</li>
|
||||
<li>Team members: <b>#{usage.team_members}</b> / #{limits.team_members}</li>
|
||||
<li>Features: #{features_usage(usage.features)}</li>
|
||||
@ -76,7 +89,7 @@ defmodule PlausibleWeb.AdminController do
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Usage - user:#{user.id}</title>
|
||||
<title>Usage - team:#{team.id}</title>
|
||||
<style>
|
||||
ul, li {margin-top: 10px;}
|
||||
body {padding-top: 10px;}
|
||||
|
@ -4,7 +4,7 @@ defmodule PlausibleWeb.BillingController do
|
||||
require Logger
|
||||
require Plausible.Billing.Subscription.Status
|
||||
alias Plausible.Billing
|
||||
alias Plausible.Billing.{Plans, Subscription}
|
||||
alias Plausible.Billing.Subscription
|
||||
|
||||
plug PlausibleWeb.RequireAccountPlug
|
||||
|
||||
@ -30,10 +30,14 @@ defmodule PlausibleWeb.BillingController do
|
||||
|
||||
def upgrade_to_enterprise_plan(conn, _params) do
|
||||
current_user = conn.assigns.current_user
|
||||
current_team = conn.assigns.current_team
|
||||
subscription = Plausible.Teams.Adapter.Read.Billing.get_subscription(current_user)
|
||||
|
||||
{latest_enterprise_plan, price} =
|
||||
Plans.latest_enterprise_plan_with_price(current_user, PlausibleWeb.RemoteIP.get(conn))
|
||||
Plausible.Teams.Billing.latest_enterprise_plan_with_price(
|
||||
current_team,
|
||||
PlausibleWeb.RemoteIP.get(conn)
|
||||
)
|
||||
|
||||
subscription_resumable? =
|
||||
Plausible.Billing.Subscriptions.resumable?(subscription)
|
||||
|
@ -8,7 +8,7 @@ defmodule PlausibleWeb.GoogleAnalyticsController do
|
||||
|
||||
plug(PlausibleWeb.RequireAccountPlug)
|
||||
|
||||
plug(PlausibleWeb.Plugs.AuthorizeSiteAccess, [:owner, :admin, :super_admin])
|
||||
plug(PlausibleWeb.Plugs.AuthorizeSiteAccess, [:owner, :editor, :admin, :super_admin])
|
||||
|
||||
def property_form(
|
||||
conn,
|
||||
|
@ -4,7 +4,7 @@ defmodule PlausibleWeb.InvitationController do
|
||||
plug PlausibleWeb.RequireAccountPlug
|
||||
|
||||
plug PlausibleWeb.Plugs.AuthorizeSiteAccess,
|
||||
[:owner, :admin] when action in [:remove_invitation]
|
||||
[:owner, :editor, :admin] when action in [:remove_invitation]
|
||||
|
||||
def accept_invitation(conn, %{"invitation_id" => invitation_id}) do
|
||||
case Plausible.Site.Memberships.accept_invitation(invitation_id, conn.assigns.current_user) do
|
||||
|
@ -21,7 +21,7 @@ defmodule PlausibleWeb.Site.MembershipController do
|
||||
plug PlausibleWeb.Plugs.AuthorizeSiteAccess, [:owner] when action in @only_owner_is_allowed_to
|
||||
|
||||
plug PlausibleWeb.Plugs.AuthorizeSiteAccess,
|
||||
[:owner, :admin] when action not in @only_owner_is_allowed_to
|
||||
[:owner, :editor, :admin] when action not in @only_owner_is_allowed_to
|
||||
|
||||
def invite_member_form(conn, _params) do
|
||||
site =
|
||||
@ -198,12 +198,16 @@ defmodule PlausibleWeb.Site.MembershipController do
|
||||
end
|
||||
end
|
||||
|
||||
defp can_grant_role_to_self?(:editor, :viewer), do: true
|
||||
defp can_grant_role_to_self?(:admin, :viewer), do: true
|
||||
defp can_grant_role_to_self?(_, _), do: false
|
||||
|
||||
defp can_grant_role_to_other?(:owner, :editor), do: true
|
||||
defp can_grant_role_to_other?(:owner, :admin), do: true
|
||||
defp can_grant_role_to_other?(:owner, :viewer), do: true
|
||||
defp can_grant_role_to_other?(:editor, :editor), do: true
|
||||
defp can_grant_role_to_other?(:admin, :admin), do: true
|
||||
defp can_grant_role_to_other?(:editor, :viewer), do: true
|
||||
defp can_grant_role_to_other?(:admin, :viewer), do: true
|
||||
defp can_grant_role_to_other?(_, _), do: false
|
||||
|
||||
|
@ -9,7 +9,7 @@ defmodule PlausibleWeb.SiteController do
|
||||
|
||||
plug(
|
||||
PlausibleWeb.Plugs.AuthorizeSiteAccess,
|
||||
[:owner, :admin, :super_admin] when action not in [:new, :create_site]
|
||||
[:owner, :admin, :editor, :super_admin] when action not in [:new, :create_site]
|
||||
)
|
||||
|
||||
def new(conn, params) do
|
||||
|
@ -60,6 +60,7 @@ defmodule PlausibleWeb.Live.GoalSettings do
|
||||
domain={@domain}
|
||||
site={@site}
|
||||
current_user={@current_user}
|
||||
current_team={@current_team}
|
||||
existing_goals={@all_goals}
|
||||
goal={@form_goal}
|
||||
on_save_goal={
|
||||
|
@ -37,6 +37,7 @@ defmodule PlausibleWeb.Live.GoalSettings.Form do
|
||||
event_name_options_count: length(assigns.event_name_options),
|
||||
event_name_options: Enum.map(assigns.event_name_options, &{&1, &1}),
|
||||
current_user: assigns.current_user,
|
||||
current_team: assigns.current_team,
|
||||
domain: assigns.domain,
|
||||
selected_tab: selected_tab,
|
||||
tab_sequence_id: 0,
|
||||
@ -73,6 +74,7 @@ defmodule PlausibleWeb.Live.GoalSettings.Form do
|
||||
f={f}
|
||||
suffix={@context_unique_id}
|
||||
current_user={@current_user}
|
||||
current_team={@current_team}
|
||||
site={@site}
|
||||
goal={@goal}
|
||||
existing_goals={@existing_goals}
|
||||
@ -115,6 +117,7 @@ defmodule PlausibleWeb.Live.GoalSettings.Form do
|
||||
f={f}
|
||||
suffix={suffix(@context_unique_id, @tab_sequence_id)}
|
||||
current_user={@current_user}
|
||||
current_team={@current_team}
|
||||
site={@site}
|
||||
existing_goals={@existing_goals}
|
||||
goal_options={@event_name_options}
|
||||
@ -199,6 +202,7 @@ defmodule PlausibleWeb.Live.GoalSettings.Form do
|
||||
attr(:f, Phoenix.HTML.Form)
|
||||
attr(:site, Plausible.Site)
|
||||
attr(:current_user, Plausible.Auth.User)
|
||||
attr(:current_team, Plausible.Teams.Team)
|
||||
attr(:suffix, :string)
|
||||
attr(:existing_goals, :list)
|
||||
attr(:goal_options, :list)
|
||||
@ -259,6 +263,7 @@ defmodule PlausibleWeb.Live.GoalSettings.Form do
|
||||
f={@f}
|
||||
site={@site}
|
||||
current_user={@current_user}
|
||||
current_team={@current_team}
|
||||
has_access_to_revenue_goals?={@has_access_to_revenue_goals?}
|
||||
goal={@goal}
|
||||
suffix={@suffix}
|
||||
@ -282,6 +287,7 @@ defmodule PlausibleWeb.Live.GoalSettings.Form do
|
||||
<PlausibleWeb.Components.Billing.Notice.premium_feature
|
||||
billable_user={@site.owner}
|
||||
current_user={@current_user}
|
||||
current_team={@current_team}
|
||||
feature_mod={Plausible.Billing.Feature.RevenueGoals}
|
||||
class="rounded-b-md"
|
||||
/>
|
||||
|
@ -499,15 +499,15 @@ defmodule PlausibleWeb.Live.Sites do
|
||||
>
|
||||
Upgrade
|
||||
</.button_link>
|
||||
<button
|
||||
type="button"
|
||||
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 dark:border-gray-500 shadow-sm px-4 py-2 bg-white dark:bg-gray-800 text-base font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-850 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
|
||||
<.button_link
|
||||
href="#"
|
||||
theme="bright"
|
||||
data-method="post"
|
||||
data-csrf={Plug.CSRFProtection.get_csrf_token()}
|
||||
x-bind:data-to="selectedInvitation && ('/sites/invitations/' + selectedInvitation.invitation.invitation_id + '/reject')"
|
||||
>
|
||||
Reject
|
||||
</button>
|
||||
</.button_link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -134,7 +134,7 @@ defmodule PlausibleWeb.Plugs.AuthorizePublicAPI do
|
||||
end
|
||||
|
||||
defp verify_site_access(api_key, site) do
|
||||
is_member? = Sites.is_member?(api_key.user_id, site)
|
||||
is_member? = Plausible.Teams.Memberships.site_member?(site, api_key.user)
|
||||
is_super_admin? = Auth.is_super_admin?(api_key.user_id)
|
||||
|
||||
cond do
|
||||
@ -144,7 +144,8 @@ defmodule PlausibleWeb.Plugs.AuthorizePublicAPI do
|
||||
Sites.locked?(site) ->
|
||||
{:error, :site_locked}
|
||||
|
||||
Plausible.Billing.Feature.StatsAPI.check_availability(api_key.user) !== :ok ->
|
||||
Plausible.Teams.Adapter.Read.Billing.check_feature_availability_for_stats_api(api_key.user) !==
|
||||
:ok ->
|
||||
{:error, :upgrade_required}
|
||||
|
||||
is_member? ->
|
||||
|
@ -38,7 +38,7 @@ defmodule PlausibleWeb.Plugs.AuthorizeSiteAccess do
|
||||
import Plug.Conn
|
||||
import Phoenix.Controller, only: [get_format: 1]
|
||||
|
||||
@all_roles [:public, :viewer, :admin, :super_admin, :owner]
|
||||
@all_roles [:public, :viewer, :admin, :editor, :super_admin, :owner]
|
||||
|
||||
def init([]), do: {@all_roles, nil}
|
||||
|
||||
@ -147,29 +147,18 @@ defmodule PlausibleWeb.Plugs.AuthorizeSiteAccess do
|
||||
end
|
||||
|
||||
defp get_site_with_role(conn, current_user, domain) do
|
||||
site_query =
|
||||
from(
|
||||
s in Plausible.Site,
|
||||
where: s.domain == ^domain,
|
||||
select: %{site: s}
|
||||
)
|
||||
site = Repo.get_by(Plausible.Site, domain: domain)
|
||||
|
||||
full_query =
|
||||
if current_user do
|
||||
from(s in site_query,
|
||||
left_join: sm in Plausible.Site.Membership,
|
||||
on: sm.site_id == s.id and sm.user_id == ^current_user.id,
|
||||
select_merge: %{role: sm.role}
|
||||
)
|
||||
else
|
||||
from(s in site_query,
|
||||
select_merge: %{role: nil}
|
||||
)
|
||||
end
|
||||
if site do
|
||||
site_role =
|
||||
case Plausible.Teams.Memberships.site_role(site, current_user) do
|
||||
{:ok, role} -> role
|
||||
_ -> nil
|
||||
end
|
||||
|
||||
case Repo.one(full_query) do
|
||||
%{site: _site} = result -> {:ok, result}
|
||||
_ -> error_not_found(conn)
|
||||
{:ok, %{site: site, role: site_role}}
|
||||
else
|
||||
error_not_found(conn)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -50,7 +50,10 @@ defmodule PlausibleWeb.Router do
|
||||
plug :accepts, ["json"]
|
||||
plug :fetch_session
|
||||
plug PlausibleWeb.AuthPlug
|
||||
plug PlausibleWeb.Plugs.AuthorizeSiteAccess, {[:admin, :super_admin, :owner], "site_id"}
|
||||
|
||||
plug PlausibleWeb.Plugs.AuthorizeSiteAccess,
|
||||
{[:admin, :editor, :super_admin, :owner], "site_id"}
|
||||
|
||||
plug PlausibleWeb.Plugs.NoRobots
|
||||
end
|
||||
|
||||
|
@ -2,27 +2,27 @@
|
||||
<%= render("_flash.html", assigns) %>
|
||||
<% end %>
|
||||
|
||||
<%= if @conn.assigns[:current_user] do %>
|
||||
<%= if @conn.assigns[:current_team] do %>
|
||||
<div class="flex flex-col gap-y-2">
|
||||
<Notice.active_grace_period
|
||||
:if={Plausible.Auth.GracePeriod.active?(@conn.assigns.current_user)}
|
||||
:if={Plausible.Auth.GracePeriod.active?(@conn.assigns.current_team)}
|
||||
enterprise?={
|
||||
Plausible.Teams.Adapter.Read.Billing.enterprise_configured?(@conn.assigns.current_user)
|
||||
Plausible.Teams.Adapter.Read.Billing.enterprise_configured?(@conn.assigns.current_team)
|
||||
}
|
||||
grace_period_end={grace_period_end(@conn.assigns.current_user)}
|
||||
grace_period_end={grace_period_end(@conn.assigns.current_team)}
|
||||
/>
|
||||
|
||||
<Notice.dashboard_locked :if={Plausible.Auth.GracePeriod.expired?(@conn.assigns.current_user)} />
|
||||
<Notice.dashboard_locked :if={Plausible.Auth.GracePeriod.expired?(@conn.assigns.current_team)} />
|
||||
|
||||
<Notice.subscription_cancelled user={@conn.assigns.current_user} />
|
||||
<Notice.subscription_cancelled subscription={@conn.assigns.current_team.subscription} />
|
||||
|
||||
<Notice.subscription_past_due
|
||||
subscription={@conn.assigns.current_user.subscription}
|
||||
subscription={@conn.assigns.current_team.subscription}
|
||||
class="container"
|
||||
/>
|
||||
|
||||
<Notice.subscription_paused
|
||||
subscription={@conn.assigns.current_user.subscription}
|
||||
subscription={@conn.assigns.current_team.subscription}
|
||||
class="container"
|
||||
/>
|
||||
</div>
|
||||
|
@ -10,6 +10,7 @@
|
||||
<PlausibleWeb.Components.Billing.Notice.premium_feature
|
||||
billable_user={@current_user}
|
||||
current_user={@current_user}
|
||||
current_team={@current_team}
|
||||
feature_mod={Plausible.Billing.Feature.StatsAPI}
|
||||
/>
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
<:title>Delete Account</:title>
|
||||
<:subtitle>Deleting your account removes all sites and stats you've collected</:subtitle>
|
||||
|
||||
<%= if Plausible.Billing.Subscription.Status.active?(@current_user.subscription) do %>
|
||||
<%= if Plausible.Billing.Subscription.Status.active?(@current_team && @current_team.subscription) do %>
|
||||
<.notice theme={:gray} title="Cannot delete account at this time">
|
||||
Your account cannot be deleted because you have an active subscription. If you want to delete your account, please cancel your subscription first.
|
||||
</.notice>
|
||||
|
@ -27,7 +27,7 @@
|
||||
</div>
|
||||
|
||||
<PlausibleWeb.Components.Billing.Notice.subscription_cancelled
|
||||
user={@current_user}
|
||||
subscription={@subscription}
|
||||
dismissable={false}
|
||||
/>
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
:if={Map.get(assigns, :is_at_limit, false)}
|
||||
current_user={@current_user}
|
||||
billable_user={@site.owner}
|
||||
current_team={@current_team}
|
||||
limit={Map.get(assigns, :team_member_limit, 0)}
|
||||
resource="team members"
|
||||
/>
|
||||
|
@ -9,6 +9,7 @@
|
||||
<PlausibleWeb.Components.Billing.Notice.limit_exceeded
|
||||
:if={@site_limit_exceeded?}
|
||||
current_user={@current_user}
|
||||
current_team={@current_team}
|
||||
billable_user={@current_user}
|
||||
limit={@site_limit}
|
||||
resource="sites"
|
||||
|
@ -15,6 +15,7 @@
|
||||
<PlausibleWeb.Components.Billing.Notice.premium_feature
|
||||
billable_user={@site.owner}
|
||||
current_user={@current_user}
|
||||
current_team={@current_team}
|
||||
feature_mod={Plausible.Billing.Feature.Funnels}
|
||||
/>
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
<PlausibleWeb.Components.Billing.Notice.premium_feature
|
||||
billable_user={@site.owner}
|
||||
current_user={@current_user}
|
||||
current_team={@current_team}
|
||||
feature_mod={Plausible.Billing.Feature.Props}
|
||||
grandfathered?
|
||||
/>
|
||||
|
@ -40,7 +40,7 @@
|
||||
Manage my subscription
|
||||
</.button_link>
|
||||
</div>
|
||||
<% role when role in [:admin, :viewer] -> %>
|
||||
<% role when role in [:admin, :viewer, :editor] -> %>
|
||||
<div class="mt-3 text-gray-600 dark:text-gray-300 text-center">
|
||||
<p>
|
||||
This dashboard is currently locked and cannot be accessed. The site owner
|
||||
|
@ -131,6 +131,8 @@ defmodule PlausibleWeb.UserAuth do
|
||||
inner_join: u in assoc(us, :user),
|
||||
as: :user,
|
||||
left_join: tm in assoc(u, :team_memberships),
|
||||
# TODO: whenever current_team.subscription is used to prevent user action, we must check whether the team association is ownership.
|
||||
# Otherwise regular members will be limited by team owner in cases like deleting their own account.
|
||||
on: tm.role != :guest,
|
||||
left_join: t in assoc(tm, :team),
|
||||
as: :team,
|
||||
|
@ -9,12 +9,13 @@
|
||||
#
|
||||
# We recommend using the bang functions (`insert!`, `update!`
|
||||
# and so on) as they will fail if something goes wrong.
|
||||
import Plausible.Teams.Test
|
||||
|
||||
words =
|
||||
for i <- 0..(:erlang.system_info(:atom_count) - 1),
|
||||
do: :erlang.binary_to_term(<<131, 75, i::24>>)
|
||||
|
||||
user = Plausible.Factory.insert(:user, email: "user@plausible.test", password: "plausible")
|
||||
user = new_user(email: "user@plausible.test", password: "plausible")
|
||||
|
||||
native_stats_range =
|
||||
Date.range(
|
||||
@ -51,19 +52,17 @@ long_random_urls =
|
||||
end
|
||||
|
||||
site =
|
||||
Plausible.Factory.insert(:site,
|
||||
new_site(
|
||||
domain: "dummy.site",
|
||||
native_stats_start_at: NaiveDateTime.new!(native_stats_range.first, ~T[00:00:00]),
|
||||
stats_start_date: NaiveDateTime.new!(legacy_imported_stats_range.first, ~T[00:00:00]),
|
||||
memberships: [
|
||||
Plausible.Factory.build(:site_membership, user: user, role: :owner),
|
||||
Plausible.Factory.build(:site_membership,
|
||||
user: Plausible.Factory.build(:user, name: "Arnold Wallaby", password: "plausible"),
|
||||
role: :viewer
|
||||
)
|
||||
]
|
||||
team: [
|
||||
native_stats_start_at: NaiveDateTime.new!(native_stats_range.first, ~T[00:00:00]),
|
||||
stats_start_date: NaiveDateTime.new!(legacy_imported_stats_range.first, ~T[00:00:00])
|
||||
],
|
||||
owner: user
|
||||
)
|
||||
|
||||
add_guest(site, user: new_user(name: "Arnold Wallaby", password: "plausible"), role: :viewer)
|
||||
|
||||
Plausible.Factory.insert_list(29, :ip_rule, site: site)
|
||||
Plausible.Factory.insert(:country_rule, site: site, country_code: "PL")
|
||||
Plausible.Factory.insert(:country_rule, site: site, country_code: "EE")
|
||||
|
@ -24,7 +24,7 @@ defmodule Plausible.Billing.FeatureTest do
|
||||
end
|
||||
|
||||
test "#{mod}.check_availability/1 returns error when site owner is on an old plan" do
|
||||
user = insert(:user, subscription: build(:subscription, paddle_plan_id: @v1_plan_id))
|
||||
user = new_user() |> subscribe_to_plan(@v1_plan_id)
|
||||
assert {:error, :upgrade_required} == unquote(mod).check_availability(user)
|
||||
end
|
||||
end
|
||||
|
@ -12,6 +12,7 @@ defmodule Plausible.Billing.PlansTest do
|
||||
test "growth_plans_for/1 returns v1 plans for a user on a legacy plan" do
|
||||
new_user()
|
||||
|> subscribe_to_plan(@legacy_plan_id)
|
||||
|> team_of(with_subscription?: true)
|
||||
|> Map.fetch!(:subscription)
|
||||
|> Plans.growth_plans_for()
|
||||
|> assert_generation(1)
|
||||
@ -20,6 +21,7 @@ defmodule Plausible.Billing.PlansTest do
|
||||
test "growth_plans_for/1 returns v1 plans for users who are already on v1 pricing" do
|
||||
new_user()
|
||||
|> subscribe_to_plan(@v1_plan_id)
|
||||
|> team_of(with_subscription?: true)
|
||||
|> Map.fetch!(:subscription)
|
||||
|> Plans.growth_plans_for()
|
||||
|> assert_generation(1)
|
||||
@ -28,6 +30,7 @@ defmodule Plausible.Billing.PlansTest do
|
||||
test "growth_plans_for/1 returns v2 plans for users who are already on v2 pricing" do
|
||||
new_user()
|
||||
|> subscribe_to_plan(@v2_plan_id)
|
||||
|> team_of(with_subscription?: true)
|
||||
|> Map.fetch!(:subscription)
|
||||
|> Plans.growth_plans_for()
|
||||
|> assert_generation(2)
|
||||
@ -36,6 +39,7 @@ defmodule Plausible.Billing.PlansTest do
|
||||
test "growth_plans_for/1 returns v4 plans for expired legacy subscriptions" do
|
||||
new_user()
|
||||
|> subscribe_to_plan(@v1_plan_id, status: :deleted, next_bill_date: ~D[2023-11-10])
|
||||
|> team_of(with_subscription?: true)
|
||||
|> Map.fetch!(:subscription)
|
||||
|> Plans.growth_plans_for()
|
||||
|> assert_generation(4)
|
||||
@ -43,7 +47,7 @@ defmodule Plausible.Billing.PlansTest do
|
||||
|
||||
test "growth_plans_for/1 shows v4 plans for everyone else" do
|
||||
new_user()
|
||||
|> Repo.preload(:subscription)
|
||||
|> team_of(with_subscription?: true)
|
||||
|> Map.fetch!(:subscription)
|
||||
|> Plans.growth_plans_for()
|
||||
|> assert_generation(4)
|
||||
@ -51,7 +55,7 @@ defmodule Plausible.Billing.PlansTest do
|
||||
|
||||
test "growth_plans_for/1 does not return business plans" do
|
||||
new_user()
|
||||
|> Repo.preload(:subscription)
|
||||
|> team_of(with_subscription?: true)
|
||||
|> Map.fetch!(:subscription)
|
||||
|> Plans.growth_plans_for()
|
||||
|> Enum.each(fn plan ->
|
||||
@ -62,6 +66,7 @@ defmodule Plausible.Billing.PlansTest do
|
||||
test "growth_plans_for/1 returns the latest generation of growth plans for a user with a business subscription" do
|
||||
new_user()
|
||||
|> subscribe_to_plan(@v3_business_plan_id)
|
||||
|> team_of(with_subscription?: true)
|
||||
|> Map.fetch!(:subscription)
|
||||
|> Plans.growth_plans_for()
|
||||
|> assert_generation(4)
|
||||
@ -70,6 +75,7 @@ defmodule Plausible.Billing.PlansTest do
|
||||
test "business_plans_for/1 returns v3 business plans for a user on a legacy plan" do
|
||||
new_user()
|
||||
|> subscribe_to_plan(@legacy_plan_id)
|
||||
|> team_of(with_subscription?: true)
|
||||
|> Map.fetch!(:subscription)
|
||||
|> Plans.business_plans_for()
|
||||
|> assert_generation(3)
|
||||
@ -78,7 +84,9 @@ defmodule Plausible.Billing.PlansTest do
|
||||
test "business_plans_for/1 returns v3 business plans for a v2 subscriber" do
|
||||
user = new_user() |> subscribe_to_plan(@v2_plan_id)
|
||||
|
||||
business_plans = Plans.business_plans_for(user.subscription)
|
||||
subscription = team_of(user, with_subscription?: true).subscription
|
||||
|
||||
business_plans = Plans.business_plans_for(subscription)
|
||||
|
||||
assert Enum.all?(business_plans, &(&1.kind == :business))
|
||||
assert_generation(business_plans, 3)
|
||||
@ -97,14 +105,22 @@ defmodule Plausible.Billing.PlansTest do
|
||||
new_user()
|
||||
|> subscribe_to_plan(@v2_plan_id, status: :deleted, next_bill_date: ~D[2023-11-10])
|
||||
|
||||
user.subscription
|
||||
user
|
||||
|> team_of(with_subscription?: true)
|
||||
|> Map.fetch!(:subscription)
|
||||
|> Plans.business_plans_for()
|
||||
|> assert_generation(4)
|
||||
end
|
||||
|
||||
test "business_plans_for/1 returns v4 business plans for everyone else" do
|
||||
user = new_user() |> Repo.preload(:subscription)
|
||||
business_plans = Plans.business_plans_for(user.subscription)
|
||||
user = new_user()
|
||||
|
||||
subscription =
|
||||
user
|
||||
|> team_of(with_subscription?: true)
|
||||
|> Map.fetch!(:subscription)
|
||||
|
||||
business_plans = Plans.business_plans_for(subscription)
|
||||
|
||||
assert Enum.all?(business_plans, &(&1.kind == :business))
|
||||
assert_generation(business_plans, 4)
|
||||
@ -113,8 +129,13 @@ defmodule Plausible.Billing.PlansTest do
|
||||
test "available_plans returns all plans for user with prices when asked for" do
|
||||
user = new_user() |> subscribe_to_plan(@v2_plan_id)
|
||||
|
||||
subscription =
|
||||
user
|
||||
|> team_of(with_subscription?: true)
|
||||
|> Map.fetch!(:subscription)
|
||||
|
||||
%{growth: growth_plans, business: business_plans} =
|
||||
Plans.available_plans_for(user.subscription, with_prices: true, customer_ip: "127.0.0.1")
|
||||
Plans.available_plans_for(subscription, with_prices: true, customer_ip: "127.0.0.1")
|
||||
|
||||
assert Enum.find(growth_plans, fn plan ->
|
||||
(%Money{} = plan.monthly_cost) && plan.monthly_product_id == @v2_plan_id
|
||||
@ -128,7 +149,9 @@ defmodule Plausible.Billing.PlansTest do
|
||||
test "available_plans returns all plans without prices by default" do
|
||||
user = new_user() |> subscribe_to_plan(@v2_plan_id)
|
||||
|
||||
assert %{growth: [_ | _], business: [_ | _]} = Plans.available_plans_for(user.subscription)
|
||||
subscription = team_of(user, with_subscription?: true).subscription
|
||||
|
||||
assert %{growth: [_ | _], business: [_ | _]} = Plans.available_plans_for(subscription)
|
||||
end
|
||||
|
||||
test "latest_enterprise_plan_with_price/1" do
|
||||
@ -156,24 +179,30 @@ defmodule Plausible.Billing.PlansTest do
|
||||
|
||||
describe "subscription_interval" do
|
||||
test "is based on the plan if user is on a standard plan" do
|
||||
user = insert(:user, subscription: build(:subscription, paddle_plan_id: @v1_plan_id))
|
||||
subscription =
|
||||
new_user()
|
||||
|> subscribe_to_plan(@v1_plan_id)
|
||||
|> team_of(with_subscription?: true)
|
||||
|> Map.fetch!(:subscription)
|
||||
|
||||
assert Plans.subscription_interval(user.subscription) == "monthly"
|
||||
assert Plans.subscription_interval(subscription) == "monthly"
|
||||
end
|
||||
|
||||
test "is N/A for free plan" do
|
||||
user = insert(:user, subscription: build(:subscription, paddle_plan_id: "free_10k"))
|
||||
subscription =
|
||||
new_user()
|
||||
|> subscribe_to_plan("free_10k")
|
||||
|> team_of(with_subscription?: true)
|
||||
|> Map.fetch!(:subscription)
|
||||
|
||||
assert Plans.subscription_interval(user.subscription) == "N/A"
|
||||
assert Plans.subscription_interval(subscription) == "N/A"
|
||||
end
|
||||
|
||||
test "is based on the enterprise plan if user is on an enterprise plan" do
|
||||
user = insert(:user)
|
||||
user = new_user()
|
||||
subscribe_to_enterprise_plan(user, billing_interval: :yearly)
|
||||
|
||||
enterprise_plan = insert(:enterprise_plan, user_id: user.id, billing_interval: :yearly)
|
||||
|
||||
subscription =
|
||||
insert(:subscription, user_id: user.id, paddle_plan_id: enterprise_plan.paddle_plan_id)
|
||||
subscription = user |> team_of(with_subscription?: true) |> Map.fetch!(:subscription)
|
||||
|
||||
assert Plans.subscription_interval(subscription) == :yearly
|
||||
end
|
||||
|
@ -217,20 +217,27 @@ defmodule Plausible.Billing.QuotaTest do
|
||||
end
|
||||
|
||||
test "is based on the enterprise plan if user is on an enterprise plan" do
|
||||
user = insert(:user)
|
||||
|
||||
enterprise_plan =
|
||||
insert(:enterprise_plan, user_id: user.id, monthly_pageview_limit: 100_000)
|
||||
user = new_user()
|
||||
|
||||
subscription =
|
||||
insert(:subscription, user_id: user.id, paddle_plan_id: enterprise_plan.paddle_plan_id)
|
||||
user
|
||||
|> subscribe_to_enterprise_plan(monthly_pageview_limit: 100_000)
|
||||
|> team_of()
|
||||
|> Repo.preload(:subscription)
|
||||
|> Map.fetch!(:subscription)
|
||||
|
||||
assert Quota.Limits.monthly_pageview_limit(subscription) == 100_000
|
||||
end
|
||||
|
||||
test "does not limit pageviews when user has a pending enterprise plan" do
|
||||
user = insert(:user)
|
||||
subscription = insert(:subscription, user_id: user.id, paddle_plan_id: "pending-enterprise")
|
||||
user = new_user()
|
||||
|
||||
subscription =
|
||||
user
|
||||
|> subscribe_to_plan("pending-enterprise")
|
||||
|> team_of()
|
||||
|> Repo.preload(:subscription)
|
||||
|> Map.fetch!(:subscription)
|
||||
|
||||
assert Quota.Limits.monthly_pageview_limit(subscription) == :unlimited
|
||||
end
|
||||
@ -462,14 +469,11 @@ defmodule Plausible.Billing.QuotaTest do
|
||||
end
|
||||
|
||||
test "returns the enterprise plan limit" do
|
||||
user =
|
||||
insert(:user,
|
||||
enterprise_plan:
|
||||
build(:enterprise_plan, paddle_plan_id: "123321", team_member_limit: 27),
|
||||
subscription: build(:subscription, paddle_plan_id: "123321")
|
||||
)
|
||||
user = new_user()
|
||||
subscribe_to_enterprise_plan(user, team_member_limit: 27)
|
||||
team = team_of(user)
|
||||
|
||||
assert 27 == Quota.Limits.team_member_limit(user)
|
||||
assert 27 == Plausible.Teams.Billing.team_member_limit(team)
|
||||
end
|
||||
|
||||
test "reads from json file when the user is on a v4 plan" do
|
||||
@ -512,13 +516,14 @@ defmodule Plausible.Billing.QuotaTest do
|
||||
test "returns [Funnels] when user/site uses funnels" do
|
||||
user = new_user()
|
||||
site = new_site(owner: user)
|
||||
team = team_of(user)
|
||||
|
||||
goals = insert_list(3, :goal, site: site, event_name: fn -> Ecto.UUID.generate() end)
|
||||
steps = Enum.map(goals, &%{"goal_id" => &1.id})
|
||||
Plausible.Funnels.create(site, "dummy", steps)
|
||||
|
||||
assert [Funnels] == Quota.Usage.features_usage(nil, [site.id])
|
||||
assert [Funnels] == Quota.Usage.features_usage(user)
|
||||
assert [Funnels] == Plausible.Teams.Billing.features_usage(nil, [site.id])
|
||||
assert [Funnels] == Plausible.Teams.Billing.features_usage(team)
|
||||
end
|
||||
|
||||
test "returns [RevenueGoals] when user/site uses revenue goals" do
|
||||
@ -559,25 +564,21 @@ defmodule Plausible.Billing.QuotaTest do
|
||||
owner: user
|
||||
)
|
||||
|
||||
team = team_of(user)
|
||||
|
||||
insert(:goal, currency: :USD, site: site, event_name: "Purchase")
|
||||
|
||||
goals = insert_list(3, :goal, site: site, event_name: fn -> Ecto.UUID.generate() end)
|
||||
steps = Enum.map(goals, &%{"goal_id" => &1.id})
|
||||
Plausible.Funnels.create(site, "dummy", steps)
|
||||
|
||||
assert [Props, Funnels, RevenueGoals, StatsAPI] == Quota.Usage.features_usage(user)
|
||||
assert [Props, Funnels, RevenueGoals, StatsAPI] ==
|
||||
Plausible.Teams.Billing.features_usage(team)
|
||||
end
|
||||
end
|
||||
|
||||
test "accounts only for sites the user owns" do
|
||||
user = insert(:user)
|
||||
|
||||
insert(:site,
|
||||
allowed_event_props: ["dummy"],
|
||||
memberships: [build(:site_membership, user: user, role: :admin)]
|
||||
)
|
||||
|
||||
assert [] == Quota.Usage.features_usage(user)
|
||||
assert [] == Plausible.Teams.Billing.features_usage(nil)
|
||||
end
|
||||
end
|
||||
|
||||
@ -606,21 +607,18 @@ defmodule Plausible.Billing.QuotaTest do
|
||||
|
||||
on_ee do
|
||||
test "returns the enterprise plan features" do
|
||||
user = insert(:user)
|
||||
user = new_user()
|
||||
|
||||
enterprise_plan =
|
||||
insert(:enterprise_plan,
|
||||
user_id: user.id,
|
||||
monthly_pageview_limit: 100_000,
|
||||
site_limit: 500,
|
||||
features: [Plausible.Billing.Feature.StatsAPI, Plausible.Billing.Feature.Funnels]
|
||||
)
|
||||
subscribe_to_enterprise_plan(user,
|
||||
monthly_pageview_limit: 100_000,
|
||||
site_limit: 500,
|
||||
features: [Plausible.Billing.Feature.StatsAPI, Plausible.Billing.Feature.Funnels]
|
||||
)
|
||||
|
||||
_subscription =
|
||||
insert(:subscription, user_id: user.id, paddle_plan_id: enterprise_plan.paddle_plan_id)
|
||||
team = team_of(user)
|
||||
|
||||
assert [Plausible.Billing.Feature.StatsAPI, Plausible.Billing.Feature.Funnels] ==
|
||||
Quota.Limits.allowed_features_for(user)
|
||||
Plausible.Teams.Billing.allowed_features_for(team)
|
||||
end
|
||||
end
|
||||
|
||||
@ -651,18 +649,22 @@ defmodule Plausible.Billing.QuotaTest do
|
||||
end
|
||||
|
||||
test "returns old plan features for enterprise customers who are due to change a plan" do
|
||||
user =
|
||||
insert(:user,
|
||||
enterprise_plan:
|
||||
build(:enterprise_plan,
|
||||
paddle_plan_id: "old-paddle-plan-id",
|
||||
features: [Plausible.Billing.Feature.StatsAPI]
|
||||
),
|
||||
subscription: build(:subscription, paddle_plan_id: "old-paddle-plan-id")
|
||||
)
|
||||
user = new_user()
|
||||
|
||||
insert(:enterprise_plan, user_id: user.id, paddle_plan_id: "new-paddle-plan-id")
|
||||
assert [Plausible.Billing.Feature.StatsAPI] == Quota.Limits.allowed_features_for(user)
|
||||
subscribe_to_enterprise_plan(user,
|
||||
paddle_plan_id: "old-paddle-plan-id",
|
||||
features: [Plausible.Billing.Feature.StatsAPI]
|
||||
)
|
||||
|
||||
subscribe_to_enterprise_plan(user,
|
||||
paddle_plan_id: "new-paddle-plan-id",
|
||||
subscription?: false
|
||||
)
|
||||
|
||||
team = team_of(user)
|
||||
|
||||
assert [Plausible.Billing.Feature.StatsAPI] ==
|
||||
Plausible.Teams.Billing.allowed_features_for(team)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
defmodule Plausible.HelpScoutTest do
|
||||
use Plausible.DataCase, async: true
|
||||
use Plausible.Teams.Test
|
||||
use Plausible
|
||||
|
||||
@moduletag :ee_only
|
||||
@ -54,7 +55,7 @@ defmodule Plausible.HelpScoutTest do
|
||||
|
||||
describe "get_details_for_customer/2" do
|
||||
test "returns details for user on trial" do
|
||||
%{id: user_id, email: email} = insert(:user)
|
||||
%{id: user_id, email: email} = new_user()
|
||||
stub_help_scout_requests(email)
|
||||
|
||||
crm_url = "#{PlausibleWeb.Endpoint.url()}/crm/auth/user/#{user_id}"
|
||||
@ -74,7 +75,7 @@ defmodule Plausible.HelpScoutTest do
|
||||
end
|
||||
|
||||
test "returns for user without trial or subscription" do
|
||||
%{email: email} = insert(:user, trial_expiry_date: nil)
|
||||
%{email: email} = new_user(trial_expiry_date: nil)
|
||||
stub_help_scout_requests(email)
|
||||
|
||||
assert {:ok,
|
||||
@ -87,7 +88,9 @@ defmodule Plausible.HelpScoutTest do
|
||||
end
|
||||
|
||||
test "returns for user with trial expired" do
|
||||
%{email: email} = insert(:user, trial_expiry_date: Date.add(Date.utc_today(), -1))
|
||||
%{email: email} =
|
||||
new_user(trial_expiry_date: Date.add(Date.utc_today(), -1))
|
||||
|
||||
stub_help_scout_requests(email)
|
||||
|
||||
assert {:ok,
|
||||
@ -100,10 +103,15 @@ defmodule Plausible.HelpScoutTest do
|
||||
end
|
||||
|
||||
test "returns for user with paid subscription on standard plan" do
|
||||
user = %{email: email} = insert(:user, trial_expiry_date: Date.add(Date.utc_today(), -1))
|
||||
user = %{email: email} = new_user(trial_expiry_date: Date.add(Date.utc_today(), -1))
|
||||
|
||||
%{paddle_subscription_id: paddle_subscription_id} =
|
||||
insert(:subscription, user: user, paddle_plan_id: @v4_business_monthly_plan_id)
|
||||
subscribe_to_plan(user, @v4_business_monthly_plan_id)
|
||||
|
||||
paddle_subscription_id =
|
||||
user
|
||||
|> team_of(with_subscription?: true)
|
||||
|> Map.fetch!(:subscription)
|
||||
|> Map.fetch!(:paddle_subscription_id)
|
||||
|
||||
stub_help_scout_requests(email)
|
||||
|
||||
@ -120,10 +128,15 @@ defmodule Plausible.HelpScoutTest do
|
||||
end
|
||||
|
||||
test "returns for user with paid subscription on standard yearly plan" do
|
||||
user = %{email: email} = insert(:user, trial_expiry_date: Date.add(Date.utc_today(), -1))
|
||||
user = %{email: email} = new_user(trial_expiry_date: Date.add(Date.utc_today(), -1))
|
||||
|
||||
%{paddle_subscription_id: paddle_subscription_id} =
|
||||
insert(:subscription, user: user, paddle_plan_id: @v4_business_yearly_plan_id)
|
||||
subscribe_to_plan(user, @v4_business_yearly_plan_id)
|
||||
|
||||
paddle_subscription_id =
|
||||
user
|
||||
|> team_of(with_subscription?: true)
|
||||
|> Map.fetch!(:subscription)
|
||||
|> Map.fetch!(:paddle_subscription_id)
|
||||
|
||||
stub_help_scout_requests(email)
|
||||
|
||||
@ -140,9 +153,9 @@ defmodule Plausible.HelpScoutTest do
|
||||
end
|
||||
|
||||
test "returns for user with paid subscription on free 10k plan" do
|
||||
user = %{email: email} = insert(:user, trial_expiry_date: Date.add(Date.utc_today(), -1))
|
||||
user = %{email: email} = new_user(trial_expiry_date: Date.add(Date.utc_today(), -1))
|
||||
|
||||
insert(:subscription, user: user, paddle_plan_id: "free_10k")
|
||||
subscribe_to_plan(user, "free_10k")
|
||||
|
||||
stub_help_scout_requests(email)
|
||||
|
||||
@ -156,15 +169,11 @@ defmodule Plausible.HelpScoutTest do
|
||||
end
|
||||
|
||||
test "returns for user with paid subscription on enterprise plan" do
|
||||
user = %{email: email} = insert(:user, trial_expiry_date: Date.add(Date.utc_today(), -1))
|
||||
user = %{email: email} = new_user(trial_expiry_date: Date.add(Date.utc_today(), -1))
|
||||
|
||||
ep =
|
||||
insert(:enterprise_plan,
|
||||
features: [Plausible.Billing.Feature.StatsAPI],
|
||||
user_id: user.id
|
||||
)
|
||||
|
||||
insert(:subscription, user: user, paddle_plan_id: ep.paddle_plan_id)
|
||||
subscribe_to_enterprise_plan(user,
|
||||
features: [Plausible.Billing.Feature.StatsAPI]
|
||||
)
|
||||
|
||||
stub_help_scout_requests(email)
|
||||
|
||||
@ -178,16 +187,12 @@ defmodule Plausible.HelpScoutTest do
|
||||
end
|
||||
|
||||
test "returns for user with paid subscription on yearly enterprise plan" do
|
||||
user = %{email: email} = insert(:user, trial_expiry_date: Date.add(Date.utc_today(), -1))
|
||||
user = %{email: email} = new_user(trial_expiry_date: Date.add(Date.utc_today(), -1))
|
||||
|
||||
ep =
|
||||
insert(:enterprise_plan,
|
||||
features: [Plausible.Billing.Feature.StatsAPI],
|
||||
user_id: user.id,
|
||||
billing_interval: :yearly
|
||||
)
|
||||
|
||||
insert(:subscription, user: user, paddle_plan_id: ep.paddle_plan_id)
|
||||
subscribe_to_enterprise_plan(user,
|
||||
features: [Plausible.Billing.Feature.StatsAPI],
|
||||
billing_interval: :yearly
|
||||
)
|
||||
|
||||
stub_help_scout_requests(email)
|
||||
|
||||
@ -201,12 +206,10 @@ defmodule Plausible.HelpScoutTest do
|
||||
end
|
||||
|
||||
test "returns for user with subscription pending cancellation" do
|
||||
user = %{email: email} = insert(:user, trial_expiry_date: Date.add(Date.utc_today(), -1))
|
||||
user = %{email: email} = new_user(trial_expiry_date: Date.add(Date.utc_today(), -1))
|
||||
|
||||
insert(:subscription,
|
||||
user: user,
|
||||
status: Subscription.Status.deleted(),
|
||||
paddle_plan_id: @v4_business_monthly_plan_id
|
||||
subscribe_to_plan(user, @v4_business_monthly_plan_id,
|
||||
status: Subscription.Status.deleted()
|
||||
)
|
||||
|
||||
stub_help_scout_requests(email)
|
||||
@ -221,12 +224,10 @@ defmodule Plausible.HelpScoutTest do
|
||||
end
|
||||
|
||||
test "returns for user with canceled subscription" do
|
||||
user = %{email: email} = insert(:user, trial_expiry_date: Date.add(Date.utc_today(), -1))
|
||||
user = %{email: email} = new_user(trial_expiry_date: Date.add(Date.utc_today(), -1))
|
||||
|
||||
insert(:subscription,
|
||||
user: user,
|
||||
subscribe_to_plan(user, @v4_business_monthly_plan_id,
|
||||
status: Subscription.Status.deleted(),
|
||||
paddle_plan_id: @v4_business_monthly_plan_id,
|
||||
next_bill_date: Date.add(Date.utc_today(), -1)
|
||||
)
|
||||
|
||||
@ -242,12 +243,10 @@ defmodule Plausible.HelpScoutTest do
|
||||
end
|
||||
|
||||
test "returns for user with paused subscription" do
|
||||
user = %{email: email} = insert(:user, trial_expiry_date: Date.add(Date.utc_today(), -1))
|
||||
user = %{email: email} = new_user(trial_expiry_date: Date.add(Date.utc_today(), -1))
|
||||
|
||||
insert(:subscription,
|
||||
user: user,
|
||||
status: Subscription.Status.paused(),
|
||||
paddle_plan_id: @v4_business_monthly_plan_id
|
||||
subscribe_to_plan(user, @v4_business_monthly_plan_id,
|
||||
status: Subscription.Status.paused()
|
||||
)
|
||||
|
||||
stub_help_scout_requests(email)
|
||||
@ -262,11 +261,10 @@ defmodule Plausible.HelpScoutTest do
|
||||
end
|
||||
|
||||
test "returns for user with locked site" do
|
||||
user = %{email: email} = insert(:user, trial_expiry_date: Date.add(Date.utc_today(), -1))
|
||||
user = %{email: email} = new_user(trial_expiry_date: Date.add(Date.utc_today(), -1))
|
||||
|
||||
insert(:site, members: [user], locked: true)
|
||||
|
||||
insert(:subscription, user: user, paddle_plan_id: @v4_business_monthly_plan_id)
|
||||
new_site(owner: user, locked: true)
|
||||
subscribe_to_plan(user, @v4_business_monthly_plan_id)
|
||||
|
||||
stub_help_scout_requests(email)
|
||||
|
||||
@ -281,7 +279,7 @@ defmodule Plausible.HelpScoutTest do
|
||||
end
|
||||
|
||||
test "returns error when no matching user found in database" do
|
||||
insert(:user)
|
||||
new_user()
|
||||
|
||||
stub_help_scout_requests("another@example.com")
|
||||
|
||||
@ -329,7 +327,7 @@ defmodule Plausible.HelpScoutTest do
|
||||
end
|
||||
|
||||
test "uses existing access token when available" do
|
||||
%{email: email} = insert(:user)
|
||||
%{email: email} = new_user()
|
||||
now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
|
||||
|
||||
Repo.insert_all("help_scout_credentials", [
|
||||
@ -359,7 +357,7 @@ defmodule Plausible.HelpScoutTest do
|
||||
end
|
||||
|
||||
test "refreshes token on expiry" do
|
||||
%{email: email} = insert(:user)
|
||||
%{email: email} = new_user()
|
||||
now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
|
||||
|
||||
Repo.insert_all("help_scout_credentials", [
|
||||
@ -407,7 +405,7 @@ defmodule Plausible.HelpScoutTest do
|
||||
|
||||
describe "get_details_for_emails/2" do
|
||||
test "returns details for user and persists mapping" do
|
||||
%{id: user_id, email: email} = insert(:user)
|
||||
%{id: user_id, email: email} = new_user()
|
||||
|
||||
crm_url = "#{PlausibleWeb.Endpoint.url()}/crm/auth/user/#{user_id}"
|
||||
|
||||
@ -428,8 +426,9 @@ defmodule Plausible.HelpScoutTest do
|
||||
end
|
||||
|
||||
test "updates mapping if one already exists" do
|
||||
user = insert(:user)
|
||||
%{email: new_email} = insert(:user)
|
||||
user = new_user()
|
||||
%{email: new_email} = new_user()
|
||||
|
||||
HelpScout.set_mapping("123", user.email)
|
||||
|
||||
assert {:ok, _} = HelpScout.get_details_for_emails([new_email], "123")
|
||||
@ -437,12 +436,14 @@ defmodule Plausible.HelpScoutTest do
|
||||
end
|
||||
|
||||
test "picks the match with largest number of owned sites" do
|
||||
user1 = insert(:user)
|
||||
insert(:site, members: [user1])
|
||||
insert(:site_membership, site: build(:site), user: user1, role: :viewer)
|
||||
insert(:site_membership, site: build(:site), user: user1, role: :admin)
|
||||
user2 = insert(:user)
|
||||
insert_list(2, :site, members: [user2])
|
||||
user1 = new_user()
|
||||
new_site(owner: user1)
|
||||
add_guest(new_site(), user: user1, role: :viewer)
|
||||
add_guest(new_site(), user: user1, role: :editor)
|
||||
|
||||
user2 = new_user()
|
||||
new_site(owner: user2)
|
||||
new_site(owner: user2)
|
||||
|
||||
crm_url = "#{PlausibleWeb.Endpoint.url()}/crm/auth/user/#{user2.id}"
|
||||
|
||||
@ -473,14 +474,14 @@ defmodule Plausible.HelpScoutTest do
|
||||
|
||||
describe "search_users/2" do
|
||||
test "lists matching users by email or site domain ordered by site counts" do
|
||||
user1 = insert(:user, email: "user1@match.example.com")
|
||||
user1 = new_user(email: "user1@match.example.com")
|
||||
|
||||
user2 = insert(:user, email: "user2@match.example.com")
|
||||
insert(:site, members: [user2])
|
||||
user2 = new_user(email: "user2@match.example.com")
|
||||
new_site(owner: user2)
|
||||
|
||||
user3 = insert(:user, email: "user3@umatched.example.com")
|
||||
insert(:site, members: [user3])
|
||||
insert(:site, domain: "big.match.example.com/hit", members: [user3])
|
||||
user3 = new_user(email: "user3@umatched.example.com")
|
||||
new_site(owner: user3)
|
||||
new_site(domain: "big.match.example.com/hit", owner: user3)
|
||||
|
||||
assert HelpScout.search_users("match.example.co", "123") == [
|
||||
%{email: user3.email, sites_count: 2},
|
||||
|
@ -2,6 +2,7 @@ defmodule Plausible.Imported.CSVImporterTest do
|
||||
use Plausible
|
||||
use Plausible.Repo
|
||||
use PlausibleWeb.ConnCase
|
||||
use Plausible.Teams.Test
|
||||
use Bamboo.Test
|
||||
alias Plausible.Imported.{CSVImporter, SiteImport}
|
||||
require SiteImport
|
||||
@ -486,8 +487,8 @@ defmodule Plausible.Imported.CSVImporterTest do
|
||||
|
||||
@tag :tmp_dir
|
||||
test "it works", %{conn: conn, user: user, tmp_dir: tmp_dir} do
|
||||
exported_site = insert(:site, members: [user])
|
||||
imported_site = insert(:site, members: [user])
|
||||
exported_site = new_site(owner: user)
|
||||
imported_site = new_site(owner: user)
|
||||
|
||||
insert(:goal, site: exported_site, event_name: "Outbound Link: Click")
|
||||
insert(:goal, site: exported_site, event_name: "404")
|
||||
|
@ -1,5 +1,6 @@
|
||||
defmodule Plausible.Ingestion.CountersTest do
|
||||
use Plausible.DataCase, async: false
|
||||
use Plausible.Teams.Test
|
||||
import Ecto.Query
|
||||
|
||||
alias Plausible.Ingestion.Counters
|
||||
@ -115,7 +116,7 @@ defmodule Plausible.Ingestion.CountersTest do
|
||||
domain = Keyword.get(opts, :domain, random_domain())
|
||||
at = Keyword.get(opts, :at, NaiveDateTime.utc_now())
|
||||
|
||||
site = insert(:site, domain: domain)
|
||||
site = new_site(domain: domain)
|
||||
|
||||
payload = %{
|
||||
name: "pageview",
|
||||
|
@ -1,5 +1,6 @@
|
||||
defmodule Plausible.Ingestion.EventTelemetryTest do
|
||||
import Phoenix.ConnTest
|
||||
import Plausible.Teams.Test
|
||||
|
||||
alias Plausible.Ingestion.Request
|
||||
alias Plausible.Ingestion.Event
|
||||
@ -24,7 +25,7 @@ defmodule Plausible.Ingestion.EventTelemetryTest do
|
||||
%{}
|
||||
)
|
||||
|
||||
site = insert(:site, ingest_rate_limit_threshold: 2)
|
||||
site = new_site(ingest_rate_limit_threshold: 2)
|
||||
|
||||
payload = %{
|
||||
name: "pageview",
|
||||
|
@ -1,5 +1,6 @@
|
||||
defmodule Plausible.Ingestion.EventTest do
|
||||
use Plausible.DataCase, async: true
|
||||
use Plausible.Teams.Test
|
||||
|
||||
import Phoenix.ConnTest
|
||||
|
||||
@ -7,7 +8,7 @@ defmodule Plausible.Ingestion.EventTest do
|
||||
alias Plausible.Ingestion.Event
|
||||
|
||||
test "processes a request into an event" do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
|
||||
payload = %{
|
||||
name: "pageview",
|
||||
@ -27,7 +28,7 @@ defmodule Plausible.Ingestion.EventTest do
|
||||
|
||||
for {user_agent, idx} <- Enum.with_index(@regressive_user_agents) do
|
||||
test "processes user agents known to cause problems parsing in the past (case #{idx})" do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
|
||||
payload = %{
|
||||
name: "pageview",
|
||||
@ -45,7 +46,7 @@ defmodule Plausible.Ingestion.EventTest do
|
||||
end
|
||||
|
||||
test "drops verification agent" do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
|
||||
payload = %{
|
||||
name: "pageview",
|
||||
@ -76,7 +77,7 @@ defmodule Plausible.Ingestion.EventTest do
|
||||
end
|
||||
|
||||
test "drops a request when referrer is spam" do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
|
||||
payload = %{
|
||||
name: "pageview",
|
||||
@ -93,7 +94,7 @@ defmodule Plausible.Ingestion.EventTest do
|
||||
end
|
||||
|
||||
test "drops a request when referrer is spam for multiple domains" do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
|
||||
payload = %{
|
||||
name: "pageview",
|
||||
@ -110,7 +111,7 @@ defmodule Plausible.Ingestion.EventTest do
|
||||
end
|
||||
|
||||
test "selectively drops an event for multiple domains" do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
|
||||
payload = %{
|
||||
name: "pageview",
|
||||
@ -126,7 +127,7 @@ defmodule Plausible.Ingestion.EventTest do
|
||||
end
|
||||
|
||||
test "selectively drops an event when rate-limited" do
|
||||
site = insert(:site, ingest_rate_limit_threshold: 1)
|
||||
site = new_site(ingest_rate_limit_threshold: 1)
|
||||
|
||||
payload = %{
|
||||
name: "pageview",
|
||||
@ -143,7 +144,7 @@ defmodule Plausible.Ingestion.EventTest do
|
||||
end
|
||||
|
||||
test "drops a request when header x-plausible-ip-type is dc_ip" do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
|
||||
payload = %{
|
||||
name: "pageview",
|
||||
@ -160,7 +161,7 @@ defmodule Plausible.Ingestion.EventTest do
|
||||
end
|
||||
|
||||
test "drops a request when ip is on blocklist" do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
|
||||
payload = %{
|
||||
name: "pageview",
|
||||
@ -180,7 +181,7 @@ defmodule Plausible.Ingestion.EventTest do
|
||||
end
|
||||
|
||||
test "drops a request when country is on blocklist" do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
|
||||
payload = %{
|
||||
name: "pageview",
|
||||
@ -201,7 +202,7 @@ defmodule Plausible.Ingestion.EventTest do
|
||||
end
|
||||
|
||||
test "drops a request when page is on blocklist" do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
|
||||
payload = %{
|
||||
name: "pageview",
|
||||
@ -220,7 +221,7 @@ defmodule Plausible.Ingestion.EventTest do
|
||||
end
|
||||
|
||||
test "drops a request when hostname allowlist is defined and hostname is not on the list" do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
|
||||
payload = %{
|
||||
name: "pageview",
|
||||
@ -239,7 +240,7 @@ defmodule Plausible.Ingestion.EventTest do
|
||||
end
|
||||
|
||||
test "passes a request when hostname allowlist is defined and hostname is on the list" do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
|
||||
payload = %{
|
||||
name: "pageview",
|
||||
@ -259,11 +260,8 @@ defmodule Plausible.Ingestion.EventTest do
|
||||
test "drops events for site with accept_trafic_until in the past" do
|
||||
yesterday = Date.add(Date.utc_today(), -1)
|
||||
|
||||
site =
|
||||
insert(:site,
|
||||
ingest_rate_limit_threshold: 1,
|
||||
members: [build(:user, accept_traffic_until: yesterday)]
|
||||
)
|
||||
owner = new_user(team: [accept_traffic_until: yesterday])
|
||||
site = new_site(ingest_rate_limit_threshold: 1, owner: owner)
|
||||
|
||||
payload = %{
|
||||
name: "pageview",
|
||||
@ -280,7 +278,7 @@ defmodule Plausible.Ingestion.EventTest do
|
||||
|
||||
@tag :slow
|
||||
test "drops events on session lock timeout" do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
|
||||
very_slow_buffer = fn sessions ->
|
||||
Process.sleep(1000)
|
||||
@ -319,7 +317,7 @@ defmodule Plausible.Ingestion.EventTest do
|
||||
end
|
||||
|
||||
test "drops pageleave event when no session found from cache" do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
|
||||
payload = %{
|
||||
name: "pageleave",
|
||||
@ -336,7 +334,7 @@ defmodule Plausible.Ingestion.EventTest do
|
||||
|
||||
@tag :ee_only
|
||||
test "saves revenue amount" do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
_goal = insert(:goal, event_name: "checkout", currency: "USD", site: site)
|
||||
|
||||
payload = %{
|
||||
@ -353,7 +351,7 @@ defmodule Plausible.Ingestion.EventTest do
|
||||
end
|
||||
|
||||
test "does not save revenue amount when there is no revenue goal" do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
|
||||
payload = %{
|
||||
name: "checkout",
|
||||
@ -369,7 +367,7 @@ defmodule Plausible.Ingestion.EventTest do
|
||||
end
|
||||
|
||||
test "IPv4 hostname is stored without public suffix processing" do
|
||||
_site = insert(:site, domain: "192.168.0.1")
|
||||
_site = new_site(domain: "192.168.0.1")
|
||||
|
||||
payload = %{
|
||||
name: "checkout",
|
||||
@ -384,7 +382,7 @@ defmodule Plausible.Ingestion.EventTest do
|
||||
end
|
||||
|
||||
test "Hostname is stored with public suffix processing" do
|
||||
_site = insert(:site, domain: "foo.netlify.app")
|
||||
_site = new_site(domain: "foo.netlify.app")
|
||||
|
||||
payload = %{
|
||||
name: "checkout",
|
||||
@ -399,7 +397,7 @@ defmodule Plausible.Ingestion.EventTest do
|
||||
end
|
||||
|
||||
test "hostname is (none) when no hostname can be derived from the url" do
|
||||
site = insert(:site, domain: "foo.example.com")
|
||||
site = new_site(domain: "foo.example.com")
|
||||
|
||||
payload = %{
|
||||
domain: site.domain,
|
||||
|
@ -13,26 +13,15 @@ defmodule Plausible.Site.CacheTest do
|
||||
name: :"cache_supervisor_#{test}"
|
||||
)
|
||||
|
||||
%{id: first_id} = site1 = insert(:site, domain: "site1.example.com")
|
||||
%{id: first_id} = site1 = new_site(domain: "site1.example.com")
|
||||
|
||||
_ =
|
||||
insert(:site,
|
||||
domain: "site2.example.com",
|
||||
memberships: [
|
||||
build(:site_membership,
|
||||
user: build(:user, accept_traffic_until: ~D[2022-01-01]),
|
||||
role: :viewer
|
||||
),
|
||||
build(:site_membership,
|
||||
user: build(:user, accept_traffic_until: ~D[2021-01-01]),
|
||||
role: :owner
|
||||
),
|
||||
build(:site_membership,
|
||||
user: build(:user, accept_traffic_until: ~D[2020-01-01]),
|
||||
role: :admin
|
||||
)
|
||||
]
|
||||
)
|
||||
owner = new_user(team: [accept_traffic_until: ~D[2021-01-01]])
|
||||
viewer = new_user(team: [accept_traffic_until: ~D[2022-01-01]])
|
||||
admin = new_user(team: [accept_traffic_until: ~D[2020-01-01]])
|
||||
|
||||
site = new_site(owner: owner, domain: "site2.example.com")
|
||||
add_guest(site, user: viewer, role: :viewer)
|
||||
add_guest(site, user: admin, role: :editor)
|
||||
|
||||
:ok = Cache.refresh_all(cache_name: test)
|
||||
|
||||
@ -46,7 +35,7 @@ defmodule Plausible.Site.CacheTest do
|
||||
assert %Site{from_cache?: true} =
|
||||
Cache.get("site2.example.com", force?: true, cache_name: test)
|
||||
|
||||
assert %Site{from_cache?: false, owner: %{accept_traffic_until: ~D[2021-01-01]}} =
|
||||
assert %Site{from_cache?: false, team: %{accept_traffic_until: ~D[2021-01-01]}} =
|
||||
Cache.get("site2.example.com", cache_name: test)
|
||||
|
||||
refute Cache.get("site3.example.com", cache_name: test, force?: true)
|
||||
@ -143,14 +132,14 @@ defmodule Plausible.Site.CacheTest do
|
||||
|
||||
test "cache is ready when refreshed", %{test: test} do
|
||||
{:ok, _} = start_test_cache(test)
|
||||
insert(:site)
|
||||
new_site()
|
||||
:ok = Cache.refresh_all(cache_name: test)
|
||||
assert Cache.ready?(test)
|
||||
end
|
||||
|
||||
test "cache allows lookups for sites with changed domain", %{test: test} do
|
||||
{:ok, _} = start_test_cache(test)
|
||||
insert(:site, domain: "new.example.com", domain_changed_from: "old.example.com")
|
||||
new_site(domain: "new.example.com", domain_changed_from: "old.example.com")
|
||||
:ok = Cache.refresh_all(cache_name: test)
|
||||
|
||||
assert Cache.get("old.example.com", force?: true, cache_name: test)
|
||||
@ -160,7 +149,7 @@ defmodule Plausible.Site.CacheTest do
|
||||
test "cache exposes hit rate", %{test: test} do
|
||||
{:ok, _} = start_test_cache(test)
|
||||
|
||||
insert(:site, domain: "site1.example.com")
|
||||
new_site(domain: "site1.example.com")
|
||||
:ok = Cache.refresh_all(cache_name: test)
|
||||
|
||||
assert Cache.hit_rate(test) == 0
|
||||
@ -179,9 +168,9 @@ defmodule Plausible.Site.CacheTest do
|
||||
cache_opts = [cache_name: test, force?: true]
|
||||
|
||||
yesterday = DateTime.utc_now() |> DateTime.add(-1 * 60 * 60 * 24)
|
||||
insert(:site, domain: domain1, inserted_at: yesterday, updated_at: yesterday)
|
||||
new_site(domain: domain1, inserted_at: yesterday, updated_at: yesterday)
|
||||
|
||||
insert(:site, domain: domain2)
|
||||
new_site(domain: domain2)
|
||||
|
||||
assert Cache.get(domain1, cache_opts) == nil
|
||||
assert Cache.get(domain2, cache_opts) == nil
|
||||
@ -199,7 +188,7 @@ defmodule Plausible.Site.CacheTest do
|
||||
domain1 = "first.example.com"
|
||||
domain2 = "second.example.com"
|
||||
|
||||
site = insert(:site, domain: domain1)
|
||||
site = new_site(domain: domain1)
|
||||
assert :ok = Cache.refresh_updated_recently(cache_opts)
|
||||
assert item = Cache.get(domain1, cache_opts)
|
||||
refute item.domain_changed_from
|
||||
@ -250,7 +239,7 @@ defmodule Plausible.Site.CacheTest do
|
||||
test "get_site_id/2", %{test: test} do
|
||||
{:ok, _} = start_test_cache(test)
|
||||
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
|
||||
domain1 = site.domain
|
||||
domain2 = "nonexisting.example.com"
|
||||
@ -353,8 +342,8 @@ defmodule Plausible.Site.CacheTest do
|
||||
domain1 = "site1.example.com"
|
||||
domain2 = "site2.example.com"
|
||||
|
||||
site1 = insert(:site, domain: domain1)
|
||||
_site2 = insert(:site, domain: domain2)
|
||||
site1 = new_site(domain: domain1)
|
||||
_site2 = new_site(domain: domain2)
|
||||
|
||||
cache_opts = [cache_name: test, force?: true]
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
defmodule Plausible.Site.GateKeeperTest do
|
||||
use Plausible.DataCase, async: true
|
||||
use Plausible.Teams.Test
|
||||
|
||||
alias Plausible.Site.Cache
|
||||
alias Plausible.Site.GateKeeper
|
||||
@ -18,10 +19,12 @@ defmodule Plausible.Site.GateKeeperTest do
|
||||
domain = "expired.example.com"
|
||||
yesterday = Date.utc_today() |> Date.add(-1)
|
||||
|
||||
owner = new_user(team: [accept_traffic_until: yesterday])
|
||||
|
||||
%{id: _} =
|
||||
add_site_and_refresh_cache(test,
|
||||
domain: domain,
|
||||
members: [build(:user, accept_traffic_until: yesterday)]
|
||||
owner: owner
|
||||
)
|
||||
|
||||
assert {:deny, :payment_required} = GateKeeper.check(domain, opts)
|
||||
@ -88,7 +91,7 @@ defmodule Plausible.Site.GateKeeperTest do
|
||||
{:ok, _} = Plausible.Repo.delete(site)
|
||||
# We need some dummy site, otherwise the cache won't refresh in case the DB
|
||||
# is completely empty
|
||||
insert(:site)
|
||||
new_site()
|
||||
deleted_site_id = site.id
|
||||
|
||||
assert {:allow, %Plausible.Site{id: ^deleted_site_id, from_cache?: true}} =
|
||||
@ -104,7 +107,7 @@ defmodule Plausible.Site.GateKeeperTest do
|
||||
end
|
||||
|
||||
defp add_site_and_refresh_cache(cache_name, site_data) do
|
||||
site = insert(:site, site_data)
|
||||
site = new_site(site_data)
|
||||
|
||||
Cache.refresh_updated_recently(cache_name: cache_name, force?: true)
|
||||
site
|
||||
|
@ -108,25 +108,16 @@ defmodule Plausible.Site.Memberships.AcceptInvitationTest do
|
||||
|
||||
describe "accept_invitation/3 - invitations" do
|
||||
test "converts an invitation into a membership" do
|
||||
inviter = insert(:user)
|
||||
invitee = insert(:user)
|
||||
site = insert(:site, members: [inviter])
|
||||
inviter = new_user()
|
||||
invitee = new_user()
|
||||
site = new_site(owner: inviter)
|
||||
|
||||
invitation =
|
||||
insert(:invitation,
|
||||
site_id: site.id,
|
||||
inviter: inviter,
|
||||
email: invitee.email,
|
||||
role: :admin
|
||||
)
|
||||
invitation = invite_guest(site, invitee, inviter: inviter, role: :editor)
|
||||
|
||||
assert {:ok, membership} =
|
||||
assert {:ok, _} =
|
||||
AcceptInvitation.accept_invitation(invitation.invitation_id, invitee)
|
||||
|
||||
assert membership.site_id == site.id
|
||||
assert membership.user_id == invitee.id
|
||||
assert membership.role == :admin
|
||||
refute Repo.reload(invitation)
|
||||
assert_team_membership(invitee, site.team, :editor)
|
||||
|
||||
assert_email_delivered_with(
|
||||
to: [nil: inviter.email],
|
||||
@ -157,71 +148,26 @@ defmodule Plausible.Site.Memberships.AcceptInvitationTest do
|
||||
assert team_membership.guest_memberships == []
|
||||
end
|
||||
|
||||
@tag :teams
|
||||
test "sync newly converted membership with team" do
|
||||
inviter = insert(:user)
|
||||
invitee = insert(:user)
|
||||
site = insert(:site, members: [inviter])
|
||||
|
||||
invitation =
|
||||
insert(:invitation,
|
||||
site_id: site.id,
|
||||
inviter: inviter,
|
||||
email: invitee.email,
|
||||
role: :admin
|
||||
)
|
||||
|
||||
assert {:ok, membership} =
|
||||
AcceptInvitation.accept_invitation(invitation.invitation_id, invitee)
|
||||
|
||||
assert membership.site_id == site.id
|
||||
assert membership.user_id == invitee.id
|
||||
assert membership.role == :admin
|
||||
|
||||
team = assert_team_exists(inviter)
|
||||
assert_team_attached(site, team.id)
|
||||
|
||||
assert_guest_membership(team, site, invitee, :editor)
|
||||
end
|
||||
|
||||
test "does not degrade role when trying to invite self as an owner" do
|
||||
user = insert(:user)
|
||||
user = new_user()
|
||||
site = new_site(owner: user)
|
||||
|
||||
%{memberships: [membership]} =
|
||||
site = insert(:site, memberships: [build(:site_membership, user: user, role: :owner)])
|
||||
invitation = invite_guest(site, user, inviter: user, role: :editor)
|
||||
|
||||
invitation =
|
||||
insert(:invitation,
|
||||
site_id: site.id,
|
||||
inviter: user,
|
||||
email: user.email,
|
||||
role: :admin
|
||||
)
|
||||
|
||||
assert {:ok, invited_membership} =
|
||||
assert {:ok, _} =
|
||||
AcceptInvitation.accept_invitation(invitation.invitation_id, user)
|
||||
|
||||
assert invited_membership.id == membership.id
|
||||
membership = Repo.reload!(membership)
|
||||
assert membership.role == :owner
|
||||
assert membership.site_id == site.id
|
||||
assert membership.user_id == user.id
|
||||
refute Repo.reload(invitation)
|
||||
assert_team_membership(user, site.team, :owner)
|
||||
end
|
||||
|
||||
test "handles accepting invitation as already a member gracefully" do
|
||||
inviter = insert(:user)
|
||||
invitee = insert(:user)
|
||||
site = insert(:site, members: [inviter])
|
||||
existing_membership = insert(:site_membership, user: invitee, site: site, role: :admin)
|
||||
inviter = new_user()
|
||||
invitee = new_user()
|
||||
site = new_site(owner: inviter)
|
||||
user = add_guest(site, user: invitee, role: :editor)
|
||||
existing_membership = List.first(user.site_memberships)
|
||||
|
||||
invitation =
|
||||
insert(:invitation,
|
||||
site_id: site.id,
|
||||
inviter: inviter,
|
||||
email: invitee.email,
|
||||
role: :viewer
|
||||
)
|
||||
invitation = invite_guest(site, invitee, inviter: inviter, role: :viewer)
|
||||
|
||||
assert {:ok, new_membership} =
|
||||
AcceptInvitation.accept_invitation(invitation.invitation_id, invitee)
|
||||
@ -425,10 +371,10 @@ defmodule Plausible.Site.Memberships.AcceptInvitationTest do
|
||||
generate_usage_for(old_owner_site, 6_000, somewhere_last_month)
|
||||
generate_usage_for(old_owner_site, 10_000, somewhere_penultimate_month)
|
||||
|
||||
invitation = invite_transfer(old_owner_site, new_owner, inviter: old_owner)
|
||||
transfer_id = invite_transfer(old_owner_site, new_owner, inviter: old_owner).invitation_id
|
||||
|
||||
assert {:error, {:over_plan_limits, [:monthly_pageview_limit]}} =
|
||||
AcceptInvitation.accept_invitation(invitation.invitation_id, new_owner)
|
||||
AcceptInvitation.accept_invitation(transfer_id, new_owner)
|
||||
end
|
||||
|
||||
@tag :ee_only
|
||||
|
@ -1,5 +1,6 @@
|
||||
defmodule Plausible.Site.Memberships.RejectInvitationTest do
|
||||
use Plausible
|
||||
use Plausible.Teams.Test
|
||||
use Plausible.DataCase, async: true
|
||||
use Bamboo.Test
|
||||
|
||||
@ -8,17 +9,11 @@ defmodule Plausible.Site.Memberships.RejectInvitationTest do
|
||||
alias Plausible.Site.Memberships.RejectInvitation
|
||||
|
||||
test "rejects invitation and sends email to inviter" do
|
||||
inviter = insert(:user)
|
||||
invitee = insert(:user)
|
||||
site = insert(:site, members: [inviter])
|
||||
inviter = new_user()
|
||||
invitee = new_user()
|
||||
site = new_site(owner: inviter)
|
||||
|
||||
invitation =
|
||||
insert(:invitation,
|
||||
site_id: site.id,
|
||||
inviter: inviter,
|
||||
email: invitee.email,
|
||||
role: :admin
|
||||
)
|
||||
invitation = invite_guest(site, invitee, inviter: inviter, role: :editor)
|
||||
|
||||
assert {:ok, rejected_invitation} =
|
||||
RejectInvitation.reject_invitation(invitation.invitation_id, invitee)
|
||||
|
@ -1,20 +1,16 @@
|
||||
defmodule Plausible.Site.Memberships.RemoveInvitationTest do
|
||||
use Plausible.DataCase, async: true
|
||||
use Plausible.Teams.Test
|
||||
|
||||
alias Plausible.Site.Memberships.RemoveInvitation
|
||||
|
||||
test "removes invitation" do
|
||||
inviter = insert(:user)
|
||||
invitee = insert(:user)
|
||||
site = insert(:site, members: [inviter])
|
||||
inviter = new_user()
|
||||
invitee = new_user()
|
||||
site = new_site(owner: inviter)
|
||||
|
||||
invitation =
|
||||
insert(:invitation,
|
||||
site_id: site.id,
|
||||
inviter: inviter,
|
||||
email: invitee.email,
|
||||
role: :admin
|
||||
)
|
||||
invite_guest(site, invitee, inviter: inviter, role: :editor)
|
||||
|
||||
assert {:ok, removed_invitation} =
|
||||
RemoveInvitation.remove_invitation(invitation.invitation_id, site)
|
||||
|
@ -1,12 +1,13 @@
|
||||
defmodule Plausible.Site.SiteRemovalTest do
|
||||
use Plausible.DataCase, async: true
|
||||
use Oban.Testing, repo: Plausible.Repo
|
||||
use Plausible.Teams.Test
|
||||
|
||||
alias Plausible.Site.Removal
|
||||
alias Plausible.Sites
|
||||
|
||||
test "site from postgres is immediately deleted" do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
assert {:ok, context} = Removal.run(site)
|
||||
assert context.delete_all == {1, nil}
|
||||
refute Sites.get_by_domain(site.domain)
|
||||
@ -14,7 +15,8 @@ defmodule Plausible.Site.SiteRemovalTest do
|
||||
|
||||
@tag :teams
|
||||
test "site deletion prunes team guest memberships" do
|
||||
site = insert(:site) |> Plausible.Teams.load_for_site() |> Repo.preload(:owner)
|
||||
owner = new_user()
|
||||
site = new_site(owner: owner)
|
||||
|
||||
team_membership =
|
||||
insert(:team_membership, user: build(:user), team: site.team, role: :guest)
|
||||
@ -25,7 +27,7 @@ defmodule Plausible.Site.SiteRemovalTest do
|
||||
insert(:team_invitation,
|
||||
email: "sitedeletion@example.test",
|
||||
team: site.team,
|
||||
inviter: site.owner,
|
||||
inviter: owner,
|
||||
role: :guest
|
||||
)
|
||||
|
||||
|
@ -212,6 +212,40 @@ defmodule Plausible.SitesTest do
|
||||
} = Plausible.Teams.Sites.list_with_invitations(user, %{})
|
||||
end
|
||||
|
||||
test "prioritizes pending transfer over pinned site with guest membership" do
|
||||
owner = new_user()
|
||||
pending_owner = new_user()
|
||||
site = new_site(owner: owner, domain: "one.example.com")
|
||||
add_guest(site, user: pending_owner, role: :editor)
|
||||
|
||||
invite_transfer(site, pending_owner, inviter: owner)
|
||||
|
||||
{:ok, _} = Sites.toggle_pin(pending_owner, site)
|
||||
|
||||
assert %{
|
||||
entries: [
|
||||
%{domain: "one.example.com", entry_type: "invitation"}
|
||||
]
|
||||
} =
|
||||
Sites.list_with_invitations(pending_owner, %{})
|
||||
end
|
||||
|
||||
test "prioritizes pending transfer over site with guest membership" do
|
||||
owner = new_user()
|
||||
pending_owner = new_user()
|
||||
site = new_site(owner: owner, domain: "one.example.com")
|
||||
add_guest(site, user: pending_owner, role: :editor)
|
||||
|
||||
invite_transfer(site, pending_owner, inviter: owner)
|
||||
|
||||
assert %{
|
||||
entries: [
|
||||
%{domain: "one.example.com", entry_type: "invitation"}
|
||||
]
|
||||
} =
|
||||
Sites.list_with_invitations(pending_owner, %{})
|
||||
end
|
||||
|
||||
test "pinned site doesn't matter with membership revoked (no active invitations)" do
|
||||
user1 = new_user(email: "user1@example.com")
|
||||
_user2 = new_user(email: "user2@example.com")
|
||||
@ -570,6 +604,20 @@ defmodule Plausible.SitesTest do
|
||||
assert prefs.pinned_at
|
||||
end
|
||||
|
||||
test "handles multiple guest memberships with same team properly (regression)" do
|
||||
user = new_user()
|
||||
owner = new_user()
|
||||
site1 = new_site(owner: owner)
|
||||
site2 = new_site(owner: owner)
|
||||
add_guest(site1, user: user, role: :viewer)
|
||||
add_guest(site2, user: user, role: :viewer)
|
||||
|
||||
assert {:ok, prefs} = Sites.toggle_pin(user, site1)
|
||||
assert prefs.site_id == site1.id
|
||||
assert prefs.user_id == user.id
|
||||
assert prefs.pinned_at
|
||||
end
|
||||
|
||||
test "returns error when pins limit hit" do
|
||||
user = new_user()
|
||||
|
||||
|
@ -1545,15 +1545,8 @@ defmodule Plausible.Stats.Filters.QueryParserTest do
|
||||
@describetag :ee_only
|
||||
|
||||
setup %{user: user} do
|
||||
plan =
|
||||
insert(:enterprise_plan,
|
||||
features: [Plausible.Billing.Feature.RevenueGoals],
|
||||
user_id: user.id
|
||||
)
|
||||
|
||||
subscription = insert(:subscription, user: user, paddle_plan_id: plan.paddle_plan_id)
|
||||
|
||||
{:ok, subscription: subscription}
|
||||
subscribe_to_enterprise_plan(user, features: [Plausible.Billing.Feature.RevenueGoals])
|
||||
:ok
|
||||
end
|
||||
|
||||
test "not valid in public schema", %{site: site} do
|
||||
@ -1590,8 +1583,9 @@ defmodule Plausible.Stats.Filters.QueryParserTest do
|
||||
)
|
||||
end
|
||||
|
||||
test "no access", %{site: site, user: user, subscription: subscription} do
|
||||
Repo.delete!(subscription)
|
||||
test "no access" do
|
||||
user = new_user()
|
||||
site = new_site(owner: user)
|
||||
|
||||
subscribe_to_enterprise_plan(user, features: [Plausible.Billing.Feature.StatsAPI])
|
||||
|
||||
|
@ -1,13 +1,14 @@
|
||||
defmodule Plausible.Stats.QueryResultTest do
|
||||
use Plausible.DataCase, async: true
|
||||
use Plausible.Teams.Test
|
||||
alias Plausible.Stats.{Query, QueryResult, QueryOptimizer}
|
||||
|
||||
setup do
|
||||
user = insert(:user)
|
||||
|
||||
site =
|
||||
insert(:site,
|
||||
members: [user],
|
||||
new_site(
|
||||
owner: user,
|
||||
inserted_at: ~N[2020-01-01T00:00:00],
|
||||
stats_start_date: ~D[2020-01-01]
|
||||
)
|
||||
@ -15,9 +16,7 @@ defmodule Plausible.Stats.QueryResultTest do
|
||||
{:ok, site: site}
|
||||
end
|
||||
|
||||
test "serializing query to JSON keeps keys ordered" do
|
||||
site = insert(:site)
|
||||
|
||||
test "serializing query to JSON keeps keys ordered", %{site: site} do
|
||||
{:ok, query} =
|
||||
Query.build(
|
||||
site,
|
||||
|
@ -10,17 +10,20 @@ defmodule PlausibleWeb.Components.Billing.NoticeTest do
|
||||
assert render_component(&Notice.premium_feature/1,
|
||||
billable_user: me,
|
||||
current_user: me,
|
||||
current_team: team_of(me),
|
||||
feature_mod: Plausible.Billing.Feature.Props
|
||||
) == ""
|
||||
end
|
||||
|
||||
test "premium_feature/1 renders an upgrade link when user is the site owner and does not have access to the feature" do
|
||||
me = new_user() |> subscribe_to_growth_plan()
|
||||
team = team_of(me)
|
||||
|
||||
rendered =
|
||||
render_component(&Notice.premium_feature/1,
|
||||
billable_user: me,
|
||||
current_user: me,
|
||||
current_team: team,
|
||||
feature_mod: Plausible.Billing.Feature.Props
|
||||
)
|
||||
|
||||
@ -37,6 +40,7 @@ defmodule PlausibleWeb.Components.Billing.NoticeTest do
|
||||
render_component(&Notice.premium_feature/1,
|
||||
billable_user: owner,
|
||||
current_user: me,
|
||||
current_team: team_of(me),
|
||||
feature_mod: Plausible.Billing.Feature.Funnels
|
||||
)
|
||||
|
||||
@ -51,6 +55,7 @@ defmodule PlausibleWeb.Components.Billing.NoticeTest do
|
||||
render_component(&Notice.premium_feature/1,
|
||||
billable_user: me,
|
||||
current_user: me,
|
||||
current_team: team_of(me),
|
||||
feature_mod: Plausible.Billing.Feature.Funnels
|
||||
)
|
||||
|
||||
@ -59,11 +64,13 @@ defmodule PlausibleWeb.Components.Billing.NoticeTest do
|
||||
|
||||
test "limit_exceeded/1 when billable user is on growth displays upgrade link" do
|
||||
me = new_user() |> subscribe_to_growth_plan()
|
||||
team = team_of(me)
|
||||
|
||||
rendered =
|
||||
render_component(&Notice.limit_exceeded/1,
|
||||
billable_user: me,
|
||||
current_user: me,
|
||||
current_team: team,
|
||||
limit: 10,
|
||||
resource: "users"
|
||||
)
|
||||
@ -80,6 +87,7 @@ defmodule PlausibleWeb.Components.Billing.NoticeTest do
|
||||
render_component(&Notice.limit_exceeded/1,
|
||||
billable_user: me,
|
||||
current_user: insert(:user),
|
||||
current_team: team_of(me),
|
||||
limit: 10,
|
||||
resource: "users"
|
||||
)
|
||||
@ -96,6 +104,7 @@ defmodule PlausibleWeb.Components.Billing.NoticeTest do
|
||||
render_component(&Notice.limit_exceeded/1,
|
||||
billable_user: me,
|
||||
current_user: me,
|
||||
current_team: team_of(me),
|
||||
limit: 10,
|
||||
resource: "users"
|
||||
)
|
||||
@ -113,6 +122,7 @@ defmodule PlausibleWeb.Components.Billing.NoticeTest do
|
||||
render_component(&Notice.limit_exceeded/1,
|
||||
billable_user: me,
|
||||
current_user: me,
|
||||
current_team: team_of(me),
|
||||
limit: 10,
|
||||
resource: "users"
|
||||
)
|
||||
@ -126,11 +136,13 @@ defmodule PlausibleWeb.Components.Billing.NoticeTest do
|
||||
@tag :ee_only
|
||||
test "limit_exceeded/1 when billable user is on a business plan displays support email" do
|
||||
me = new_user() |> subscribe_to_business_plan()
|
||||
team = team_of(me)
|
||||
|
||||
rendered =
|
||||
render_component(&Notice.limit_exceeded/1,
|
||||
billable_user: me,
|
||||
current_user: me,
|
||||
current_team: team,
|
||||
limit: 10,
|
||||
resource: "users"
|
||||
)
|
||||
|
@ -1,5 +1,6 @@
|
||||
defmodule PlausibleWeb.AdminControllerTest do
|
||||
use PlausibleWeb.ConnCase, async: false
|
||||
use Plausible.Teams.Test
|
||||
|
||||
alias Plausible.Repo
|
||||
|
||||
@ -37,12 +38,12 @@ defmodule PlausibleWeb.AdminControllerTest do
|
||||
} do
|
||||
patch_env(:super_admin_user_ids, [user.id])
|
||||
|
||||
s1 = insert(:site, inserted_at: ~N[2024-01-01 00:00:00])
|
||||
insert_list(3, :site_membership, site: s1)
|
||||
s2 = insert(:site, inserted_at: ~N[2024-01-02 00:00:00])
|
||||
insert_list(3, :site_membership, site: s2)
|
||||
s3 = insert(:site, inserted_at: ~N[2024-01-03 00:00:00])
|
||||
insert_list(3, :site_membership, site: s3)
|
||||
s1 = new_site(inserted_at: ~N[2024-01-01 00:00:00])
|
||||
for _ <- 1..3, do: add_guest(s1, role: :viewer)
|
||||
s2 = new_site(inserted_at: ~N[2024-01-02 00:00:00])
|
||||
for _ <- 1..3, do: add_guest(s2, role: :viewer)
|
||||
s3 = new_site(inserted_at: ~N[2024-01-03 00:00:00])
|
||||
for _ <- 1..3, do: add_guest(s3, role: :viewer)
|
||||
|
||||
conn1 = get(conn, "/crm/sites/site", %{"limit" => "2"})
|
||||
page1_html = html_response(conn1, 200)
|
||||
@ -128,7 +129,7 @@ defmodule PlausibleWeb.AdminControllerTest do
|
||||
} do
|
||||
patch_env(:super_admin_user_ids, [user.id])
|
||||
|
||||
insert(:subscription, user: user)
|
||||
subscribe_to_plan(user, "does-not-exist")
|
||||
|
||||
conn = get(conn, "/crm/billing/user/#{user.id}/current_plan")
|
||||
assert json_response(conn, 200) == %{"features" => []}
|
||||
@ -138,7 +139,7 @@ defmodule PlausibleWeb.AdminControllerTest do
|
||||
test "returns plan data for user with subscription", %{conn: conn, user: user} do
|
||||
patch_env(:super_admin_user_ids, [user.id])
|
||||
|
||||
insert(:subscription, user: user, paddle_plan_id: "857104")
|
||||
subscribe_to_plan(user, "857104")
|
||||
|
||||
conn = get(conn, "/crm/billing/user/#{user.id}/current_plan")
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
defmodule PlausibleWeb.Api.ExternalControllerTest do
|
||||
use PlausibleWeb.ConnCase
|
||||
use Plausible.ClickhouseRepo
|
||||
use Plausible.Teams.Test
|
||||
|
||||
@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"
|
||||
@user_agent_mobile "Mozilla/5.0 (Linux; Android 6.0; U007 Pro Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/44.0.2403.119 Mobile Safari/537.36"
|
||||
@ -8,7 +9,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
|
||||
|
||||
describe "POST /api/event" do
|
||||
setup do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
{:ok, site: site}
|
||||
end
|
||||
|
||||
@ -72,7 +73,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
|
||||
conn: conn,
|
||||
site: site1
|
||||
} do
|
||||
site2 = insert(:site)
|
||||
site2 = new_site()
|
||||
|
||||
params = %{
|
||||
name: "pageview",
|
||||
@ -302,7 +303,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
|
||||
test "blocks traffic from a domain when it's blocked", %{
|
||||
conn: conn
|
||||
} do
|
||||
site = insert(:site, ingest_rate_limit_threshold: 0)
|
||||
site = new_site(ingest_rate_limit_threshold: 0)
|
||||
|
||||
params = %{
|
||||
domain: site.domain,
|
||||
@ -1255,7 +1256,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
|
||||
|
||||
describe "scroll depth tests" do
|
||||
setup do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
{:ok, site: site}
|
||||
end
|
||||
|
||||
@ -1313,7 +1314,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
|
||||
|
||||
describe "acquisition channel tests" do
|
||||
setup do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
{:ok, site: site}
|
||||
end
|
||||
|
||||
@ -2113,7 +2114,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
|
||||
|
||||
describe "custom source parsing rules" do
|
||||
setup do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
{:ok, site: site}
|
||||
end
|
||||
|
||||
@ -2991,7 +2992,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
|
||||
|
||||
describe "custom channel parsing rules" do
|
||||
setup do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
{:ok, site: site}
|
||||
end
|
||||
|
||||
@ -3317,7 +3318,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
|
||||
|
||||
describe "user_id generation" do
|
||||
setup do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
{:ok, site: site}
|
||||
end
|
||||
|
||||
@ -3391,7 +3392,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
|
||||
end
|
||||
|
||||
test "different domain value results in different user ID", %{conn: conn, site: site1} do
|
||||
site2 = insert(:site)
|
||||
site2 = new_site()
|
||||
|
||||
params = %{
|
||||
url: "https://user-id-test-domain.com/",
|
||||
@ -3465,7 +3466,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
|
||||
|
||||
describe "remaining" do
|
||||
setup do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
{:ok, site: site}
|
||||
end
|
||||
|
||||
|
@ -47,8 +47,7 @@ defmodule PlausibleWeb.Api.ExternalStatsController.AuthTest do
|
||||
end
|
||||
|
||||
test "locked site - returns 402", %{conn: conn, api_key: api_key, user: user} do
|
||||
site = insert(:site, members: [user])
|
||||
{:ok, 1} = Plausible.Billing.SiteLocker.set_lock_status_for(user, true)
|
||||
site = new_site(owner: user, locked: true)
|
||||
|
||||
conn
|
||||
|> with_api_key(api_key)
|
||||
@ -57,7 +56,7 @@ defmodule PlausibleWeb.Api.ExternalStatsController.AuthTest do
|
||||
end
|
||||
|
||||
test "can access with correct API key and site ID", %{conn: conn, user: user, api_key: api_key} do
|
||||
site = insert(:site, members: [user])
|
||||
site = new_site(owner: user)
|
||||
|
||||
conn
|
||||
|> with_api_key(api_key)
|
||||
@ -74,7 +73,7 @@ defmodule PlausibleWeb.Api.ExternalStatsController.AuthTest do
|
||||
end
|
||||
|
||||
test "can access as a super admin", %{conn: conn, api_key: api_key} do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
|
||||
conn
|
||||
|> with_api_key(api_key)
|
||||
@ -89,8 +88,7 @@ defmodule PlausibleWeb.Api.ExternalStatsController.AuthTest do
|
||||
api_key: api_key,
|
||||
user: user
|
||||
} do
|
||||
site = insert(:site, members: [user])
|
||||
{:ok, 1} = Plausible.Billing.SiteLocker.set_lock_status_for(user, true)
|
||||
site = new_site(owner: user, locked: true)
|
||||
|
||||
conn
|
||||
|> with_api_key(api_key)
|
||||
@ -132,7 +130,7 @@ defmodule PlausibleWeb.Api.ExternalStatsController.AuthTest do
|
||||
} do
|
||||
old_domain = "old.example.com"
|
||||
new_domain = "new.example.com"
|
||||
site = insert(:site, domain: old_domain, members: [user])
|
||||
site = new_site(domain: old_domain, owner: user)
|
||||
|
||||
Plausible.Site.Domain.change(site, new_domain)
|
||||
|
||||
|
@ -65,8 +65,7 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
|
||||
user: user,
|
||||
site: site
|
||||
} do
|
||||
ep = insert(:enterprise_plan, features: [Feature.StatsAPI], user_id: user.id)
|
||||
insert(:subscription, user: user, paddle_plan_id: ep.paddle_plan_id)
|
||||
subscribe_to_enterprise_plan(user, features: [Feature.StatsAPI])
|
||||
|
||||
conn =
|
||||
get(conn, "/api/v1/stats/breakdown", %{
|
||||
|
@ -1,5 +1,6 @@
|
||||
defmodule PlausibleWeb.Api.ExternalStatsController.QueryTest do
|
||||
use PlausibleWeb.ConnCase
|
||||
use Plausible.Teams.Test
|
||||
|
||||
@user_id Enum.random(1000..9999)
|
||||
|
||||
@ -1381,7 +1382,7 @@ defmodule PlausibleWeb.Api.ExternalStatsController.QueryTest do
|
||||
|
||||
test "timeseries with quarter-hour timezone", %{conn: conn, user: user} do
|
||||
# GMT+05:45
|
||||
site = insert(:site, timezone: "Asia/Katmandu", members: [user])
|
||||
site = new_site(timezone: "Asia/Katmandu", owner: user)
|
||||
|
||||
populate_stats(site, [
|
||||
build(:pageview, timestamp: ~N[2021-01-02 05:00:00]),
|
||||
|
@ -1,4 +1,5 @@
|
||||
defmodule PlausibleWeb.Api.StatsController.AuthorizationTest do
|
||||
use Plausible.Teams.Test
|
||||
use PlausibleWeb.ConnCase
|
||||
|
||||
describe "API authorization - as anonymous user" do
|
||||
@ -37,21 +38,21 @@ defmodule PlausibleWeb.Api.StatsController.AuthorizationTest do
|
||||
end
|
||||
|
||||
test "Sends 404 Not found when user does not have access to site", %{conn: conn} do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
conn = get(conn, "/api/stats/#{site.domain}/main-graph")
|
||||
|
||||
assert conn.status == 404
|
||||
end
|
||||
|
||||
test "returns stats for public site", %{conn: conn} do
|
||||
site = insert(:site, public: true)
|
||||
site = new_site(public: true)
|
||||
conn = get(conn, "/api/stats/#{site.domain}/main-graph")
|
||||
|
||||
assert %{"plot" => _any} = json_response(conn, 200)
|
||||
end
|
||||
|
||||
test "returns stats for a private site that the user owns", %{conn: conn, user: user} do
|
||||
site = insert(:site, public: false, members: [user])
|
||||
site = new_site(public: false, owner: user)
|
||||
conn = get(conn, "/api/stats/#{site.domain}/main-graph")
|
||||
|
||||
assert %{"plot" => _any} = json_response(conn, 200)
|
||||
|
@ -99,7 +99,7 @@ defmodule PlausibleWeb.Api.StatsController.FunnelsTest do
|
||||
end
|
||||
|
||||
test "computes all-time funnel with filters", %{conn: conn, user: user} do
|
||||
site = insert(:site, stats_start_date: ~D[2020-01-01], members: [user])
|
||||
site = new_site(stats_start_date: ~D[2020-01-01], owner: user)
|
||||
{:ok, funnel} = setup_funnel(site, @build_funnel_with)
|
||||
|
||||
populate_stats(site, [
|
||||
|
@ -1,5 +1,6 @@
|
||||
defmodule PlausibleWeb.Api.StatsController.MainGraphTest do
|
||||
use PlausibleWeb.ConnCase
|
||||
use Plausible.Teams.Test
|
||||
|
||||
@user_id Enum.random(1000..9999)
|
||||
|
||||
@ -102,9 +103,9 @@ defmodule PlausibleWeb.Api.StatsController.MainGraphTest do
|
||||
test "displays hourly stats in configured timezone", %{conn: conn, user: user} do
|
||||
# UTC+1
|
||||
site =
|
||||
insert(:site,
|
||||
new_site(
|
||||
domain: "tz-test.com",
|
||||
members: [user],
|
||||
owner: user,
|
||||
timezone: "CET"
|
||||
)
|
||||
|
||||
@ -1273,7 +1274,7 @@ defmodule PlausibleWeb.Api.StatsController.MainGraphTest do
|
||||
end
|
||||
|
||||
test "bugfix: don't crash when timezone gap occurs", %{conn: conn, user: user} do
|
||||
site = insert(:site, members: [user], timezone: "America/Santiago")
|
||||
site = new_site(owner: user, timezone: "America/Santiago")
|
||||
|
||||
populate_stats(site, [
|
||||
build(:pageview, timestamp: relative_time(minutes: -5))
|
||||
|
@ -1,4 +1,5 @@
|
||||
defmodule PlausibleWeb.Api.StatsController.RegionsTest do
|
||||
use Plausible.Teams.Test
|
||||
use PlausibleWeb.ConnCase
|
||||
|
||||
describe "GET /api/stats/:domain/regions" do
|
||||
@ -99,7 +100,7 @@ defmodule PlausibleWeb.Api.StatsController.RegionsTest do
|
||||
# Given it's 28th Nov and there's 30 day range, the starting day falls on 29th Oct
|
||||
# which coincides with daylight savings time change there:
|
||||
# https://www.timeanddate.com/time/change/portugal/ponta-delgada-azores.
|
||||
site = insert(:site, members: [user], timezone: "Atlantic/Azores")
|
||||
site = new_site(owner: user, timezone: "Atlantic/Azores")
|
||||
|
||||
populate_stats(site, [
|
||||
build(:pageview, timestamp: relative_time(minutes: -5))
|
||||
|
@ -1,6 +1,7 @@
|
||||
defmodule PlausibleWeb.AuthControllerTest do
|
||||
use PlausibleWeb.ConnCase, async: true
|
||||
use Bamboo.Test
|
||||
use Plausible.Teams.Test
|
||||
use Plausible.Repo
|
||||
|
||||
import Plausible.Test.Support.HTML
|
||||
@ -582,14 +583,9 @@ defmodule PlausibleWeb.AuthControllerTest do
|
||||
])
|
||||
|
||||
insert(:google_auth, site: site, user: user)
|
||||
insert(:subscription, user: user, status: Subscription.Status.deleted())
|
||||
insert(:subscription, user: user, status: Subscription.Status.active())
|
||||
|
||||
insert(:enterprise_plan,
|
||||
user: user,
|
||||
paddle_plan_id: "whatever",
|
||||
site_limit: 1
|
||||
)
|
||||
subscribe_to_growth_plan(user, status: Subscription.Status.deleted())
|
||||
subscribe_to_growth_plan(user, status: Subscription.Status.active())
|
||||
subscribe_to_enterprise_plan(user, site_limit: 1, subscription?: false)
|
||||
|
||||
{:ok, _team} = Plausible.Teams.get_or_create(user)
|
||||
|
||||
@ -598,6 +594,8 @@ defmodule PlausibleWeb.AuthControllerTest do
|
||||
assert Repo.reload(site) == nil
|
||||
assert Repo.reload(user) == nil
|
||||
assert Repo.all(Plausible.Billing.Subscription) == []
|
||||
assert Repo.all(Plausible.Billing.EnterprisePlan) == []
|
||||
assert Repo.all(Plausible.Site.Membership) == []
|
||||
assert Repo.all(Plausible.Teams.Team) == []
|
||||
end
|
||||
|
||||
|
@ -43,6 +43,7 @@ defmodule PlausibleWeb.BillingControllerTest do
|
||||
user: user
|
||||
} do
|
||||
subscribe_to_plan(user, "123123")
|
||||
team = team_of(user)
|
||||
|
||||
for _ <- 1..11, do: new_site(owner: user)
|
||||
|
||||
@ -50,7 +51,7 @@ defmodule PlausibleWeb.BillingControllerTest do
|
||||
|
||||
conn = post(conn, Routes.billing_path(conn, :change_plan, @v4_growth_plan))
|
||||
|
||||
subscription = Plausible.Repo.get_by(Plausible.Billing.Subscription, user_id: user.id)
|
||||
subscription = Plausible.Repo.get_by(Plausible.Billing.Subscription, team_id: team.id)
|
||||
|
||||
assert Phoenix.Flash.get(conn.assigns.flash, :error) =~ "are exceeded: site limit"
|
||||
assert subscription.paddle_plan_id == "123123"
|
||||
@ -61,6 +62,7 @@ defmodule PlausibleWeb.BillingControllerTest do
|
||||
user: user
|
||||
} do
|
||||
subscribe_to_plan(user, "123123")
|
||||
team = team_of(user)
|
||||
site = new_site(owner: user)
|
||||
now = NaiveDateTime.utc_now()
|
||||
|
||||
@ -69,7 +71,7 @@ defmodule PlausibleWeb.BillingControllerTest do
|
||||
|
||||
conn1 = post(conn, Routes.billing_path(conn, :change_plan, @v4_growth_plan))
|
||||
|
||||
subscription = Plausible.Repo.get_by(Plausible.Billing.Subscription, user_id: user.id)
|
||||
subscription = Plausible.Repo.get_by(Plausible.Billing.Subscription, team_id: team.id)
|
||||
|
||||
assert Phoenix.Flash.get(conn1.assigns.flash, :error) =~
|
||||
"are exceeded: monthly pageview limit"
|
||||
@ -88,10 +90,11 @@ defmodule PlausibleWeb.BillingControllerTest do
|
||||
|
||||
test "calls Paddle API to update subscription", %{conn: conn, user: user} do
|
||||
subscribe_to_plan(user, "321321")
|
||||
team = team_of(user)
|
||||
|
||||
post(conn, Routes.billing_path(conn, :change_plan, "123123"))
|
||||
|
||||
subscription = Plausible.Repo.get_by(Plausible.Billing.Subscription, user_id: user.id)
|
||||
subscription = Plausible.Repo.get_by(Plausible.Billing.Subscription, team_id: team.id)
|
||||
assert subscription.paddle_plan_id == "123123"
|
||||
assert subscription.next_bill_date == ~D[2019-07-10]
|
||||
assert subscription.next_bill_amount == "6.00"
|
||||
|
@ -8,15 +8,11 @@ defmodule PlausibleWeb.Site.InvitationControllerTest do
|
||||
|
||||
describe "POST /sites/invitations/:invitation_id/accept" do
|
||||
test "converts the invitation into a membership", %{conn: conn, user: user} do
|
||||
site = insert(:site)
|
||||
owner = new_user()
|
||||
site = new_site(owner: owner)
|
||||
|
||||
invitation =
|
||||
insert(:invitation,
|
||||
site_id: site.id,
|
||||
inviter: build(:user),
|
||||
email: user.email,
|
||||
role: :admin
|
||||
)
|
||||
invite_guest(site, user.email, inviter: owner, role: :editor)
|
||||
|
||||
conn = post(conn, "/sites/invitations/#{invitation.invitation_id}/accept")
|
||||
|
||||
@ -31,7 +27,7 @@ defmodule PlausibleWeb.Site.InvitationControllerTest do
|
||||
assert membership.role == :admin
|
||||
end
|
||||
|
||||
@tag :team
|
||||
@tag :teams
|
||||
test "multiple invites per same team sync regression", %{conn: conn, user: user} do
|
||||
inviter = insert(:user)
|
||||
{:ok, team} = Plausible.Teams.get_or_create(inviter)
|
||||
@ -82,7 +78,7 @@ defmodule PlausibleWeb.Site.InvitationControllerTest do
|
||||
end
|
||||
|
||||
test "does not crash if clicked for the 2nd time in another tab", %{conn: conn, user: user} do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
|
||||
invitation =
|
||||
insert(:invitation,
|
||||
@ -168,15 +164,10 @@ defmodule PlausibleWeb.Site.InvitationControllerTest do
|
||||
|
||||
describe "POST /sites/invitations/:invitation_id/reject" do
|
||||
test "rejects the invitation", %{conn: conn, user: user} do
|
||||
site = insert(:site)
|
||||
owner = new_user()
|
||||
site = new_site(owner: owner)
|
||||
|
||||
invitation =
|
||||
insert(:invitation,
|
||||
site_id: site.id,
|
||||
inviter: build(:user),
|
||||
email: user.email,
|
||||
role: :admin
|
||||
)
|
||||
invitation = invite_guest(site, user.email, inviter: owner, role: :editor)
|
||||
|
||||
conn = post(conn, "/sites/invitations/#{invitation.invitation_id}/reject")
|
||||
|
||||
@ -197,19 +188,10 @@ defmodule PlausibleWeb.Site.InvitationControllerTest do
|
||||
|
||||
describe "DELETE /sites/:domain/invitations/:invitation_id" do
|
||||
test "removes the invitation", %{conn: conn, user: user} do
|
||||
site =
|
||||
insert(:site,
|
||||
members: [build(:user)],
|
||||
memberships: [build(:site_membership, user: user, role: :admin)]
|
||||
)
|
||||
|
||||
invitation =
|
||||
insert(:invitation,
|
||||
site_id: site.id,
|
||||
inviter: build(:user),
|
||||
email: "jane@example.com",
|
||||
role: :admin
|
||||
)
|
||||
owner = new_user()
|
||||
site = new_site(owner: owner)
|
||||
add_guest(site, user: user, role: :editor)
|
||||
invitation = invite_guest(site, "jane@example.com", inviter: owner, role: :editor)
|
||||
|
||||
conn =
|
||||
delete(
|
||||
@ -223,19 +205,10 @@ defmodule PlausibleWeb.Site.InvitationControllerTest do
|
||||
end
|
||||
|
||||
test "removes the invitation for ownership transfer", %{conn: conn, user: user} do
|
||||
site =
|
||||
insert(:site,
|
||||
members: [build(:user)],
|
||||
memberships: [build(:site_membership, user: user, role: :admin)]
|
||||
)
|
||||
|
||||
invitation =
|
||||
insert(:invitation,
|
||||
site_id: site.id,
|
||||
inviter: build(:user),
|
||||
email: "jane@example.com",
|
||||
role: :owner
|
||||
)
|
||||
owner = new_user()
|
||||
site = new_site(owner: owner)
|
||||
add_guest(site, user: user, role: :editor)
|
||||
invitation = invite_transfer(site, "jane@example.com", inviter: owner)
|
||||
|
||||
conn =
|
||||
delete(
|
||||
@ -249,15 +222,11 @@ defmodule PlausibleWeb.Site.InvitationControllerTest do
|
||||
end
|
||||
|
||||
test "fails to remove an invitation with insufficient permission", %{conn: conn, user: user} do
|
||||
site = insert(:site, memberships: [build(:site_membership, user: user, role: :viewer)])
|
||||
owner = new_user()
|
||||
site = new_site(owner: owner)
|
||||
add_guest(site, user: user, role: :viewer)
|
||||
|
||||
invitation =
|
||||
insert(:invitation,
|
||||
site_id: site.id,
|
||||
inviter: build(:user),
|
||||
email: "jane@example.com",
|
||||
role: :admin
|
||||
)
|
||||
invitation = invite_guest(site, "jane@example.com", inviter: owner, role: :editor)
|
||||
|
||||
delete(
|
||||
conn,
|
||||
@ -268,20 +237,14 @@ defmodule PlausibleWeb.Site.InvitationControllerTest do
|
||||
end
|
||||
|
||||
test "fails to remove an invitation from the outside", %{conn: my_conn, user: me} do
|
||||
_my_site = insert(:site, memberships: [build(:site_membership, user: me, role: "owner")])
|
||||
new_site(owner: me)
|
||||
|
||||
other_user = insert(:user)
|
||||
other_user = new_user()
|
||||
|
||||
other_site =
|
||||
insert(:site, memberships: [build(:site_membership, user: other_user, role: "owner")])
|
||||
other_site = new_site(owner: other_user)
|
||||
|
||||
invitation =
|
||||
insert(:invitation,
|
||||
site_id: other_site.id,
|
||||
inviter: other_user,
|
||||
email: "jane@example.com",
|
||||
role: :admin
|
||||
)
|
||||
invite_guest(other_site, "jane@example.com", role: :editor, inviter: other_user)
|
||||
|
||||
remove_invitation_path =
|
||||
Routes.invitation_path(
|
||||
@ -297,7 +260,8 @@ defmodule PlausibleWeb.Site.InvitationControllerTest do
|
||||
end
|
||||
|
||||
test "renders error for non-existent invitation", %{conn: conn, user: user} do
|
||||
site = insert(:site, memberships: [build(:site_membership, user: user, role: :admin)])
|
||||
site = new_site()
|
||||
add_guest(site, user: user, role: :editor)
|
||||
|
||||
remove_invitation_path =
|
||||
Routes.invitation_path(
|
||||
|
@ -48,7 +48,6 @@ defmodule PlausibleWeb.SettingsControllerTest do
|
||||
|
||||
@tag :ee_only
|
||||
test "shows enterprise plan subscription", %{conn: conn, user: user} do
|
||||
subscribe_to_plan(user, "123")
|
||||
configure_enterprise_plan(user)
|
||||
|
||||
conn = get(conn, Routes.settings_path(conn, :subscription))
|
||||
@ -117,13 +116,7 @@ defmodule PlausibleWeb.SettingsControllerTest do
|
||||
conn: conn,
|
||||
user: user
|
||||
} do
|
||||
configure_enterprise_plan(user)
|
||||
|
||||
insert(:subscription,
|
||||
user: user,
|
||||
status: Subscription.Status.past_due(),
|
||||
paddle_plan_id: @configured_enterprise_plan_paddle_plan_id
|
||||
)
|
||||
configure_enterprise_plan(user, subscription: [status: Subscription.Status.past_due()])
|
||||
|
||||
doc =
|
||||
conn
|
||||
@ -137,13 +130,7 @@ defmodule PlausibleWeb.SettingsControllerTest do
|
||||
conn: conn,
|
||||
user: user
|
||||
} do
|
||||
configure_enterprise_plan(user)
|
||||
|
||||
insert(:subscription,
|
||||
user: user,
|
||||
status: Subscription.Status.paused(),
|
||||
paddle_plan_id: @configured_enterprise_plan_paddle_plan_id
|
||||
)
|
||||
configure_enterprise_plan(user, subscription: [status: Subscription.Status.paused()])
|
||||
|
||||
doc =
|
||||
conn
|
||||
@ -185,8 +172,6 @@ defmodule PlausibleWeb.SettingsControllerTest do
|
||||
@tag :ee_only
|
||||
test "links to '/billing/choose-plan' with the text 'Change plan' for a configured enterprise plan with an existing subscription + renders cancel button",
|
||||
%{conn: conn, user: user} do
|
||||
insert(:subscription, paddle_plan_id: @v3_plan_id, user: user)
|
||||
|
||||
configure_enterprise_plan(user)
|
||||
|
||||
doc =
|
||||
@ -207,9 +192,9 @@ defmodule PlausibleWeb.SettingsControllerTest do
|
||||
|
||||
@tag :ee_only
|
||||
test "renders cancelled subscription notice", %{conn: conn, user: user} do
|
||||
insert(:subscription,
|
||||
paddle_plan_id: @v4_plan_id,
|
||||
user: user,
|
||||
subscribe_to_plan(
|
||||
user,
|
||||
@v4_plan_id,
|
||||
status: :deleted,
|
||||
next_bill_date: ~D[2023-01-01]
|
||||
)
|
||||
@ -229,11 +214,9 @@ defmodule PlausibleWeb.SettingsControllerTest do
|
||||
conn: conn,
|
||||
user: user
|
||||
} do
|
||||
insert(:subscription,
|
||||
paddle_plan_id: @v4_plan_id,
|
||||
user: user,
|
||||
subscribe_to_plan(user, @v4_plan_id,
|
||||
status: :deleted,
|
||||
next_bill_date: Timex.shift(Timex.today(), days: 10)
|
||||
next_bill_date: Date.shift(Date.utc_today(), day: 10)
|
||||
)
|
||||
|
||||
notice_text =
|
||||
@ -252,11 +235,11 @@ defmodule PlausibleWeb.SettingsControllerTest do
|
||||
conn: conn,
|
||||
user: user
|
||||
} do
|
||||
insert(:subscription,
|
||||
paddle_plan_id: @v3_plan_id,
|
||||
user: user,
|
||||
subscribe_to_plan(
|
||||
user,
|
||||
@v3_plan_id,
|
||||
status: :deleted,
|
||||
next_bill_date: Timex.shift(Timex.today(), days: 10)
|
||||
next_bill_date: Date.shift(Date.utc_today(), day: 10)
|
||||
)
|
||||
|
||||
notice_text =
|
||||
@ -353,11 +336,16 @@ defmodule PlausibleWeb.SettingsControllerTest do
|
||||
assert element_exists?(doc, "#total_pageviews_penultimate_cycle")
|
||||
end
|
||||
|
||||
subscribe_to_plan(user, @v4_plan_id,
|
||||
status: :active,
|
||||
last_bill_date: Timex.shift(Timex.now(), months: -6)
|
||||
)
|
||||
|
||||
subscription =
|
||||
subscribe_to_plan(user, @v4_plan_id,
|
||||
status: :active,
|
||||
last_bill_date: Timex.shift(Timex.now(), months: -6)
|
||||
).subscription
|
||||
user
|
||||
|> team_of()
|
||||
|> Plausible.Teams.with_subscription()
|
||||
|> Map.fetch!(:subscription)
|
||||
|
||||
get(conn, Routes.settings_path(conn, :subscription))
|
||||
|> html_response(200)
|
||||
@ -458,12 +446,17 @@ defmodule PlausibleWeb.SettingsControllerTest do
|
||||
|> html_response(200)
|
||||
|> assert_usage.()
|
||||
|
||||
subscribe_to_plan(user, @v4_plan_id,
|
||||
status: :deleted,
|
||||
last_bill_date: ~D[2022-01-01],
|
||||
next_bill_date: ~D[2022-02-01]
|
||||
)
|
||||
|
||||
subscription =
|
||||
subscribe_to_plan(user, @v4_plan_id,
|
||||
status: :deleted,
|
||||
last_bill_date: ~D[2022-01-01],
|
||||
next_bill_date: ~D[2022-02-01]
|
||||
).subscription
|
||||
user
|
||||
|> team_of()
|
||||
|> Plausible.Teams.with_subscription()
|
||||
|> Map.fetch!(:subscription)
|
||||
|
||||
conn
|
||||
|> get(Routes.settings_path(conn, :subscription))
|
||||
@ -1097,11 +1090,17 @@ defmodule PlausibleWeb.SettingsControllerTest do
|
||||
end
|
||||
end
|
||||
|
||||
defp configure_enterprise_plan(user) do
|
||||
subscribe_to_enterprise_plan(user,
|
||||
paddle_plan_id: @configured_enterprise_plan_paddle_plan_id,
|
||||
monthly_pageview_limit: 20_000_000,
|
||||
billing_interval: :yearly
|
||||
defp configure_enterprise_plan(user, attrs \\ []) do
|
||||
subscribe_to_enterprise_plan(
|
||||
user,
|
||||
Keyword.merge(
|
||||
[
|
||||
paddle_plan_id: @configured_enterprise_plan_paddle_plan_id,
|
||||
monthly_pageview_limit: 20_000_000,
|
||||
billing_interval: :yearly
|
||||
],
|
||||
attrs
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
@ -77,7 +77,8 @@ defmodule PlausibleWeb.Site.MembershipControllerTest do
|
||||
end
|
||||
|
||||
test "fails to create invitation with insufficient permissions", %{conn: conn, user: user} do
|
||||
site = insert(:site, memberships: [build(:site_membership, user: user, role: :viewer)])
|
||||
site = new_site()
|
||||
add_guest(site, user: user, role: :viewer)
|
||||
|
||||
conn =
|
||||
post(conn, "/sites/#{site.domain}/memberships/invite", %{
|
||||
@ -86,17 +87,14 @@ defmodule PlausibleWeb.Site.MembershipControllerTest do
|
||||
})
|
||||
|
||||
assert conn.status == 404
|
||||
|
||||
refute Repo.get_by(Plausible.Auth.Invitation, email: "john.doe@example.com")
|
||||
end
|
||||
|
||||
test "fails to create invitation for a foreign site", %{conn: my_conn, user: me} do
|
||||
_my_site = insert(:site, memberships: [build(:site_membership, user: me, role: "owner")])
|
||||
_my_site = new_site(owner: me)
|
||||
|
||||
other_user = insert(:user)
|
||||
other_user = new_user()
|
||||
|
||||
other_site =
|
||||
insert(:site, memberships: [build(:site_membership, user: other_user, role: "owner")])
|
||||
other_site = new_site(owner: other_user)
|
||||
|
||||
my_conn =
|
||||
post(my_conn, "/sites/#{other_site.domain}/memberships/invite", %{
|
||||
@ -243,8 +241,8 @@ defmodule PlausibleWeb.Site.MembershipControllerTest do
|
||||
end
|
||||
|
||||
test "fails to transfer ownership to a foreign domain", %{conn: conn, user: user} do
|
||||
insert(:site, members: [user])
|
||||
foreign_site = insert(:site)
|
||||
new_site(owner: user)
|
||||
foreign_site = new_site()
|
||||
|
||||
conn =
|
||||
post(conn, "/sites/#{foreign_site.domain}/transfer-ownership", %{
|
||||
@ -252,8 +250,6 @@ defmodule PlausibleWeb.Site.MembershipControllerTest do
|
||||
})
|
||||
|
||||
assert conn.status == 404
|
||||
|
||||
refute Repo.get_by(Plausible.Auth.Invitation, email: "john.doe@example.com")
|
||||
end
|
||||
|
||||
test "fails to transfer ownership to invited user with proper error message", ctx do
|
||||
@ -295,35 +291,12 @@ defmodule PlausibleWeb.Site.MembershipControllerTest do
|
||||
assert_team_membership(collaborator, site.team, :viewer)
|
||||
end
|
||||
|
||||
@tag :teams
|
||||
test "syncs role update to team", %{conn: conn, user: user} do
|
||||
admin = insert(:user)
|
||||
|
||||
site =
|
||||
insert(:site,
|
||||
memberships: [
|
||||
build(:site_membership, user: user, role: :owner),
|
||||
build(:site_membership, user: admin, role: :admin)
|
||||
]
|
||||
)
|
||||
|> Plausible.Teams.load_for_site()
|
||||
|
||||
team_membership =
|
||||
insert(:team_membership, user: admin, team: site.team, role: :guest)
|
||||
|
||||
guest_membership =
|
||||
insert(:guest_membership, team_membership: team_membership, site: site, role: :editor)
|
||||
|
||||
put(conn, "/sites/#{site.domain}/memberships/u/#{admin.id}/role/viewer")
|
||||
|
||||
assert Repo.reload!(guest_membership).role == :viewer
|
||||
end
|
||||
|
||||
test "can downgrade yourself from admin to viewer, redirects to stats instead", %{
|
||||
test "can downgrade yourself from admin to viewer, redirects to stats", %{
|
||||
conn: conn,
|
||||
user: user
|
||||
} do
|
||||
site = insert(:site, memberships: [build(:site_membership, user: user, role: :admin)])
|
||||
site = new_site()
|
||||
add_guest(site, user: user, role: :editor)
|
||||
|
||||
conn = put(conn, "/sites/#{site.domain}/memberships/u/#{user.id}/role/viewer")
|
||||
|
||||
@ -352,7 +325,7 @@ defmodule PlausibleWeb.Site.MembershipControllerTest do
|
||||
conn: conn,
|
||||
user: user
|
||||
} do
|
||||
site = insert(:site, memberships: [build(:site_membership, user: user, role: :owner)])
|
||||
site = new_site(owner: user)
|
||||
|
||||
conn = put(conn, "/sites/#{site.domain}/memberships/u/#{user.id}/role/admin")
|
||||
|
||||
@ -375,7 +348,7 @@ defmodule PlausibleWeb.Site.MembershipControllerTest do
|
||||
|
||||
conn = put(conn, "/sites/#{site.domain}/memberships/u/#{viewer.id}/role/admin")
|
||||
|
||||
assert_team_membership(viewer, site.team, :editor)
|
||||
assert_team_membership(viewer, site.team, :viewer)
|
||||
assert redirected_to(conn) == "/#{URI.encode_www_form(site.domain)}/settings/people"
|
||||
end
|
||||
|
||||
@ -403,105 +376,17 @@ defmodule PlausibleWeb.Site.MembershipControllerTest do
|
||||
refute Repo.exists?(from sm in Plausible.Site.Membership, where: sm.user_id == ^admin.id)
|
||||
end
|
||||
|
||||
@tag :teams
|
||||
test "syncs member removal to team", %{conn: conn, user: user} do
|
||||
admin = insert(:user)
|
||||
|
||||
site =
|
||||
insert(:site,
|
||||
memberships: [
|
||||
build(:site_membership, user: user, role: :owner),
|
||||
build(:site_membership, user: admin, role: :admin)
|
||||
]
|
||||
)
|
||||
|> Plausible.Teams.load_for_site()
|
||||
|
||||
team_membership =
|
||||
insert(:team_membership, user: admin, team: site.team, role: :guest)
|
||||
|
||||
guest_membership =
|
||||
insert(:guest_membership, team_membership: team_membership, site: site, role: :editor)
|
||||
|
||||
conn = delete(conn, "/sites/#{site.domain}/memberships/u/#{admin.id}")
|
||||
assert Phoenix.Flash.get(conn.assigns.flash, :success) =~ "has been removed"
|
||||
|
||||
refute Repo.reload(guest_membership)
|
||||
refute Repo.reload(team_membership)
|
||||
end
|
||||
|
||||
@tag :teams
|
||||
test "sync retains team guest membership when there's another guest membership on it", %{
|
||||
conn: conn,
|
||||
user: user
|
||||
} do
|
||||
admin = insert(:user)
|
||||
|
||||
site =
|
||||
insert(:site,
|
||||
memberships: [
|
||||
build(:site_membership, user: user, role: :owner),
|
||||
build(:site_membership, user: admin, role: :admin)
|
||||
]
|
||||
)
|
||||
|> Plausible.Teams.load_for_site()
|
||||
|
||||
another_site =
|
||||
insert(:site,
|
||||
team: site.team,
|
||||
memberships: [
|
||||
build(:site_membership, user: user, role: :owner),
|
||||
build(:site_membership, user: admin, role: :admin)
|
||||
]
|
||||
)
|
||||
|> Plausible.Teams.load_for_site()
|
||||
|
||||
team_membership =
|
||||
insert(:team_membership, user: admin, team: site.team, role: :guest)
|
||||
|
||||
guest_membership =
|
||||
insert(:guest_membership, team_membership: team_membership, site: site, role: :editor)
|
||||
|
||||
another_guest_membership =
|
||||
insert(:guest_membership,
|
||||
team_membership: team_membership,
|
||||
site: another_site,
|
||||
role: :editor
|
||||
)
|
||||
|
||||
conn = delete(conn, "/sites/#{site.domain}/memberships/u/#{admin.id}")
|
||||
assert Phoenix.Flash.get(conn.assigns.flash, :success) =~ "has been removed"
|
||||
|
||||
refute Repo.reload(guest_membership)
|
||||
assert Repo.reload(another_guest_membership)
|
||||
assert Repo.reload(team_membership)
|
||||
end
|
||||
|
||||
test "fails to remove a member from a foreign site", %{conn: conn, user: user} do
|
||||
foreign_site =
|
||||
insert(:site,
|
||||
memberships: [
|
||||
build(:site_membership, user: build(:user), role: :admin)
|
||||
]
|
||||
)
|
||||
foreign_member = new_user()
|
||||
foreign_site = new_site()
|
||||
add_guest(foreign_site, user: foreign_member, role: :editor)
|
||||
|
||||
[foreign_membership] = foreign_site.memberships
|
||||
site = new_site(owner: user)
|
||||
|
||||
site =
|
||||
insert(:site,
|
||||
memberships: [
|
||||
build(:site_membership, user: user, role: :owner)
|
||||
]
|
||||
)
|
||||
|
||||
conn = delete(conn, "/sites/#{site.domain}/memberships/u/#{foreign_membership.user_id}")
|
||||
conn = delete(conn, "/sites/#{site.domain}/memberships/u/#{foreign_member.id}")
|
||||
|
||||
assert Phoenix.Flash.get(conn.assigns.flash, :error) ==
|
||||
"Failed to find membership to remove"
|
||||
|
||||
assert Repo.exists?(
|
||||
from sm in Plausible.Site.Membership,
|
||||
where: sm.user_id == ^foreign_membership.user.id
|
||||
)
|
||||
end
|
||||
|
||||
test "notifies the user who has been removed via email", %{conn: conn, user: user} do
|
||||
|
@ -42,12 +42,11 @@ defmodule PlausibleWeb.SiteControllerTest do
|
||||
conn: conn,
|
||||
user: user
|
||||
} do
|
||||
ep = insert(:enterprise_plan, user: user)
|
||||
insert(:subscription, user: user, paddle_plan_id: ep.paddle_plan_id)
|
||||
subscribe_to_enterprise_plan(user)
|
||||
|
||||
insert(:site, members: [user])
|
||||
insert(:site, members: [user])
|
||||
insert(:site, members: [user])
|
||||
new_site(owner: user)
|
||||
new_site(owner: user)
|
||||
new_site(owner: user)
|
||||
|
||||
conn = get(conn, "/sites/new")
|
||||
refute html_response(conn, 200) =~ "is limited to"
|
||||
@ -342,9 +341,9 @@ defmodule PlausibleWeb.SiteControllerTest do
|
||||
conn: conn,
|
||||
user: user
|
||||
} do
|
||||
ep = insert(:enterprise_plan, user: user, site_limit: 1)
|
||||
insert(:subscription, user: user, paddle_plan_id: ep.paddle_plan_id)
|
||||
insert_list(2, :site, members: [user])
|
||||
subscribe_to_enterprise_plan(user, site_limit: 1)
|
||||
new_site(owner: user)
|
||||
new_site(owner: user)
|
||||
|
||||
conn =
|
||||
post(conn, "/sites", %{
|
||||
@ -622,19 +621,17 @@ defmodule PlausibleWeb.SiteControllerTest do
|
||||
end
|
||||
|
||||
test "fails to make site public with insufficient permissions", %{conn: conn, user: user} do
|
||||
site = insert(:site, memberships: [build(:site_membership, user: user, role: :viewer)])
|
||||
site = new_site()
|
||||
add_guest(site, user: user, role: :viewer)
|
||||
conn = post(conn, "/sites/#{site.domain}/make-public")
|
||||
assert conn.status == 404
|
||||
refute Repo.get(Plausible.Site, site.id).public
|
||||
end
|
||||
|
||||
test "fails to make foreign site public", %{conn: my_conn, user: me} do
|
||||
_my_site = insert(:site, memberships: [build(:site_membership, user: me, role: :owner)])
|
||||
|
||||
other_user = insert(:user)
|
||||
|
||||
other_site =
|
||||
insert(:site, memberships: [build(:site_membership, user: other_user, role: "owner")])
|
||||
_my_site = new_site(owner: me)
|
||||
other_user = new_user()
|
||||
other_site = new_site(owner: other_user)
|
||||
|
||||
my_conn = post(my_conn, "/sites/#{other_site.domain}/make-public")
|
||||
assert my_conn.status == 404
|
||||
@ -660,7 +657,7 @@ defmodule PlausibleWeb.SiteControllerTest do
|
||||
setup [:create_user, :log_in, :create_site]
|
||||
|
||||
test "deletes the site", %{conn: conn, user: user} do
|
||||
site = insert(:site, members: [user])
|
||||
site = new_site(owner: user)
|
||||
insert(:google_auth, user: user, site: site)
|
||||
insert(:spike_notification, site: site)
|
||||
insert(:drop_notification, site: site)
|
||||
@ -671,7 +668,8 @@ defmodule PlausibleWeb.SiteControllerTest do
|
||||
end
|
||||
|
||||
test "fails to delete a site with insufficient permissions", %{conn: conn, user: user} do
|
||||
site = insert(:site, memberships: [build(:site_membership, user: user, role: :viewer)])
|
||||
site = new_site()
|
||||
add_guest(site, user: user, role: :viewer)
|
||||
insert(:google_auth, user: user, site: site)
|
||||
insert(:spike_notification, site: site)
|
||||
|
||||
@ -682,12 +680,9 @@ defmodule PlausibleWeb.SiteControllerTest do
|
||||
end
|
||||
|
||||
test "fails to delete a foreign site", %{conn: my_conn, user: me} do
|
||||
_my_site = insert(:site, memberships: [build(:site_membership, user: me, role: :owner)])
|
||||
|
||||
other_user = insert(:user)
|
||||
|
||||
other_site =
|
||||
insert(:site, memberships: [build(:site_membership, user: other_user, role: "owner")])
|
||||
_my_site = new_site(owner: me)
|
||||
other_user = new_user()
|
||||
other_site = new_site(owner: other_user)
|
||||
|
||||
insert(:google_auth, user: other_user, site: other_site)
|
||||
insert(:spike_notification, site: other_site)
|
||||
@ -734,7 +729,7 @@ defmodule PlausibleWeb.SiteControllerTest do
|
||||
conn: conn,
|
||||
user: user
|
||||
} do
|
||||
other_site = insert(:site)
|
||||
other_site = new_site()
|
||||
insert(:google_auth, user: user, site: other_site)
|
||||
conn = delete(conn, "/#{URI.encode_www_form(other_site.domain)}/settings/google-search")
|
||||
|
||||
@ -907,7 +902,7 @@ defmodule PlausibleWeb.SiteControllerTest do
|
||||
end
|
||||
|
||||
test "displays Continue with Google link", %{conn: conn, user: user} do
|
||||
site = insert(:site, domain: "notconnectedyet.example.com", members: [user])
|
||||
site = new_site(domain: "notconnectedyet.example.com", owner: user)
|
||||
|
||||
conn = get(conn, "/#{site.domain}/settings/integrations")
|
||||
resp = html_response(conn, 200)
|
||||
@ -1026,13 +1021,8 @@ defmodule PlausibleWeb.SiteControllerTest do
|
||||
conn: conn0,
|
||||
conn_with_url: conn_with_url
|
||||
} do
|
||||
site =
|
||||
insert(:site,
|
||||
memberships: [
|
||||
build(:site_membership, user: build(:user), role: :owner),
|
||||
build(:site_membership, user: user, role: :admin)
|
||||
]
|
||||
)
|
||||
site = new_site()
|
||||
add_guest(site, user: user, role: :editor)
|
||||
|
||||
conn =
|
||||
put(
|
||||
@ -1082,8 +1072,8 @@ defmodule PlausibleWeb.SiteControllerTest do
|
||||
conn: conn0,
|
||||
conn_with_url: conn_with_url
|
||||
} do
|
||||
site = insert(:site)
|
||||
insert(:site_membership, user: user, site: site, role: :viewer)
|
||||
site = new_site()
|
||||
add_guest(site, user: user, role: :viewer)
|
||||
|
||||
conn =
|
||||
put(
|
||||
@ -1106,8 +1096,8 @@ defmodule PlausibleWeb.SiteControllerTest do
|
||||
conn: conn0,
|
||||
conn_with_url: conn_with_url
|
||||
} do
|
||||
site = insert(:site)
|
||||
insert(:site_membership, user: user, site: site, role: :admin)
|
||||
site = new_site()
|
||||
add_guest(site, user: user, role: :editor)
|
||||
|
||||
setting = :funnels_enabled
|
||||
|
||||
@ -1172,7 +1162,7 @@ defmodule PlausibleWeb.SiteControllerTest do
|
||||
end
|
||||
|
||||
test "fails to delete the weekly report record for a foreign site", %{conn: conn} do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
insert(:weekly_report, site: site)
|
||||
|
||||
post(conn, "/sites/#{site.domain}/weekly-report/disable")
|
||||
@ -1207,7 +1197,7 @@ defmodule PlausibleWeb.SiteControllerTest do
|
||||
end
|
||||
|
||||
test "fails to remove a recipient from the weekly report in a foreign website", %{conn: conn} do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
insert(:weekly_report, site: site, recipients: ["recipient@email.com"])
|
||||
|
||||
conn1 = delete(conn, "/sites/#{site.domain}/weekly-report/recipients/recipient@email.com")
|
||||
@ -1290,7 +1280,7 @@ defmodule PlausibleWeb.SiteControllerTest do
|
||||
test "fails to remove a recipient from the monthly report in a foreign website", %{
|
||||
conn: conn
|
||||
} do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
insert(:monthly_report, site: site, recipients: ["recipient@email.com"])
|
||||
|
||||
conn1 = delete(conn, "/sites/#{site.domain}/monthly-report/recipients/recipient@email.com")
|
||||
@ -1419,7 +1409,7 @@ defmodule PlausibleWeb.SiteControllerTest do
|
||||
test "fails to remove a recipient from the #{type} notification in a foreign website", %{
|
||||
conn: conn
|
||||
} do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
insert(:"#{unquote(type)}_notification", site: site, recipients: ["recipient@email.com"])
|
||||
|
||||
conn =
|
||||
|
@ -39,7 +39,7 @@ defmodule PlausibleWeb.StatsControllerTest do
|
||||
end
|
||||
|
||||
test "plausible.io live demo - shows site stats", %{conn: conn} do
|
||||
site = insert(:site, domain: "plausible.io", public: true)
|
||||
site = new_site(domain: "plausible.io", public: true)
|
||||
populate_stats(site, [build(:pageview)])
|
||||
|
||||
conn = get(conn, "/#{site.domain}")
|
||||
@ -66,7 +66,7 @@ defmodule PlausibleWeb.StatsControllerTest do
|
||||
test "public site - no stats with skip_to_dashboard", %{
|
||||
conn: conn
|
||||
} do
|
||||
insert(:site, domain: "some-other-public-site.io", public: true)
|
||||
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)
|
||||
@ -103,13 +103,13 @@ defmodule PlausibleWeb.StatsControllerTest do
|
||||
end
|
||||
|
||||
test "shows locked page if page is locked", %{conn: conn, user: user} do
|
||||
locked_site = insert(:site, locked: true, members: [user])
|
||||
locked_site = new_site(locked: true, owner: user)
|
||||
conn = get(conn, "/" <> locked_site.domain)
|
||||
assert html_response(conn, 200) =~ "Dashboard locked"
|
||||
end
|
||||
|
||||
test "can not view stats of someone else's website", %{conn: conn} do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
conn = get(conn, "/" <> site.domain)
|
||||
assert html_response(conn, 404) =~ "There's nothing here"
|
||||
end
|
||||
@ -125,7 +125,7 @@ defmodule PlausibleWeb.StatsControllerTest do
|
||||
setup [:create_user, :make_user_super_admin, :log_in]
|
||||
|
||||
test "can view a private dashboard with stats", %{conn: conn} do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
populate_stats(site, [build(:pageview)])
|
||||
|
||||
conn = get(conn, "/" <> site.domain)
|
||||
@ -133,15 +133,15 @@ defmodule PlausibleWeb.StatsControllerTest do
|
||||
end
|
||||
|
||||
test "can enter verification when site is without stats", %{conn: conn} do
|
||||
site = insert(:site)
|
||||
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 = insert(:user)
|
||||
site = insert(:site, locked: true, members: [user])
|
||||
user = new_user()
|
||||
site = new_site(locked: true, owner: user)
|
||||
populate_stats(site, [build(:pageview)])
|
||||
|
||||
conn = get(conn, "/" <> site.domain)
|
||||
@ -153,15 +153,15 @@ defmodule PlausibleWeb.StatsControllerTest do
|
||||
end
|
||||
|
||||
test "can view private locked verification without stats", %{conn: conn} do
|
||||
user = insert(:user)
|
||||
site = insert(:site, locked: true, members: [user])
|
||||
user = new_user()
|
||||
site = new_site(locked: true, owner: user)
|
||||
|
||||
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 = insert(:site, locked: true, public: true)
|
||||
site = new_site(locked: true, public: true)
|
||||
populate_stats(site, [build(:pageview)])
|
||||
|
||||
conn = get(conn, "/" <> site.domain)
|
||||
@ -172,7 +172,7 @@ defmodule PlausibleWeb.StatsControllerTest do
|
||||
end
|
||||
|
||||
test "shows CRM link to the site", %{conn: conn} do
|
||||
site = insert(:site)
|
||||
site = new_site()
|
||||
conn = get(conn, conn |> get("/" <> site.domain) |> redirected_to())
|
||||
assert html_response(conn, 200) =~ "/crm/sites/site/#{site.id}"
|
||||
end
|
||||
@ -603,7 +603,7 @@ defmodule PlausibleWeb.StatsControllerTest do
|
||||
|
||||
describe "GET /:domain/export - via shared link" do
|
||||
test "exports data in zipped csvs", %{conn: conn} do
|
||||
site = insert(:site, domain: "new-site.com")
|
||||
site = new_site(domain: "new-site.com")
|
||||
link = insert(:shared_link, site: site)
|
||||
|
||||
populate_exported_stats(site)
|
||||
@ -875,7 +875,7 @@ defmodule PlausibleWeb.StatsControllerTest do
|
||||
test "logs anonymous user in straight away if the link is not password-protected", %{
|
||||
conn: conn
|
||||
} do
|
||||
site = insert(:site, domain: "test-site.com")
|
||||
site = new_site(domain: "test-site.com")
|
||||
link = insert(:shared_link, site: site)
|
||||
|
||||
conn = get(conn, "/share/test-site.com/?auth=#{link.slug}")
|
||||
@ -885,7 +885,7 @@ defmodule PlausibleWeb.StatsControllerTest do
|
||||
test "returns page with X-Frame-Options disabled so it can be embedded in an iframe", %{
|
||||
conn: conn
|
||||
} do
|
||||
site = insert(:site, domain: "test-site.com")
|
||||
site = new_site(domain: "test-site.com")
|
||||
link = insert(:shared_link, site: site)
|
||||
|
||||
conn = get(conn, "/share/test-site.com/?auth=#{link.slug}")
|
||||
@ -897,7 +897,7 @@ defmodule PlausibleWeb.StatsControllerTest do
|
||||
test "returns page embedded page", %{
|
||||
conn: conn
|
||||
} do
|
||||
site = insert(:site, domain: "test-site.com")
|
||||
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")
|
||||
@ -959,7 +959,7 @@ defmodule PlausibleWeb.StatsControllerTest do
|
||||
|
||||
describe "POST /share/:slug/authenticate" do
|
||||
test "logs anonymous user in with correct password", %{conn: conn} do
|
||||
site = insert(:site, domain: "test-site.com")
|
||||
site = new_site(domain: "test-site.com")
|
||||
|
||||
link =
|
||||
insert(:shared_link, site: site, password_hash: Plausible.Auth.Password.hash("password"))
|
||||
|
@ -867,9 +867,12 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
|
||||
|
||||
test "highlights recommended tier if subscription expired and no days are paid for anymore",
|
||||
%{conn: conn, user: user} do
|
||||
user.subscription
|
||||
user
|
||||
|> team_of()
|
||||
|> Repo.preload(:subscription)
|
||||
|> Map.fetch!(:subscription)
|
||||
|> Subscription.changeset(%{next_bill_date: Timex.shift(Timex.now(), months: -2)})
|
||||
|> Repo.update()
|
||||
|> Repo.update!()
|
||||
|
||||
{:ok, _lv, doc} = get_liveview(conn)
|
||||
assert text_of_element(doc, @growth_highlight_pill) == "Recommended"
|
||||
|
@ -64,8 +64,8 @@ defmodule PlausibleWeb.Plugs.AuthorizePublicAPITest do
|
||||
|
||||
@tag :ee_only
|
||||
test "halts with error when upgrade is required", %{conn: conn} do
|
||||
user = insert(:user, trial_expiry_date: nil)
|
||||
site = insert(:site, members: [user])
|
||||
user = new_user() |> subscribe_to_enterprise_plan(paddle_plan_id: "123321", features: [])
|
||||
site = new_site(owner: user)
|
||||
api_key = insert(:api_key, user: user)
|
||||
|
||||
conn =
|
||||
@ -82,8 +82,8 @@ defmodule PlausibleWeb.Plugs.AuthorizePublicAPITest do
|
||||
end
|
||||
|
||||
test "halts with error when site is locked", %{conn: conn} do
|
||||
user = insert(:user)
|
||||
site = insert(:site, members: [user], locked: true)
|
||||
user = new_user()
|
||||
site = new_site(owner: user, locked: true)
|
||||
api_key = insert(:api_key, user: user)
|
||||
|
||||
conn =
|
||||
@ -202,9 +202,9 @@ defmodule PlausibleWeb.Plugs.AuthorizePublicAPITest do
|
||||
|
||||
@tag :ee_only
|
||||
test "passes for super admin user even if not a member of the requested site", %{conn: conn} do
|
||||
user = insert(:user)
|
||||
user = new_user()
|
||||
patch_env(:super_admin_user_ids, [user.id])
|
||||
site = insert(:site, locked: true)
|
||||
site = new_site(locked: true)
|
||||
api_key = insert(:api_key, user: user)
|
||||
|
||||
conn =
|
||||
|
@ -1,5 +1,6 @@
|
||||
defmodule PlausibleWeb.Plugs.AuthorizeSiteAccessTest do
|
||||
use PlausibleWeb.ConnCase, async: false
|
||||
use Plausible.Teams.Test
|
||||
alias PlausibleWeb.Plugs.AuthorizeSiteAccess
|
||||
|
||||
setup [:create_user, :log_in, :create_site]
|
||||
@ -14,10 +15,10 @@ defmodule PlausibleWeb.Plugs.AuthorizeSiteAccessTest do
|
||||
[],
|
||||
:all_roles,
|
||||
{:all_roles, nil},
|
||||
{[:public, :viewer, :admin, :super_admin, :owner], nil}
|
||||
{[:public, :viewer, :admin, :editor, :super_admin, :owner], nil}
|
||||
] do
|
||||
test "init resolves to expected options with argument #{inspect(init_argument)}" do
|
||||
assert {[:public, :viewer, :admin, :super_admin, :owner], nil} ==
|
||||
assert {[:public, :viewer, :admin, :editor, :super_admin, :owner], nil} ==
|
||||
AuthorizeSiteAccess.init(unquote(init_argument))
|
||||
end
|
||||
end
|
||||
@ -46,7 +47,7 @@ defmodule PlausibleWeb.Plugs.AuthorizeSiteAccessTest do
|
||||
test "rejects user completely unrelated to the site", %{conn: conn} do
|
||||
opts = AuthorizeSiteAccess.init(:all_roles)
|
||||
|
||||
site = insert(:site, members: [build(:user)])
|
||||
site = new_site()
|
||||
|
||||
conn =
|
||||
conn
|
||||
@ -98,7 +99,7 @@ defmodule PlausibleWeb.Plugs.AuthorizeSiteAccessTest do
|
||||
conn: conn,
|
||||
site: site
|
||||
} do
|
||||
other_site = insert(:site, members: [build(:user)])
|
||||
other_site = new_site()
|
||||
|
||||
opts = AuthorizeSiteAccess.init([:admin, :owner])
|
||||
|
||||
@ -116,7 +117,8 @@ defmodule PlausibleWeb.Plugs.AuthorizeSiteAccessTest do
|
||||
end
|
||||
|
||||
test "returns 404 with custom error message for failed API routes", %{conn: conn, user: user} do
|
||||
site = insert(:site, memberships: [build(:site_membership, user: user, role: :viewer)])
|
||||
site = new_site()
|
||||
add_guest(site, user: user, role: :viewer)
|
||||
|
||||
opts = AuthorizeSiteAccess.init([:admin, :owner, :super_admin])
|
||||
|
||||
@ -137,7 +139,7 @@ defmodule PlausibleWeb.Plugs.AuthorizeSiteAccessTest do
|
||||
conn: conn,
|
||||
site: site
|
||||
} do
|
||||
shared_link_other_site = insert(:shared_link, site: build(:site))
|
||||
shared_link_other_site = insert(:shared_link, site: new_site())
|
||||
|
||||
params = %{"shared_link" => %{"name" => "some name"}}
|
||||
|
||||
@ -160,7 +162,7 @@ defmodule PlausibleWeb.Plugs.AuthorizeSiteAccessTest do
|
||||
site: site
|
||||
} do
|
||||
shared_link = insert(:shared_link, site: site)
|
||||
other_site = insert(:site, members: [user])
|
||||
other_site = new_site(owner: user)
|
||||
|
||||
opts = AuthorizeSiteAccess.init([:super_admin, :admin, :owner])
|
||||
|
||||
@ -200,8 +202,8 @@ defmodule PlausibleWeb.Plugs.AuthorizeSiteAccessTest do
|
||||
end
|
||||
|
||||
test "rejects user on mismatched membership role", %{conn: conn, user: user} do
|
||||
site =
|
||||
insert(:site, memberships: [build(:site_membership, user: user, role: :admin)])
|
||||
site = new_site()
|
||||
add_guest(site, user: user, role: :editor)
|
||||
|
||||
opts = AuthorizeSiteAccess.init([:owner])
|
||||
|
||||
@ -215,10 +217,26 @@ defmodule PlausibleWeb.Plugs.AuthorizeSiteAccessTest do
|
||||
assert html_response(conn, 404)
|
||||
end
|
||||
|
||||
for role <- [:viewer, :admin, :owner] do
|
||||
test "allows user based on ownership", %{conn: conn, user: user} do
|
||||
site = new_site(owner: user)
|
||||
|
||||
opts = AuthorizeSiteAccess.init([:owner])
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> bypass_through(PlausibleWeb.Router)
|
||||
|> get("/plug-tests/#{site.domain}/with-domain")
|
||||
|> AuthorizeSiteAccess.call(opts)
|
||||
|
||||
refute conn.halted
|
||||
assert conn.assigns.site.id == site.id
|
||||
assert conn.assigns.current_user_role == :owner
|
||||
end
|
||||
|
||||
for role <- [:viewer, :editor] do
|
||||
test "allows user based on their #{role} membership", %{conn: conn, user: user} do
|
||||
site =
|
||||
insert(:site, memberships: [build(:site_membership, user: user, role: unquote(role))])
|
||||
site = new_site()
|
||||
add_guest(site, user: user, role: unquote(role))
|
||||
|
||||
opts = AuthorizeSiteAccess.init([unquote(role)])
|
||||
|
||||
@ -236,7 +254,7 @@ defmodule PlausibleWeb.Plugs.AuthorizeSiteAccessTest do
|
||||
|
||||
@tag :ee_only
|
||||
test "allows user based on their superadmin status", %{conn: conn, user: user} do
|
||||
site = insert(:site, members: [build(:user)])
|
||||
site = new_site()
|
||||
|
||||
patch_env(:super_admin_user_ids, [user.id])
|
||||
|
||||
@ -254,7 +272,7 @@ defmodule PlausibleWeb.Plugs.AuthorizeSiteAccessTest do
|
||||
end
|
||||
|
||||
test "allows user based on website visibility (authenticated user)", %{conn: conn} do
|
||||
site = insert(:site, members: [build(:user)], public: true)
|
||||
site = new_site(public: true)
|
||||
|
||||
opts = AuthorizeSiteAccess.init([:public])
|
||||
|
||||
@ -284,7 +302,7 @@ defmodule PlausibleWeb.Plugs.AuthorizeSiteAccessTest do
|
||||
end
|
||||
|
||||
test "allows user based on shared link auth (authenticated user)", %{conn: conn} do
|
||||
site = insert(:site, members: [build(:user)])
|
||||
site = new_site()
|
||||
shared_link = insert(:shared_link, site: site)
|
||||
|
||||
opts = AuthorizeSiteAccess.init([:public])
|
||||
|
@ -46,22 +46,40 @@ defmodule Plausible.Teams.Test do
|
||||
end
|
||||
|
||||
def new_user(args \\ []) do
|
||||
{team_args, args} = Keyword.pop(args, :team, [])
|
||||
user = insert(:user, args)
|
||||
|
||||
if user.trial_expiry_date do
|
||||
{:ok, _team} = Teams.get_or_create(user)
|
||||
{:ok, team} = Teams.get_or_create(user)
|
||||
|
||||
team_args = Keyword.merge(team_args, trial_expiry_date: user.trial_expiry_date)
|
||||
|
||||
team
|
||||
|> Ecto.Changeset.change(team_args)
|
||||
|> Repo.update!()
|
||||
end
|
||||
|
||||
Repo.preload(user, team_memberships: :team)
|
||||
end
|
||||
|
||||
def team_of(%{team_memberships: [%{role: :owner, team: %Teams.Team{} = team}]}) do
|
||||
team
|
||||
def team_of(subject, opts \\ [])
|
||||
|
||||
def team_of(%{team_memberships: [%{role: :owner, team: %Teams.Team{} = team}]}, opts) do
|
||||
if opts[:with_subscription?] do
|
||||
Plausible.Teams.with_subscription(team)
|
||||
else
|
||||
team
|
||||
end
|
||||
end
|
||||
|
||||
def team_of(user) do
|
||||
def team_of(user, opts) do
|
||||
{:ok, team} = Plausible.Teams.get_by_owner(user)
|
||||
team
|
||||
|
||||
if opts[:with_subscription?] do
|
||||
Plausible.Teams.with_subscription(team)
|
||||
else
|
||||
team
|
||||
end
|
||||
end
|
||||
|
||||
def add_guest(site, args \\ []) do
|
||||
@ -121,15 +139,21 @@ defmodule Plausible.Teams.Test do
|
||||
old_model_invitation
|
||||
end
|
||||
|
||||
def invite_transfer(site, invitee, args \\ []) do
|
||||
def invite_transfer(site, invitee_or_email, args \\ []) do
|
||||
inviter = Keyword.fetch!(args, :inviter)
|
||||
|
||||
email =
|
||||
case invitee_or_email do
|
||||
%{email: email} -> email
|
||||
email when is_binary(email) -> email
|
||||
end
|
||||
|
||||
old_model_invitation =
|
||||
insert(:invitation, email: invitee.email, inviter: inviter, role: :owner, site: site)
|
||||
insert(:invitation, email: email, inviter: inviter, role: :owner, site: site)
|
||||
|
||||
insert(:site_transfer,
|
||||
transfer_id: old_model_invitation.invitation_id,
|
||||
email: invitee.email,
|
||||
email: email,
|
||||
site: site,
|
||||
initiator: inviter
|
||||
)
|
||||
@ -170,8 +194,7 @@ defmodule Plausible.Teams.Test do
|
||||
{:ok, team} = Teams.get_or_create(user)
|
||||
attrs = Keyword.merge([user: user, team: team, paddle_plan_id: paddle_plan_id], attrs)
|
||||
|
||||
subscription =
|
||||
insert(:subscription, attrs)
|
||||
subscription = insert(:subscription, attrs)
|
||||
|
||||
%{user | subscription: subscription}
|
||||
end
|
||||
@ -180,14 +203,21 @@ defmodule Plausible.Teams.Test do
|
||||
{:ok, team} = Teams.get_or_create(user)
|
||||
|
||||
{subscription?, attrs} = Keyword.pop(attrs, :subscription?, true)
|
||||
{subscription_attrs, attrs} = Keyword.pop(attrs, :subscription, [])
|
||||
|
||||
enterprise_plan = insert(:enterprise_plan, Keyword.merge([user: user, team: team], attrs))
|
||||
|
||||
if subscription? do
|
||||
insert(:subscription,
|
||||
team: team,
|
||||
user: user,
|
||||
paddle_plan_id: enterprise_plan.paddle_plan_id
|
||||
insert(
|
||||
:subscription,
|
||||
Keyword.merge(
|
||||
[
|
||||
team: team,
|
||||
user: user,
|
||||
paddle_plan_id: enterprise_plan.paddle_plan_id
|
||||
],
|
||||
subscription_attrs
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
|
@ -431,13 +431,13 @@ defmodule Plausible.Workers.CheckUsageTest do
|
||||
}
|
||||
end)
|
||||
|
||||
enterprise_plan = insert(:enterprise_plan, user: user, monthly_pageview_limit: 1_000_000)
|
||||
|
||||
insert(:subscription,
|
||||
user: user,
|
||||
paddle_plan_id: enterprise_plan.paddle_plan_id,
|
||||
last_bill_date: Timex.shift(Timex.today(), days: -1),
|
||||
status: unquote(status)
|
||||
subscribe_to_enterprise_plan(
|
||||
user,
|
||||
monthly_pageview_limit: 1_000_000,
|
||||
subscription: [
|
||||
last_bill_date: Timex.shift(Timex.today(), days: -1),
|
||||
status: unquote(status)
|
||||
]
|
||||
)
|
||||
|
||||
CheckUsage.perform(nil, usage_stub)
|
||||
@ -461,19 +461,18 @@ defmodule Plausible.Workers.CheckUsageTest do
|
||||
}
|
||||
end)
|
||||
|
||||
enterprise_plan = insert(:enterprise_plan, user: user, site_limit: 2)
|
||||
|
||||
insert(:site, members: [user])
|
||||
insert(:site, members: [user])
|
||||
insert(:site, members: [user])
|
||||
|
||||
insert(:subscription,
|
||||
user: user,
|
||||
paddle_plan_id: enterprise_plan.paddle_plan_id,
|
||||
last_bill_date: Timex.shift(Timex.today(), days: -1),
|
||||
status: unquote(status)
|
||||
subscribe_to_enterprise_plan(user,
|
||||
site_limit: 2,
|
||||
subscription: [
|
||||
last_bill_date: Timex.shift(Timex.today(), days: -1),
|
||||
status: unquote(status)
|
||||
]
|
||||
)
|
||||
|
||||
new_site(owner: user)
|
||||
new_site(owner: user)
|
||||
new_site(owner: user)
|
||||
|
||||
CheckUsage.perform(nil, usage_stub)
|
||||
|
||||
assert_email_delivered_with(
|
||||
@ -482,6 +481,33 @@ defmodule Plausible.Workers.CheckUsageTest do
|
||||
)
|
||||
end
|
||||
|
||||
test "manual lock grace period is synced with teams", %{user: user} do
|
||||
usage_stub =
|
||||
Plausible.Billing.Quota.Usage
|
||||
|> stub(:monthly_pageview_usage, fn _user ->
|
||||
%{
|
||||
penultimate_cycle: %{date_range: @date_range, total: 1_100_000},
|
||||
last_cycle: %{date_range: @date_range, total: 1_100_000}
|
||||
}
|
||||
end)
|
||||
|
||||
subscribe_to_enterprise_plan(
|
||||
user,
|
||||
monthly_pageview_limit: 1_000_000,
|
||||
subscription: [
|
||||
last_bill_date: Timex.shift(Timex.today(), days: -1),
|
||||
status: unquote(status)
|
||||
]
|
||||
)
|
||||
|
||||
CheckUsage.perform(nil, usage_stub)
|
||||
|
||||
assert user = Repo.reload!(user)
|
||||
team = assert_team_exists(user)
|
||||
assert team.grace_period.manual_lock == user.grace_period.manual_lock
|
||||
assert team.grace_period.manual_lock == true
|
||||
end
|
||||
|
||||
test "starts grace period when plan is outgrown", %{user: user} do
|
||||
usage_stub =
|
||||
Plausible.Billing.Quota.Usage
|
||||
@ -492,46 +518,18 @@ defmodule Plausible.Workers.CheckUsageTest do
|
||||
}
|
||||
end)
|
||||
|
||||
enterprise_plan = insert(:enterprise_plan, user: user, monthly_pageview_limit: 1_000_000)
|
||||
|
||||
insert(:subscription,
|
||||
user: user,
|
||||
paddle_plan_id: enterprise_plan.paddle_plan_id,
|
||||
last_bill_date: Timex.shift(Timex.today(), days: -1),
|
||||
status: unquote(status)
|
||||
subscribe_to_enterprise_plan(
|
||||
user,
|
||||
monthly_pageview_limit: 1_000_000,
|
||||
subscription: [
|
||||
last_bill_date: Timex.shift(Timex.today(), days: -1),
|
||||
status: unquote(status)
|
||||
]
|
||||
)
|
||||
|
||||
CheckUsage.perform(nil, usage_stub)
|
||||
assert user |> Repo.reload() |> Plausible.Auth.GracePeriod.active?()
|
||||
end
|
||||
|
||||
@tag :teams
|
||||
test "manual lock grace period is synced with teams", %{user: user} do
|
||||
usage_stub =
|
||||
Plausible.Billing.Quota.Usage
|
||||
|> stub(:monthly_pageview_usage, fn _user ->
|
||||
%{
|
||||
penultimate_cycle: %{date_range: @date_range, total: 1_100_000},
|
||||
last_cycle: %{date_range: @date_range, total: 1_100_000}
|
||||
}
|
||||
end)
|
||||
|
||||
enterprise_plan = insert(:enterprise_plan, user: user, monthly_pageview_limit: 1_000_000)
|
||||
|
||||
insert(:subscription,
|
||||
user: user,
|
||||
paddle_plan_id: enterprise_plan.paddle_plan_id,
|
||||
last_bill_date: Timex.shift(Timex.today(), days: -1),
|
||||
status: unquote(status)
|
||||
)
|
||||
|
||||
CheckUsage.perform(nil, usage_stub)
|
||||
|
||||
assert user = Repo.reload!(user)
|
||||
team = assert_team_exists(user)
|
||||
assert team.grace_period.manual_lock == user.grace_period.manual_lock
|
||||
assert team.grace_period.manual_lock == true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
defmodule Plausible.Workers.SendEmailReportTest do
|
||||
use Plausible.DataCase
|
||||
use Bamboo.Test
|
||||
use Plausible.Teams.Test
|
||||
use Oban.Testing, repo: Plausible.Repo
|
||||
import Plausible.Test.Support.HTML
|
||||
alias Plausible.Workers.SendEmailReport
|
||||
@ -11,7 +12,7 @@ defmodule Plausible.Workers.SendEmailReportTest do
|
||||
|
||||
describe "weekly reports" do
|
||||
test "sends weekly report to all recipients" do
|
||||
site = insert(:site, domain: "test-site.com", timezone: "US/Eastern")
|
||||
site = new_site(domain: "test-site.com", timezone: "US/Eastern")
|
||||
insert(:weekly_report, site: site, recipients: ["user@email.com", "user2@email.com"])
|
||||
|
||||
perform_job(SendEmailReport, %{"site_id" => site.id, "interval" => "weekly"})
|
||||
@ -33,7 +34,7 @@ defmodule Plausible.Workers.SendEmailReportTest do
|
||||
end
|
||||
|
||||
test "does not crash when weekly report has been deleted since scheduling job" do
|
||||
site = insert(:site, domain: "test-site.com", timezone: "US/Eastern")
|
||||
site = new_site(domain: "test-site.com", timezone: "US/Eastern")
|
||||
|
||||
assert :discard =
|
||||
perform_job(SendEmailReport, %{"site_id" => site.id, "interval" => "weekly"})
|
||||
@ -41,9 +42,7 @@ defmodule Plausible.Workers.SendEmailReportTest do
|
||||
|
||||
test "calculates timezone correctly" do
|
||||
site =
|
||||
insert(:site,
|
||||
timezone: "US/Eastern"
|
||||
)
|
||||
new_site(timezone: "US/Eastern")
|
||||
|
||||
insert(:weekly_report, site: site, recipients: ["user@email.com"])
|
||||
|
||||
@ -81,7 +80,7 @@ defmodule Plausible.Workers.SendEmailReportTest do
|
||||
|
||||
test "includes the correct stats" do
|
||||
now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
|
||||
site = insert(:site, domain: "test-site.com", inserted_at: Timex.shift(now, days: -8))
|
||||
site = new_site(domain: "test-site.com", inserted_at: Timex.shift(now, days: -8))
|
||||
insert(:weekly_report, site: site, recipients: ["user@email.com"])
|
||||
|
||||
populate_stats(site, [
|
||||
@ -114,7 +113,7 @@ defmodule Plausible.Workers.SendEmailReportTest do
|
||||
week_ago = now |> Timex.shift(days: -7)
|
||||
two_weeks_ago = now |> Timex.shift(days: -14)
|
||||
|
||||
site = insert(:site, inserted_at: Timex.shift(now, days: -15))
|
||||
site = new_site(inserted_at: Timex.shift(now, days: -15))
|
||||
insert(:weekly_report, site: site, recipients: ["user@email.com"])
|
||||
|
||||
populate_stats(site, [
|
||||
@ -149,7 +148,7 @@ defmodule Plausible.Workers.SendEmailReportTest do
|
||||
week_ago = now |> Timex.shift(days: -7)
|
||||
two_weeks_ago = now |> Timex.shift(days: -14)
|
||||
|
||||
site = insert(:site, inserted_at: Timex.shift(now, days: -15))
|
||||
site = new_site(inserted_at: Timex.shift(now, days: -15))
|
||||
insert(:weekly_report, site: site, recipients: ["user@email.com"])
|
||||
|
||||
populate_stats(site, [
|
||||
@ -184,7 +183,7 @@ defmodule Plausible.Workers.SendEmailReportTest do
|
||||
week_ago = now |> Timex.shift(days: -7)
|
||||
two_weeks_ago = now |> Timex.shift(days: -14)
|
||||
|
||||
site = insert(:site, inserted_at: Timex.shift(now, days: -15))
|
||||
site = new_site(inserted_at: Timex.shift(now, days: -15))
|
||||
insert(:weekly_report, site: site, recipients: ["user@email.com"])
|
||||
|
||||
populate_stats(site, [
|
||||
@ -215,7 +214,7 @@ defmodule Plausible.Workers.SendEmailReportTest do
|
||||
|
||||
describe "monthly_reports" do
|
||||
test "sends monthly report to all recipients" do
|
||||
site = insert(:site, domain: "test-site.com", timezone: "US/Eastern")
|
||||
site = new_site(domain: "test-site.com", timezone: "US/Eastern")
|
||||
insert(:monthly_report, site: site, recipients: ["user@email.com", "user2@email.com"])
|
||||
|
||||
last_month =
|
||||
@ -238,7 +237,7 @@ defmodule Plausible.Workers.SendEmailReportTest do
|
||||
end
|
||||
|
||||
test "does not crash when monthly report has been deleted since scheduling job" do
|
||||
site = insert(:site, domain: "test-site.com", timezone: "US/Eastern")
|
||||
site = new_site(domain: "test-site.com", timezone: "US/Eastern")
|
||||
|
||||
assert :discard =
|
||||
perform_job(SendEmailReport, %{"site_id" => site.id, "interval" => "monthly"})
|
||||
|
@ -2,13 +2,14 @@ defmodule Plausible.Workers.SendSiteSetupEmailsTest do
|
||||
use Plausible.DataCase, async: true
|
||||
use Bamboo.Test
|
||||
use Oban.Testing, repo: Plausible.Repo
|
||||
use Plausible.Teams.Test
|
||||
|
||||
alias Plausible.Workers.SendSiteSetupEmails
|
||||
|
||||
describe "when user has not managed to set up the site" do
|
||||
test "does not send an email 47 hours after site creation" do
|
||||
user = insert(:user)
|
||||
insert(:site, members: [user], inserted_at: hours_ago(47))
|
||||
user = new_user()
|
||||
new_site(owner: user, inserted_at: hours_ago(47))
|
||||
|
||||
perform_job(SendSiteSetupEmails, %{})
|
||||
|
||||
@ -16,8 +17,8 @@ defmodule Plausible.Workers.SendSiteSetupEmailsTest do
|
||||
end
|
||||
|
||||
test "sends a setup help email 48 hours after site has been created" do
|
||||
user = insert(:user)
|
||||
insert(:site, members: [user], inserted_at: hours_ago(49))
|
||||
user = new_user()
|
||||
new_site(owner: user, inserted_at: hours_ago(49))
|
||||
|
||||
perform_job(SendSiteSetupEmails, %{})
|
||||
|
||||
@ -39,9 +40,8 @@ defmodule Plausible.Workers.SendSiteSetupEmailsTest do
|
||||
|
||||
describe "when user has managed to set up their site" do
|
||||
test "sends the setup completed email as soon as possible" do
|
||||
user = insert(:user)
|
||||
|
||||
site = insert(:site, members: [user])
|
||||
user = new_user()
|
||||
site = new_site(owner: user)
|
||||
|
||||
populate_stats(site, [build(:pageview)])
|
||||
|
||||
@ -54,8 +54,8 @@ defmodule Plausible.Workers.SendSiteSetupEmailsTest do
|
||||
end
|
||||
|
||||
test "sends the setup completed email after the help email has been sent" do
|
||||
user = insert(:user)
|
||||
site = insert(:site, members: [user], inserted_at: hours_ago(49))
|
||||
user = new_user()
|
||||
site = new_site(owner: user, inserted_at: hours_ago(49))
|
||||
|
||||
perform_job(SendSiteSetupEmails, %{})
|
||||
|
||||
@ -76,7 +76,7 @@ defmodule Plausible.Workers.SendSiteSetupEmailsTest do
|
||||
|
||||
describe "trial user who has not set up a website" do
|
||||
test "does not send an email before 48h have passed" do
|
||||
insert(:user, inserted_at: hours_ago(47))
|
||||
new_user(inserted_at: hours_ago(47))
|
||||
|
||||
perform_job(SendSiteSetupEmails, %{})
|
||||
|
||||
@ -84,7 +84,7 @@ defmodule Plausible.Workers.SendSiteSetupEmailsTest do
|
||||
end
|
||||
|
||||
test "sends the create site email after 48h" do
|
||||
user = insert(:user, inserted_at: hours_ago(49))
|
||||
user = new_user(inserted_at: hours_ago(49))
|
||||
|
||||
perform_job(SendSiteSetupEmails, %{})
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user