Switch reads in invitation creation logic to teams behind FF + loosely related fixes 🍌 (#4845)

* Reduce "choose plan" reliance on the old schema

* Fix team members usage computation on teams schema

* Switch CreateInvitation to reading from team schemas behind FF (WIP)

* Allow test-inviting one guest into multiple sites

* Convert another test case where team members count is wrong

cc @zoldar

* WIP: support site transfer notification e-mails

* Even more strict SiteTransfer fetching

* Make skipping permissions work

* Make CreateInvitation read from team schemas behind FF fully

* Fix passing options to `check_invitation_permissions`

* Fix allowance check for pageview usage for active or recently ended trial case

* Fix `check_invitation_permissions`

* Remove no longer relevant invite implementations for Teams

---------

Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
This commit is contained in:
hq1 2024-11-21 12:12:51 +01:00 committed by GitHub
parent 5072613c4f
commit 4d9ea15e9e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 387 additions and 427 deletions

View File

@ -6,7 +6,6 @@ defmodule Plausible.Site.Memberships.CreateInvitation do
alias Plausible.Auth.{User, Invitation} alias Plausible.Auth.{User, Invitation}
alias Plausible.{Site, Sites, Site.Membership} alias Plausible.{Site, Sites, Site.Membership}
alias Plausible.Site.Memberships.Invitations
alias Plausible.Billing.Quota alias Plausible.Billing.Quota
import Ecto.Query import Ecto.Query
use Plausible use Plausible
@ -73,24 +72,49 @@ defmodule Plausible.Site.Memberships.CreateInvitation do
attrs = %{email: invitee_email, role: role, site_id: site.id, inviter_id: inviter.id} attrs = %{email: invitee_email, role: role, site_id: site.id, inviter_id: inviter.id}
with site <- Plausible.Repo.preload(site, :owner), with site <- Plausible.Repo.preload(site, :owner),
:ok <- check_invitation_permissions(site, inviter, role, opts), :ok <-
:ok <- check_team_member_limit(site, role, invitee_email), Plausible.Teams.Adapter.Read.Invitations.check_invitation_permissions(
site,
inviter,
role,
opts
),
:ok <-
Plausible.Teams.Adapter.Read.Invitations.check_team_member_limit(
inviter,
site,
role,
invitee_email
),
invitee = Plausible.Auth.find_user_by(email: invitee_email), invitee = Plausible.Auth.find_user_by(email: invitee_email),
:ok <- Invitations.ensure_transfer_valid(site, invitee, role), :ok <-
:ok <- ensure_new_membership(site, invitee, role), Plausible.Teams.Adapter.Read.Invitations.ensure_transfer_valid(
inviter,
site,
invitee,
role
),
:ok <-
Plausible.Teams.Adapter.Read.Invitations.ensure_new_membership(
inviter,
site,
invitee,
role
),
%Ecto.Changeset{} = changeset <- Invitation.new(attrs), %Ecto.Changeset{} = changeset <- Invitation.new(attrs),
{:ok, invitation} <- Plausible.Repo.insert(changeset) do {:ok, invitation} <- Plausible.Repo.insert(changeset) do
send_invitation_email(invitation, invitee)
Plausible.Teams.Invitations.invite_sync(site, invitation) Plausible.Teams.Invitations.invite_sync(site, invitation)
Plausible.Teams.Adapter.Read.Invitations.send_invitation_email(inviter, invitation, invitee)
invitation invitation
else else
{:error, cause} -> Plausible.Repo.rollback(cause) {:error, cause} -> Plausible.Repo.rollback(cause)
end end
end end
defp check_invitation_permissions(site, inviter, requested_role, opts) do @doc false
def check_invitation_permissions(site, inviter, requested_role, opts) do
check_permissions? = Keyword.get(opts, :check_permissions, true) check_permissions? = Keyword.get(opts, :check_permissions, true)
if check_permissions? do if check_permissions? do
@ -107,7 +131,8 @@ defmodule Plausible.Site.Memberships.CreateInvitation do
end end
end end
defp send_invitation_email(invitation, invitee) do @doc false
def send_invitation_email(invitation, invitee) do
invitation = Plausible.Repo.preload(invitation, [:site, :inviter]) invitation = Plausible.Repo.preload(invitation, [:site, :inviter])
email = email =
@ -140,11 +165,12 @@ defmodule Plausible.Site.Memberships.CreateInvitation do
Plausible.Mailer.send(email) Plausible.Mailer.send(email)
end end
defp ensure_new_membership(_site, _invitee, :owner) do @doc false
def ensure_new_membership(_site, _invitee, :owner) do
:ok :ok
end end
defp ensure_new_membership(site, invitee, _role) do def ensure_new_membership(site, invitee, _role) do
if invitee && Sites.is_member?(invitee.id, site) do if invitee && Sites.is_member?(invitee.id, site) do
{:error, :already_a_member} {:error, :already_a_member}
else else
@ -152,11 +178,12 @@ defmodule Plausible.Site.Memberships.CreateInvitation do
end end
end end
defp check_team_member_limit(_site, :owner, _invitee_email) do @doc false
def check_team_member_limit(_site, :owner, _invitee_email) do
:ok :ok
end end
defp check_team_member_limit(site, _role, invitee_email) do def check_team_member_limit(site, _role, invitee_email) do
site = Plausible.Repo.preload(site, :owner) site = Plausible.Repo.preload(site, :owner)
limit = Quota.Limits.team_member_limit(site.owner) limit = Quota.Limits.team_member_limit(site.owner)
usage = Quota.Usage.team_member_usage(site.owner, exclude_emails: [invitee_email]) usage = Quota.Usage.team_member_usage(site.owner, exclude_emails: [invitee_email])

View File

@ -16,7 +16,9 @@ defmodule Plausible.Teams do
def on_trial?(team) do def on_trial?(team) do
team = with_subscription(team) team = with_subscription(team)
not Plausible.Billing.Subscriptions.active?(team.subscription) && trial_days_left(team) >= 0
not Plausible.Billing.Subscriptions.active?(team.subscription) &&
trial_days_left(team) >= 0
end end
else else
def on_trial?(_), do: true def on_trial?(_), do: true

View File

@ -4,6 +4,20 @@ defmodule Plausible.Teams.Adapter.Read.Billing do
""" """
use Plausible.Teams.Adapter use Plausible.Teams.Adapter
def quota_usage(user, opts \\ []) do
switch(user,
team_fn: &Plausible.Teams.Billing.quota_usage(&1, opts),
user_fn: &Plausible.Billing.Quota.Usage.usage(&1, opts)
)
end
def allow_next_upgrade_override?(user) do
switch(user,
team_fn: &(&1 && &1.allow_next_upgrade_override),
user_fn: & &1.allow_next_upgrade_override
)
end
def change_plan(user, new_plan_id) do def change_plan(user, new_plan_id) do
switch(user, switch(user,
team_fn: &Plausible.Teams.Billing.change_plan(&1, new_plan_id), team_fn: &Plausible.Teams.Billing.change_plan(&1, new_plan_id),

View File

@ -0,0 +1,120 @@
defmodule Plausible.Teams.Adapter.Read.Invitations do
@moduledoc """
Transition adapter for new schema reads
"""
use Plausible
use Plausible.Teams.Adapter
alias Plausible.Repo
def check_invitation_permissions(site, inviter, role, opts) do
switch(
inviter,
team_fn: fn _ ->
Plausible.Teams.Invitations.check_invitation_permissions(
site,
inviter,
role,
opts
)
end,
user_fn: fn _ ->
Plausible.Site.Memberships.CreateInvitation.check_invitation_permissions(
site,
inviter,
role,
opts
)
end
)
end
def check_team_member_limit(inviter, site, role, invitee_email) do
switch(
inviter,
team_fn: fn _ ->
site_team = Repo.preload(site, :team).team
Plausible.Teams.Invitations.check_team_member_limit(
site_team,
role,
invitee_email
)
end,
user_fn: fn _ ->
Plausible.Site.Memberships.CreateInvitation.check_team_member_limit(
site,
role,
invitee_email
)
end
)
end
def ensure_transfer_valid(inviter, site, invitee, role) do
switch(
inviter,
team_fn: fn _ ->
site_team = Repo.preload(site, :team).team
Plausible.Teams.Invitations.ensure_transfer_valid(
site_team,
invitee,
role
)
end,
user_fn: fn _ ->
Plausible.Site.Memberships.Invitations.ensure_transfer_valid(
site,
invitee,
role
)
end
)
end
def ensure_new_membership(inviter, site, invitee, role) do
switch(
inviter,
team_fn: fn _ ->
Plausible.Teams.Invitations.ensure_new_membership(
site,
invitee,
role
)
end,
user_fn: fn _ ->
Plausible.Site.Memberships.CreateInvitation.ensure_new_membership(
site,
invitee,
role
)
end
)
end
def send_invitation_email(inviter, invitation, invitee) do
switch(
inviter,
team_fn: fn _ ->
if invitation.role == :owner do
Teams.SiteTransfer
|> Repo.get_by!(transfer_id: invitation.invitation_id, initiator_id: inviter.id)
|> Repo.preload([:site, :initiator])
|> Plausible.Teams.Invitations.send_invitation_email(invitee)
else
Teams.GuestInvitation
|> Repo.get_by!(invitation_id: invitation.invitation_id)
|> Repo.preload([:site, team_invitation: :inviter])
|> Plausible.Teams.Invitations.send_invitation_email(invitee)
end
end,
user_fn: fn _ ->
Plausible.Site.Memberships.CreateInvitation.send_invitation_email(
invitation,
invitee
)
end
)
end
end

View File

@ -0,0 +1,27 @@
defmodule Plausible.Teams.Adapter.Read.Teams do
@moduledoc """
Transition adapter for new schema reads
"""
use Plausible.Teams.Adapter
def trial_expiry_date(user) do
switch(user,
team_fn: &(&1 && &1.trial_expiry_date),
user_fn: & &1.trial_expiry_date
)
end
def on_trial?(user) do
switch(user,
team_fn: &Plausible.Teams.on_trial?/1,
user_fn: &Plausible.Users.on_trial?/1
)
end
def trial_days_left(user) do
switch(user,
team_fn: &Plausible.Teams.trial_days_left/1,
user_fn: &Plausible.Users.trial_days_left/1
)
end
end

View File

@ -252,7 +252,9 @@ defmodule Plausible.Teams.Billing do
end end
def team_member_usage(team, opts) do def team_member_usage(team, opts) do
exclude_emails = Keyword.get(opts, :exclude_emails, []) {:ok, owner} = Teams.Sites.get_owner(team)
exclude_emails = Keyword.get(opts, :exclude_emails, []) ++ [owner.email]
pending_site_ids = Keyword.get(opts, :pending_ownership_site_ids, []) pending_site_ids = Keyword.get(opts, :pending_ownership_site_ids, [])
team team
@ -320,7 +322,7 @@ defmodule Plausible.Teams.Billing do
} }
end end
def features_usage(user, site_ids \\ nil) def features_usage(team, site_ids \\ nil)
def features_usage(%Teams.Team{} = team, nil) do def features_usage(%Teams.Team{} = team, nil) do
owned_site_ids = team |> Teams.owned_sites() |> Enum.map(& &1.id) owned_site_ids = team |> Teams.owned_sites() |> Enum.map(& &1.id)
@ -331,8 +333,16 @@ defmodule Plausible.Teams.Billing do
site_scoped_feature_usage = features_usage(nil, owned_site_ids) site_scoped_feature_usage = features_usage(nil, owned_site_ids)
stats_api_used? = stats_api_used? =
from(a in Plausible.Auth.ApiKey, where: a.team_id == ^team.id) Plausible.Repo.exists?(
|> Plausible.Repo.exists?() from tm in Plausible.Teams.Membership,
as: :team_membership,
where: tm.team_id == ^team.id,
where:
exists(
from ak in Plausible.Auth.ApiKey,
where: ak.user_id == parent_as(:team_membership).user_id
)
)
if stats_api_used? do if stats_api_used? do
site_scoped_feature_usage ++ [Feature.StatsAPI] site_scoped_feature_usage ++ [Feature.StatsAPI]
@ -345,36 +355,47 @@ defmodule Plausible.Teams.Billing do
Plausible.Billing.Quota.Usage.features_usage(nil, owned_site_ids) Plausible.Billing.Quota.Usage.features_usage(nil, owned_site_ids)
end end
defp query_team_member_emails(team, site_ids, exclude_emails) do defp query_team_member_emails(team, pending_ownership_site_ids, exclude_emails) do
pending_owner_memberships_q =
from s in Plausible.Site,
inner_join: t in assoc(s, :team),
inner_join: tm in assoc(t, :team_memberships),
inner_join: u in assoc(tm, :user),
where: s.id in ^pending_ownership_site_ids,
where: tm.role == :owner,
where: u.email not in ^exclude_emails,
select: %{email: u.email}
pending_memberships_q = pending_memberships_q =
from tm in Teams.Membership, from tm in Teams.Membership,
inner_join: u in assoc(tm, :user), inner_join: u in assoc(tm, :user),
inner_join: gm in assoc(tm, :guest_memberships), left_join: gm in assoc(tm, :guest_memberships),
where: gm.site_id in ^site_ids and tm.role != :owner, where: gm.site_id in ^pending_ownership_site_ids,
where: u.email not in ^exclude_emails, where: u.email not in ^exclude_emails,
select: %{email: u.email} select: %{email: u.email}
pending_invitations_q = pending_invitations_q =
from ti in Teams.Invitation, from ti in Teams.Invitation,
inner_join: gi in assoc(ti, :guest_invitations), inner_join: gi in assoc(ti, :guest_invitations),
where: gi.site_id in ^site_ids and ti.role != :owner, where: gi.site_id in ^pending_ownership_site_ids,
where: ti.email not in ^exclude_emails, where: ti.email not in ^exclude_emails,
select: %{email: ti.email} select: %{email: ti.email}
team_memberships_q = team_memberships_q =
from tm in Teams.Membership, from tm in Teams.Membership,
inner_join: u in assoc(tm, :user), inner_join: u in assoc(tm, :user),
where: tm.team_id == ^team.id and tm.role != :owner, where: tm.team_id == ^team.id,
where: u.email not in ^exclude_emails, where: u.email not in ^exclude_emails,
select: %{email: u.email} select: %{email: u.email}
team_invitations_q = team_invitations_q =
from ti in Teams.Invitation, from ti in Teams.Invitation,
where: ti.team_id == ^team.id and ti.role != :owner, where: ti.team_id == ^team.id,
where: ti.email not in ^exclude_emails, where: ti.email not in ^exclude_emails,
select: %{email: ti.email} select: %{email: ti.email}
pending_memberships_q pending_memberships_q
|> union(^pending_owner_memberships_q)
|> union(^pending_invitations_q) |> union(^pending_invitations_q)
|> union(^team_memberships_q) |> union(^team_memberships_q)
|> union(^team_invitations_q) |> union(^team_invitations_q)

View File

@ -3,41 +3,10 @@ defmodule Plausible.Teams.Invitations do
import Ecto.Query import Ecto.Query
alias Plausible.Auth
alias Plausible.Billing alias Plausible.Billing
alias Plausible.Repo alias Plausible.Repo
alias Plausible.Teams alias Plausible.Teams
def invite(site, inviter, invitee_email, role, opts \\ [])
def invite(site, initiator, invitee_email, :owner, opts) do
check_permissions? = opts[:check_permissions]
site = Repo.preload(site, :team)
with :ok <- check_transfer_permissions(site.team, initiator, check_permissions?),
new_owner = Plausible.Auth.find_user_by(email: invitee_email),
:ok <- ensure_transfer_valid(site.team, new_owner),
{:ok, site_transfer} <- create_site_transfer(site, initiator, invitee_email) do
send_transfer_init_email(site_transfer, new_owner)
{:ok, site_transfer}
end
end
def invite(site, inviter, invitee_email, role, opts) do
check_permissions? = opts[:check_permissions]
site = Repo.preload(site, :team)
role = translate_role(role)
with :ok <- check_invitation_permissions(site.team, inviter, check_permissions?),
:ok <- check_team_member_limit(site.team, role, invitee_email),
invitee = Auth.find_user_by(email: invitee_email),
:ok <- ensure_new_membership(site, invitee, role),
{:ok, guest_invitation} <- create_invitation(site, invitee_email, role, inviter) do
send_invitation_email(guest_invitation, invitee)
{:ok, guest_invitation}
end
end
def invite_sync(site, site_invitation) do def invite_sync(site, site_invitation) do
site = Teams.load_for_site(site) site = Teams.load_for_site(site)
site_invitation = Repo.preload(site_invitation, :inviter) site_invitation = Repo.preload(site_invitation, :inviter)
@ -97,31 +66,6 @@ defmodule Plausible.Teams.Invitations do
:ok :ok
end end
def transfer_site(site, new_owner, now \\ NaiveDateTime.utc_now(:second)) do
site = Repo.preload(site, :team)
with :ok <- ensure_transfer_valid(site.team, new_owner),
{:ok, team} <- Teams.get_or_create(new_owner),
:ok <- ensure_can_take_ownership(site, team) do
site =
Repo.preload(site, [
:team,
:owner,
guest_memberships: [team_membership: :user],
guest_invitations: :team_invitation
])
{:ok, _} =
Repo.transaction(fn ->
:ok = transfer_site_ownership(site, team, now)
end)
{:ok, team_membership} = Teams.Memberships.get(team, new_owner)
{:ok, team_membership}
end
end
def transfer_site_sync(site, user) do def transfer_site_sync(site, user) do
{:ok, team} = Teams.get_or_create(user) {:ok, team} = Teams.get_or_create(user)
site = Teams.load_for_site(site) site = Teams.load_for_site(site)
@ -219,26 +163,29 @@ defmodule Plausible.Teams.Invitations do
end) end)
end end
defp check_transfer_permissions(_team, _initiator, false = _check_permissions?) do def check_transfer_permissions(_team, _initiator, false = _check_permissions?) do
:ok :ok
end end
defp check_transfer_permissions(team, initiator, _) do def check_transfer_permissions(team, initiator, _) do
case Teams.Memberships.team_role(team, initiator) do case Teams.Memberships.team_role(team, initiator) do
{:ok, :owner} -> :ok {:ok, :owner} -> :ok
_ -> {:error, :forbidden} _ -> {:error, :forbidden}
end end
end end
defp ensure_transfer_valid(_team, nil), do: :ok @doc false
def ensure_transfer_valid(_team, nil, :owner), do: :ok
defp ensure_transfer_valid(team, new_owner) do def ensure_transfer_valid(team, new_owner, :owner) do
case Teams.Memberships.team_role(team, new_owner) do case Teams.Memberships.team_role(team, new_owner) do
{:ok, :owner} -> {:error, :transfer_to_self} {:ok, :owner} -> {:error, :transfer_to_self}
_ -> :ok _ -> :ok
end end
end end
def ensure_transfer_valid(_team, _new_owner, _role), do: :ok
defp create_site_transfer(site, initiator, invitee_email, now \\ NaiveDateTime.utc_now(:second)) do defp create_site_transfer(site, initiator, invitee_email, now \\ NaiveDateTime.utc_now(:second)) do
site site
|> Teams.SiteTransfer.changeset(initiator: initiator, email: invitee_email) |> Teams.SiteTransfer.changeset(initiator: initiator, email: invitee_email)
@ -249,7 +196,7 @@ defmodule Plausible.Teams.Invitations do
) )
end end
defp send_transfer_init_email(site_transfer, new_owner) do def send_transfer_init_email(site_transfer, new_owner) do
email = email =
PlausibleWeb.Email.ownership_transfer_request( PlausibleWeb.Email.ownership_transfer_request(
site_transfer.email, site_transfer.email,
@ -296,7 +243,7 @@ defmodule Plausible.Teams.Invitations do
# - remove old guest memberships # - remove old guest memberships
site_transfer = Repo.preload(site_transfer, [:initiator, site: :team]) site_transfer = Repo.preload(site_transfer, [:initiator, site: :team])
with :ok <- ensure_transfer_valid(site_transfer.site.team, new_owner), with :ok <- ensure_transfer_valid(site_transfer.site.team, new_owner, :owner),
{:ok, team} <- Teams.get_or_create(new_owner), {:ok, team} <- Teams.get_or_create(new_owner),
:ok <- ensure_can_take_ownership(site_transfer.site, team) do :ok <- ensure_can_take_ownership(site_transfer.site, team) do
site = Repo.preload(site_transfer.site, guest_memberships: [team_membership: :user]) site = Repo.preload(site_transfer.site, guest_memberships: [team_membership: :user])
@ -465,21 +412,34 @@ defmodule Plausible.Teams.Invitations do
end end
end end
defp check_invitation_permissions(_team, _inviter, false = _check_permission?) do @doc false
:ok def check_invitation_permissions(site, inviter, invitation_role, opts) do
end check_permissions? = Keyword.get(opts, :check_permissions, true)
defp check_invitation_permissions(team, inviter, _) do if check_permissions? do
case Teams.Memberships.team_role(team, inviter) do case Teams.Memberships.site_role(site, inviter) do
{:ok, role} when role in [:owner, :admin] -> :ok {:ok, :owner} when invitation_role == :owner ->
_ -> {:error, :forbidden} :ok
{:ok, inviter_role}
when inviter_role in [:owner, :editor, :admin] and invitation_role != :owner ->
:ok
_ ->
{:error, :forbidden}
end
else
:ok
end end
end end
defp translate_role(:admin), do: :editor defp translate_role(:admin), do: :editor
defp translate_role(role), do: role defp translate_role(role), do: role
defp check_team_member_limit(team, _role, invitee_email) do @doc false
def check_team_member_limit(_team, :owner, _invitee_email), do: :ok
def check_team_member_limit(team, _role, invitee_email) do
limit = Teams.Billing.team_member_limit(team) limit = Teams.Billing.team_member_limit(team)
usage = Teams.Billing.team_member_usage(team, exclude_emails: [invitee_email]) usage = Teams.Billing.team_member_usage(team, exclude_emails: [invitee_email])
@ -490,9 +450,12 @@ defmodule Plausible.Teams.Invitations do
end end
end end
defp ensure_new_membership(_site, nil, _role), do: :ok @doc false
def ensure_new_membership(_site, nil, _role), do: :ok
defp ensure_new_membership(site, invitee, _role) do def ensure_new_membership(_site, _invitee, :owner), do: :ok
def ensure_new_membership(site, invitee, _role) do
if Teams.Memberships.site_role(site, invitee) == {:error, :not_a_member} do if Teams.Memberships.site_role(site, invitee) == {:error, :not_a_member} do
:ok :ok
else else
@ -535,7 +498,21 @@ defmodule Plausible.Teams.Invitations do
) )
end end
defp send_invitation_email(guest_invitation, invitee) do @doc false
def send_invitation_email(%Teams.SiteTransfer{} = transfer, invitee) do
email =
PlausibleWeb.Email.ownership_transfer_request(
transfer.email,
transfer.transfer_id,
transfer.site,
transfer.initiator,
invitee
)
Plausible.Mailer.send(email)
end
def send_invitation_email(%Teams.GuestInvitation{} = guest_invitation, invitee) do
team_invitation = guest_invitation.team_invitation team_invitation = guest_invitation.team_invitation
email = email =

View File

@ -174,7 +174,8 @@ defmodule PlausibleWeb.Components.Billing.PlanBox do
paddle_product_id = get_paddle_product_id(assigns.plan_to_render, assigns.selected_interval) paddle_product_id = get_paddle_product_id(assigns.plan_to_render, assigns.selected_interval)
change_plan_link_text = change_plan_link_text(assigns) change_plan_link_text = change_plan_link_text(assigns)
subscription = assigns.current_user.subscription subscription =
Plausible.Teams.Adapter.Read.Billing.get_subscription(assigns.current_user)
billing_details_expired = billing_details_expired =
Subscription.Status.in?(subscription, [ Subscription.Status.in?(subscription, [
@ -270,15 +271,15 @@ defmodule PlausibleWeb.Components.Billing.PlanBox do
# because in the past we've let users upgrade without that constraint, as # because in the past we've let users upgrade without that constraint, as
# well as transfer sites to those accounts. to these accounts we won't be # well as transfer sites to those accounts. to these accounts we won't be
# offering an extra pageview limit allowance margin though. # offering an extra pageview limit allowance margin though.
invited_user? = is_nil(current_user.trial_expiry_date) invited_user? = is_nil(Plausible.Teams.Adapter.Read.Teams.trial_expiry_date(current_user))
trial_active_or_ended_recently? = trial_active_or_ended_recently? =
not invited_user? && not invited_user? &&
Date.diff(Date.utc_today(), current_user.trial_expiry_date) <= 10 Plausible.Teams.Adapter.Read.Teams.trial_days_left(current_user) >= -10
limit_checking_opts = limit_checking_opts =
cond do cond do
current_user.allow_next_upgrade_override -> Plausible.Teams.Adapter.Read.Billing.allow_next_upgrade_override?(current_user) ->
[ignore_pageview_limit: true] [ignore_pageview_limit: true]
trial_active_or_ended_recently? && plan.volume == "10k" -> trial_active_or_ended_recently? && plan.volume == "10k" ->

View File

@ -29,8 +29,8 @@ defmodule PlausibleWeb.Site.MembershipController do
|> Plausible.Teams.Adapter.Read.Sites.get_for_user!(conn.assigns.site.domain) |> Plausible.Teams.Adapter.Read.Sites.get_for_user!(conn.assigns.site.domain)
|> Plausible.Repo.preload(:owner) |> Plausible.Repo.preload(:owner)
limit = Plausible.Billing.Quota.Limits.team_member_limit(site.owner) limit = Plausible.Teams.Adapter.Read.Billing.team_member_limit(site.owner)
usage = Plausible.Billing.Quota.Usage.team_member_usage(site.owner) usage = Plausible.Teams.Adapter.Read.Billing.team_member_usage(site.owner)
below_limit? = Plausible.Billing.Quota.below_limit?(usage, limit) below_limit? = Plausible.Billing.Quota.below_limit?(usage, limit)
render( render(

View File

@ -25,7 +25,7 @@ defmodule PlausibleWeb.Live.ChoosePlan do
current_user: current_user, current_user: current_user,
pending_ownership_site_ids: pending_ownership_site_ids pending_ownership_site_ids: pending_ownership_site_ids
} -> } ->
Quota.Usage.usage(current_user, Plausible.Teams.Adapter.Read.Billing.quota_usage(current_user,
with_features: true, with_features: true,
pending_ownership_site_ids: pending_ownership_site_ids pending_ownership_site_ids: pending_ownership_site_ids
) )

View File

@ -1,6 +1,7 @@
defmodule Plausible.Site.AdminTest do defmodule Plausible.Site.AdminTest do
use Plausible use Plausible
use Plausible.DataCase, async: true use Plausible.DataCase, async: true
use Plausible.Teams.Test
use Bamboo.Test use Bamboo.Test
@subject_prefix if ee?(), do: "[Plausible Analytics] ", else: "[Plausible CE] " @subject_prefix if ee?(), do: "[Plausible Analytics] ", else: "[Plausible CE] "
@ -38,9 +39,8 @@ defmodule Plausible.Site.AdminTest do
end end
test "new owner can't be the same as old owner", %{conn: conn, transfer_action: action} do test "new owner can't be the same as old owner", %{conn: conn, transfer_action: action} do
current_owner = insert(:user) current_owner = new_user()
site = new_site(owner: current_owner)
site = insert(:site, members: [current_owner])
assert {:error, "User is already an owner of one of the sites"} = assert {:error, "User is already an owner of one of the sites"} =
action.(conn, [site], %{"email" => current_owner.email}) action.(conn, [site], %{"email" => current_owner.email})
@ -50,14 +50,10 @@ defmodule Plausible.Site.AdminTest do
conn: conn, conn: conn,
transfer_action: action transfer_action: action
} do } do
current_owner = insert(:user) current_owner = new_user()
new_owner = insert(:user) new_owner = new_user()
site1 = new_site(owner: current_owner)
site1 = site2 = new_site(owner: current_owner)
insert(:site, memberships: [build(:site_membership, user: current_owner, role: :owner)])
site2 =
insert(:site, memberships: [build(:site_membership, user: current_owner, role: :owner)])
assert :ok = action.(conn, [site1, site2], %{"email" => new_owner.email}) assert :ok = action.(conn, [site1, site2], %{"email" => new_owner.email})

View File

@ -78,64 +78,6 @@ defmodule Plausible.Site.Memberships.AcceptInvitationTest do
assert_guest_membership(team, site, existing_owner, :editor) assert_guest_membership(team, site, existing_owner, :editor)
end end
@tag :teams
test "transfers ownership successfully (TEAM)" do
site = insert(:site, memberships: [])
existing_owner = insert(:user)
_existing_membership =
insert(:site_membership, user: existing_owner, site: site, role: :owner)
site = Plausible.Teams.load_for_site(site)
old_team = site.team
another_user = insert(:user)
another_team_membership =
insert(:team_membership, user: another_user, team: old_team, role: :guest)
another_guest_membership =
insert(:guest_membership,
team_membership: another_team_membership,
site: site,
role: :viewer
)
new_owner = insert(:user)
new_team = insert(:team)
insert(:team_membership, user: new_owner, team: new_team, role: :owner)
insert(:growth_subscription, user: new_owner, team: new_team)
assert {:ok, new_team_membership} =
Plausible.Teams.Invitations.transfer_site(site, new_owner)
assert new_team_membership.team_id == new_team.id
assert new_team_membership.user_id == new_owner.id
assert new_team_membership.role == :owner
assert_team_membership(existing_owner, old_team)
refute Repo.reload(another_team_membership)
refute Repo.reload(another_guest_membership)
assert new_another_team_membership =
Plausible.Teams.Membership
|> Repo.get_by(
team_id: new_team.id,
user_id: another_user.id
)
|> Repo.preload(:guest_memberships)
assert another_team_membership.id != new_another_team_membership.id
assert [new_another_guest_membership] = new_another_team_membership.guest_memberships
assert new_another_guest_membership.site_id == site.id
assert new_another_guest_membership.role == another_guest_membership.role
assert new_another_team_membership.role == :guest
assert_no_emails_delivered()
end
@tag :ee_only @tag :ee_only
test "unlocks the site if it was previously locked" do test "unlocks the site if it was previously locked" do
site = insert(:site, locked: true, memberships: []) site = insert(:site, locked: true, memberships: [])

View File

@ -9,137 +9,38 @@ defmodule Plausible.Site.Memberships.CreateInvitationTest do
describe "create_invitation/4" do describe "create_invitation/4" do
test "creates an invitation" do test "creates an invitation" do
inviter = insert(:user) inviter = new_user()
invitee = insert(:user) invitee = new_user()
team = insert(:team) site = new_site(owner: inviter)
site =
insert(:site,
team: team,
memberships: [build(:site_membership, user: inviter, role: :owner)]
)
insert(:team_membership, team: team, user: inviter, role: :owner)
assert {:ok, %Plausible.Auth.Invitation{}} = assert {:ok, %Plausible.Auth.Invitation{}} =
CreateInvitation.create_invitation(site, inviter, invitee.email, :viewer) CreateInvitation.create_invitation(site, inviter, invitee.email, :viewer)
assert {:ok, %Plausible.Teams.GuestInvitation{}} =
Plausible.Teams.Invitations.invite(site, inviter, invitee.email, :viewer)
end
@tag :teams
test "[TEAMS] syncs a created invitation" do
inviter = insert(:user)
invitee = insert(:user)
site =
insert(:site,
team: nil,
memberships: [build(:site_membership, user: inviter, role: :owner)]
)
assert {:ok, %Plausible.Auth.Invitation{}} =
CreateInvitation.create_invitation(site, inviter, invitee.email, :viewer)
team = assert_team_attached(site)
assert_guest_invitation(team, site, invitee.email, :viewer)
end
@tag :teams
test "[TEAMS] sync a created invitation with team already setup but site not assigned yet" do
inviter = insert(:user)
invitee = insert(:user)
{:ok, %{id: team_id}} = Plausible.Teams.get_or_create(inviter)
site =
insert(:site,
team: nil,
memberships: [build(:site_membership, user: inviter, role: :owner)]
)
assert {:ok, %Plausible.Auth.Invitation{}} =
CreateInvitation.create_invitation(site, inviter, invitee.email, :viewer)
team = assert_team_attached(site, team_id)
assert_guest_invitation(team, site, invitee.email, :viewer)
end
@tag :teams
test "[TEAMS] sync a created invitation with team fully setup" do
inviter = insert(:user)
invitee = insert(:user)
{:ok, %{id: team_id} = team} = Plausible.Teams.get_or_create(inviter)
site =
insert(:site,
team: team,
memberships: [build(:site_membership, user: inviter, role: :owner)]
)
assert {:ok, %Plausible.Auth.Invitation{}} =
CreateInvitation.create_invitation(site, inviter, invitee.email, :viewer)
team = assert_team_attached(site, team_id)
assert_guest_invitation(team, site, invitee.email, :viewer)
end end
test "returns validation errors" do test "returns validation errors" do
inviter = insert(:user) inviter = new_user()
team = insert(:team) site = new_site(owner: inviter)
site =
insert(:site,
team: team,
memberships: [build(:site_membership, user: inviter, role: :owner)]
)
insert(:team_membership, team: team, user: inviter, role: :owner)
assert {:error, changeset} = CreateInvitation.create_invitation(site, inviter, "", :viewer) assert {:error, changeset} = CreateInvitation.create_invitation(site, inviter, "", :viewer)
assert {"can't be blank", _} = changeset.errors[:email] assert {"can't be blank", _} = changeset.errors[:email]
assert {:error, changeset} = Plausible.Teams.Invitations.invite(site, inviter, "", :viewer)
assert {"can't be blank", _} = changeset.errors[:email]
end end
test "returns error when user is already a member" do test "returns error when user is already a member" do
inviter = insert(:user) inviter = new_user()
invitee = insert(:user) invitee = new_user()
site = new_site(owner: inviter)
team = insert(:team) add_guest(site, user: invitee, role: :viewer)
site =
insert(:site,
team: team,
memberships: [
build(:site_membership, user: inviter, role: :owner),
build(:site_membership, user: invitee, role: :viewer)
]
)
insert(:team_membership, team: team, user: inviter, role: :owner)
team_membership = insert(:team_membership, team: team, user: invitee, role: :guest)
insert(:guest_membership, team_membership: team_membership, site: site, role: :viewer)
assert {:error, :already_a_member} = assert {:error, :already_a_member} =
CreateInvitation.create_invitation(site, inviter, invitee.email, :viewer) CreateInvitation.create_invitation(site, inviter, invitee.email, :viewer)
assert {:error, :already_a_member} =
Plausible.Teams.Invitations.invite(site, inviter, invitee.email, :viewer)
assert {:error, :already_a_member} = assert {:error, :already_a_member} =
CreateInvitation.create_invitation(site, inviter, inviter.email, :viewer) CreateInvitation.create_invitation(site, inviter, inviter.email, :viewer)
assert {:error, :already_a_member} =
Plausible.Teams.Invitations.invite(site, inviter, inviter.email, :viewer)
end end
test "sends invitation email for existing users" do test "sends invitation email for existing users" do
[inviter, invitee] = insert_list(2, :user) [inviter, invitee] = for _ <- 1..2, do: new_user()
site = insert(:site, memberships: [build(:site_membership, user: inviter, role: :owner)]) site = new_site(owner: inviter)
assert {:ok, %Plausible.Auth.Invitation{}} = assert {:ok, %Plausible.Auth.Invitation{}} =
CreateInvitation.create_invitation(site, inviter, invitee.email, :viewer) CreateInvitation.create_invitation(site, inviter, invitee.email, :viewer)
@ -151,8 +52,8 @@ defmodule Plausible.Site.Memberships.CreateInvitationTest do
end end
test "sends invitation email for new users" do test "sends invitation email for new users" do
inviter = insert(:user) inviter = new_user()
site = insert(:site, memberships: [build(:site_membership, user: inviter, role: :owner)]) site = new_site(owner: inviter)
assert {:ok, %Plausible.Auth.Invitation{}} = assert {:ok, %Plausible.Auth.Invitation{}} =
CreateInvitation.create_invitation(site, inviter, "vini@plausible.test", :viewer) CreateInvitation.create_invitation(site, inviter, "vini@plausible.test", :viewer)
@ -165,15 +66,11 @@ defmodule Plausible.Site.Memberships.CreateInvitationTest do
@tag :ee_only @tag :ee_only
test "returns error when owner is over their team member limit" do test "returns error when owner is over their team member limit" do
[owner, inviter, invitee] = insert_list(3, :user) [owner, inviter, invitee] = for _ <- 1..3, do: new_user()
memberships = site = new_site(owner: owner)
[ inviter = add_guest(site, user: inviter, role: :editor)
build(:site_membership, user: owner, role: :owner), for _ <- 1..4, do: add_guest(site, role: :viewer)
build(:site_membership, user: inviter, role: :admin)
] ++ build_list(4, :site_membership)
site = insert(:site, memberships: memberships)
assert {:error, {:over_limit, 3}} = assert {:error, {:over_limit, 3}} =
CreateInvitation.create_invitation(site, inviter, invitee.email, :viewer) CreateInvitation.create_invitation(site, inviter, invitee.email, :viewer)
@ -181,14 +78,8 @@ defmodule Plausible.Site.Memberships.CreateInvitationTest do
@tag :ee_only @tag :ee_only
test "allows inviting users who were already invited to other sites, within the limit" do test "allows inviting users who were already invited to other sites, within the limit" do
owner = insert(:user) owner = new_user()
site = new_site(owner: owner)
memberships =
[
build(:site_membership, user: owner, role: :owner)
]
site = insert(:site, memberships: memberships)
invite = fn site, email -> invite = fn site, email ->
CreateInvitation.create_invitation(site, owner, email, :viewer) CreateInvitation.create_invitation(site, owner, email, :viewer)
@ -199,28 +90,24 @@ defmodule Plausible.Site.Memberships.CreateInvitationTest do
assert {:ok, _} = invite.(site, "i3@example.com") assert {:ok, _} = invite.(site, "i3@example.com")
assert {:error, {:over_limit, 3}} = invite.(site, "i4@example.com") assert {:error, {:over_limit, 3}} = invite.(site, "i4@example.com")
site2 = insert(:site, memberships: memberships) site2 = new_site(owner: owner)
assert {:ok, _} = invite.(site2, "i3@example.com") assert {:ok, _} = invite.(site2, "i3@example.com")
end end
import Ecto.Query
@tag :ee_only @tag :ee_only
test "allows inviting users who are already members of other sites, within the limit" do test "allows inviting users who are already members of other sites, within the limit" do
[u1, u2, u3, u4] = insert_list(4, :user) [u1, u2, u3, u4] = for _ <- 1..4, do: new_user()
site = new_site(owner: u1)
add_guest(site, user: u2, role: :viewer)
add_guest(site, user: u3, role: :viewer)
add_guest(site, user: u4, role: :viewer)
memberships = site2 = new_site(owner: u1)
[ add_guest(site2, user: u2, role: :viewer)
build(:site_membership, user: u1, role: :owner), add_guest(site2, user: u3, role: :viewer)
build(:site_membership, user: u2, role: :viewer),
build(:site_membership, user: u3, role: :viewer)
]
site =
insert(:site,
memberships: memberships ++ [build(:site_membership, user: u4, role: :viewer)]
)
site2 = insert(:site, memberships: memberships)
invite = fn site, email -> invite = fn site, email ->
CreateInvitation.create_invitation(site, u1, email, :viewer) CreateInvitation.create_invitation(site, u1, email, :viewer)
@ -232,8 +119,8 @@ defmodule Plausible.Site.Memberships.CreateInvitationTest do
end end
test "sends ownership transfer email when invitation role is owner" do test "sends ownership transfer email when invitation role is owner" do
inviter = insert(:user) inviter = new_user()
site = insert(:site, memberships: [build(:site_membership, user: inviter, role: :owner)]) site = new_site(owner: inviter)
assert {:ok, %Plausible.Auth.Invitation{}} = assert {:ok, %Plausible.Auth.Invitation{}} =
CreateInvitation.create_invitation(site, inviter, "vini@plausible.test", :owner) CreateInvitation.create_invitation(site, inviter, "vini@plausible.test", :owner)
@ -245,68 +132,37 @@ defmodule Plausible.Site.Memberships.CreateInvitationTest do
end end
test "only allows owners to transfer ownership" do test "only allows owners to transfer ownership" do
inviter = insert(:user) inviter = new_user()
site = site = new_site()
insert(:site, add_guest(site, user: inviter, role: :editor)
memberships: [
build(:site_membership, user: build(:user), role: :owner),
build(:site_membership, user: inviter, role: :admin)
]
)
assert {:error, :forbidden} = assert {:error, :forbidden} =
CreateInvitation.create_invitation(site, inviter, "vini@plausible.test", :owner) CreateInvitation.create_invitation(site, inviter, "vini@plausible.test", :owner)
end end
test "allows ownership transfer to existing site members" do test "allows ownership transfer to existing site members" do
inviter = insert(:user) inviter = new_user()
invitee = insert(:user) invitee = new_user()
site = new_site(owner: inviter)
site = add_guest(site, user: invitee, role: :viewer)
insert(:site,
memberships: [
build(:site_membership, user: inviter, role: :owner),
build(:site_membership, user: invitee, role: :viewer)
]
)
|> Plausible.Teams.load_for_site()
insert(:team_membership, team: site.team, user: invitee, role: :viewer)
assert {:ok, %Plausible.Auth.Invitation{}} = assert {:ok, %Plausible.Auth.Invitation{}} =
CreateInvitation.create_invitation(site, inviter, invitee.email, :owner) CreateInvitation.create_invitation(site, inviter, invitee.email, :owner)
assert {:ok, %Plausible.Teams.SiteTransfer{}} =
Plausible.Teams.Invitations.invite(site, inviter, invitee.email, :owner)
end end
test "does not allow transferring ownership to existing owner" do test "does not allow transferring ownership to existing owner" do
inviter = insert(:user, email: "vini@plausible.test") inviter = new_user(email: "vini@plausible.test")
site = new_site(owner: inviter)
site =
insert(:site,
memberships: [
build(:site_membership, user: inviter, role: :owner)
]
)
site = Plausible.Teams.load_for_site(site)
assert {:error, :transfer_to_self} = assert {:error, :transfer_to_self} =
CreateInvitation.create_invitation(site, inviter, "vini@plausible.test", :owner) CreateInvitation.create_invitation(site, inviter, "vini@plausible.test", :owner)
assert {:error, :transfer_to_self} =
Plausible.Teams.Invitations.invite(site, inviter, "vini@plausible.test", :owner)
end end
test "allows creating an ownership transfer even when at team member limit" do test "allows creating an ownership transfer even when at team member limit" do
inviter = insert(:user) inviter = new_user()
site = new_site(owner: inviter)
memberships = for _ <- 1..3, do: add_guest(site, role: :viewer)
[build(:site_membership, user: inviter, role: :owner)] ++ build_list(3, :site_membership)
site = insert(:site, memberships: memberships)
assert {:ok, _invitation} = assert {:ok, _invitation} =
CreateInvitation.create_invitation( CreateInvitation.create_invitation(
@ -318,37 +174,19 @@ defmodule Plausible.Site.Memberships.CreateInvitationTest do
end end
test "does not allow viewers to invite users" do test "does not allow viewers to invite users" do
inviter = insert(:user) inviter = new_user()
owner = insert(:user) owner = new_user()
site = new_site(owner: owner)
site = add_guest(site, user: inviter, role: :viewer)
insert(:site,
memberships: [
build(:site_membership, user: owner, role: :owner),
build(:site_membership, user: inviter, role: :viewer)
]
)
|> Plausible.Teams.load_for_site()
insert(:team_membership, team: site.team, user: inviter, role: :viewer)
assert {:error, :forbidden} = assert {:error, :forbidden} =
CreateInvitation.create_invitation(site, inviter, "vini@plausible.test", :viewer) CreateInvitation.create_invitation(site, inviter, "vini@plausible.test", :viewer)
assert {:error, :forbidden} =
Plausible.Teams.Invitations.invite(site, inviter, "vini@plausible.test", :viewer)
end end
test "allows admins to invite other admins" do test "allows admins to invite other admins" do
inviter = insert(:user) inviter = new_user()
site = new_site()
site = add_guest(site, user: inviter, role: :editor)
insert(:site,
memberships: [
build(:site_membership, user: build(:user), role: :owner),
build(:site_membership, user: inviter, role: :admin)
]
)
assert {:ok, %Plausible.Auth.Invitation{}} = assert {:ok, %Plausible.Auth.Invitation{}} =
CreateInvitation.create_invitation(site, inviter, "vini@plausible.test", :admin) CreateInvitation.create_invitation(site, inviter, "vini@plausible.test", :admin)
@ -357,14 +195,11 @@ defmodule Plausible.Site.Memberships.CreateInvitationTest do
describe "bulk_create_invitation/5" do describe "bulk_create_invitation/5" do
test "initiates ownership transfer for multiple sites in one action" do test "initiates ownership transfer for multiple sites in one action" do
admin_user = insert(:user) admin_user = new_user()
new_owner = insert(:user) new_owner = new_user()
site1 = site1 = new_site(owner: admin_user)
insert(:site, memberships: [build(:site_membership, user: admin_user, role: :owner)]) site2 = new_site(owner: admin_user)
site2 =
insert(:site, memberships: [build(:site_membership, user: admin_user, role: :owner)])
assert {:ok, _} = assert {:ok, _} =
CreateInvitation.bulk_create_invitation( CreateInvitation.bulk_create_invitation(
@ -397,11 +232,11 @@ defmodule Plausible.Site.Memberships.CreateInvitationTest do
end end
test "initiates ownership transfer for multiple sites in one action skipping permission checks" do test "initiates ownership transfer for multiple sites in one action skipping permission checks" do
superadmin_user = insert(:user) superadmin_user = new_user()
new_owner = insert(:user) new_owner = new_user()
site1 = insert(:site) site1 = new_site()
site2 = insert(:site) site2 = new_site()
assert {:ok, _} = assert {:ok, _} =
CreateInvitation.bulk_create_invitation( CreateInvitation.bulk_create_invitation(

View File

@ -293,9 +293,6 @@ defmodule PlausibleWeb.Site.MembershipControllerTest do
put(conn, "/sites/#{site.domain}/memberships/u/#{collaborator.id}/role/viewer") put(conn, "/sites/#{site.domain}/memberships/u/#{collaborator.id}/role/viewer")
assert_team_membership(collaborator, site.team, :viewer) assert_team_membership(collaborator, site.team, :viewer)
old_model_membership = Repo.get_by(Plausible.Site.Membership, user_id: collaborator.id)
assert old_model_membership.role == :viewer
end end
@tag :teams @tag :teams

View File

@ -280,8 +280,8 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
conn: conn, conn: conn,
user: user user: user
} do } do
insert_list(9, :site, members: [user]) for _ <- 1..9, do: new_site(owner: user)
assert 10 = Plausible.Billing.Quota.Usage.site_usage(user) assert 10 = Plausible.Teams.Adapter.Read.Billing.site_usage(user)
another_user = new_user() another_user = new_user()
pending_ownership_site = new_site(owner: another_user) pending_ownership_site = new_site(owner: another_user)
@ -323,6 +323,7 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
user user
|> Plausible.Auth.User.changeset(%{trial_expiry_date: Timex.shift(Timex.today(), days: -10)}) |> Plausible.Auth.User.changeset(%{trial_expiry_date: Timex.shift(Timex.today(), days: -10)})
|> Repo.update!() |> Repo.update!()
|> Plausible.Teams.sync_team()
generate_usage_for(site, 13_000) generate_usage_for(site, 13_000)
@ -349,6 +350,7 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
user user
|> Plausible.Auth.User.changeset(%{trial_expiry_date: Timex.shift(Timex.today(), days: -11)}) |> Plausible.Auth.User.changeset(%{trial_expiry_date: Timex.shift(Timex.today(), days: -11)})
|> Repo.update!() |> Repo.update!()
|> Plausible.Teams.sync_team()
generate_usage_for(site, 11_000) generate_usage_for(site, 11_000)
@ -613,7 +615,7 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
new_site(owner: user) new_site(owner: user)
end end
assert 50 = Plausible.Billing.Quota.Usage.site_usage(user) assert 50 = Plausible.Teams.Adapter.Read.Billing.quota_usage(user).sites
another_user = new_user() another_user = new_user()
pending_ownership_site = new_site(owner: another_user) pending_ownership_site = new_site(owner: another_user)
@ -655,15 +657,8 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
conn: conn, conn: conn,
user: user user: user
} do } do
insert(:site, site = new_site(owner: user)
memberships: [ for _ <- 1..4, do: add_guest(site, role: :viewer)
build(:site_membership, user: user, role: :owner),
build(:site_membership, user: build(:user)),
build(:site_membership, user: build(:user)),
build(:site_membership, user: build(:user)),
build(:site_membership, user: build(:user))
]
)
{:ok, _lv, doc} = get_liveview(conn) {:ok, _lv, doc} = get_liveview(conn)
@ -678,7 +673,7 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
conn: conn, conn: conn,
user: user user: user
} do } do
for _ <- 1..11, do: insert(:site, members: [user]) for _ <- 1..11, do: new_site(owner: user)
{:ok, _lv, doc} = get_liveview(conn) {:ok, _lv, doc} = get_liveview(conn)
@ -693,17 +688,10 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
conn: conn, conn: conn,
user: user user: user
} do } do
for _ <- 1..11, do: insert(:site, members: [user]) for _ <- 1..11, do: new_site(owner: user)
insert(:site, site = new_site(owner: user)
memberships: [ for _ <- 1..4, do: add_guest(site, role: :viewer)
build(:site_membership, user: user, role: :owner),
build(:site_membership, user: build(:user)),
build(:site_membership, user: build(:user)),
build(:site_membership, user: build(:user)),
build(:site_membership, user: build(:user))
]
)
{:ok, _lv, doc} = get_liveview(conn) {:ok, _lv, doc} = get_liveview(conn)
@ -1111,7 +1099,10 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
defp create_subscription_for(user, subscription_opts) do defp create_subscription_for(user, subscription_opts) do
{paddle_plan_id, subscription_opts} = Keyword.pop(subscription_opts, :paddle_plan_id) {paddle_plan_id, subscription_opts} = Keyword.pop(subscription_opts, :paddle_plan_id)
user = subscribe_to_plan(user, paddle_plan_id, subscription_opts)
user =
subscribe_to_plan(user, paddle_plan_id, subscription_opts)
{:ok, user: user} {:ok, user: user}
end end

View File

@ -62,8 +62,15 @@ defmodule Plausible.Teams.Test do
insert(:site_membership, user: user, role: translate_role_to_old_model(role), site: site) insert(:site_membership, user: user, role: translate_role_to_old_model(role), site: site)
team_membership = insert(:team_membership, team: team, user: user, role: :guest) team_membership =
insert(:guest_membership, team_membership: team_membership, site: site, role: role) build(:team_membership, team: team, user: user, role: :guest)
|> Repo.insert!(
on_conflict: [set: [updated_at: NaiveDateTime.utc_now()]],
conflict_target: [:team_id, :user_id],
returning: true
)
insert(:guest_membership, site: site, team_membership: team_membership, role: role)
user |> Repo.preload([:site_memberships, :team_memberships]) user |> Repo.preload([:site_memberships, :team_memberships])
end end
@ -152,7 +159,10 @@ defmodule Plausible.Teams.Test do
def subscribe_to_plan(user, paddle_plan_id, attrs \\ []) do def subscribe_to_plan(user, paddle_plan_id, attrs \\ []) do
{:ok, team} = Teams.get_or_create(user) {:ok, team} = Teams.get_or_create(user)
attrs = Keyword.merge([user: user, team: team, paddle_plan_id: paddle_plan_id], attrs) 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} %{user | subscription: subscription}
end end