| defmodule Plausible.Teams.Test do |
| @moduledoc """ |
| Convenience assertions for teams schema transition |
| """ |
| use Plausible |
|
|
| alias Plausible.Repo |
| alias Plausible.Teams |
|
|
| import Ecto.Query |
|
|
| use ExUnit.CaseTemplate |
|
|
| import Plausible.Factory |
|
|
| defmacro __using__(_) do |
| quote do |
| import Plausible.Teams.Test |
| end |
| end |
|
|
| def set_current_team(conn, team) do |
| Plug.Conn.put_session(conn, :current_team_id, team.identifier) |
| end |
|
|
| on_ee do |
| def new_consolidated_view(team) do |
| team = Teams.complete_setup(team) |
| {:ok, site} = Plausible.ConsolidatedView.enable(team) |
| site |
| end |
| end |
|
|
| def new_site(args \\ []) do |
| args = |
| cond do |
| user = args[:owner] -> |
| {owner, args} = Keyword.pop(args, :owner) |
| {:ok, team} = Teams.get_or_create(user) |
|
|
| args |
| |> Keyword.put(:owners, [owner]) |
| |> Keyword.put(:team, team) |
|
|
| args[:team] -> |
| args |
|
|
| true -> |
| user = new_user() |
| {:ok, team} = Teams.get_or_create(user) |
|
|
| args |
| |> Keyword.put(:team, team) |
| end |
|
|
| :site |
| |> insert(args) |
| end |
|
|
| def new_user(args \\ []) do |
| {team_args, args} = Keyword.pop(args, :team, []) |
| {trial_expiry_date, args} = Keyword.pop(args, :trial_expiry_date) |
|
|
| on_ee do |
| args = Keyword.merge([type: :standard], args) |
| end |
|
|
| user = insert(:user, args) |
|
|
| trial_expiry_date = |
| if team_args != [] && !trial_expiry_date do |
| Date.add(Date.utc_today(), 30) |
| else |
| trial_expiry_date |
| end |
|
|
| if trial_expiry_date do |
| {:ok, team} = Teams.get_or_create(user) |
|
|
| team_args = |
| Keyword.merge(team_args, trial_expiry_date: trial_expiry_date) |
|
|
| team |
| |> Ecto.Changeset.change(team_args) |
| |> Repo.update!() |
| end |
|
|
| Repo.preload(user, team_memberships: :team) |
| end |
|
|
| 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, opts) do |
| case Plausible.Teams.get_by_owner(user) do |
| {:ok, team} -> |
| if opts[:with_subscription?] do |
| Plausible.Teams.with_subscription(team) |
| else |
| team |
| end |
|
|
| _ -> |
| nil |
| end |
| end |
|
|
| def add_site_guest_or_team_member(site, args \\ []) do |
| case Keyword.pop!(args, :membership_type) do |
| {:site_guest, args} -> add_guest(site, args) |
| {:team_member, args} -> add_member(site.team, args) |
| end |
| end |
|
|
| def add_guest(site, args \\ []) do |
| user = Keyword.get(args, :user, new_user()) |
| role = Keyword.fetch!(args, :role) |
| team = Repo.preload(site, :team).team |
|
|
| team_membership = |
| 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(:team_memberships) |
| end |
|
|
| def add_member(team, args \\ []) do |
| user = Keyword.get(args, :user, new_user()) |
| role = Keyword.fetch!(args, :role) |
|
|
| insert(:team_membership, team: team, user: user, role: role) |
|
|
| user |> Repo.preload(:team_memberships) |
| end |
|
|
| def invite_guest(site, invitee_or_email, args \\ []) when not is_nil(invitee_or_email) do |
| {role, args} = Keyword.pop!(args, :role) |
| {inviter, args} = Keyword.pop!(args, :inviter) |
| {team_invitation_args, args} = Keyword.pop(args, :team_invitation, []) |
| team = Repo.preload(site, :team).team |
|
|
| email = |
| case invitee_or_email do |
| %{email: email} -> email |
| email when is_binary(email) -> email |
| end |
|
|
| team_invitation = |
| insert( |
| :team_invitation, |
| Keyword.merge( |
| [ |
| team: team, |
| email: email, |
| inviter: inviter, |
| role: :guest |
| ], |
| team_invitation_args |
| ) |
| ) |
|
|
| insert( |
| :guest_invitation, |
| Keyword.merge( |
| [ |
| team_invitation: team_invitation, |
| site: site, |
| role: role |
| ], |
| args |
| ) |
| ) |
| end |
|
|
| def invite_member(team, invitee_or_email, args \\ []) when not is_nil(invitee_or_email) do |
| {role, args} = Keyword.pop!(args, :role) |
| {inviter, args} = Keyword.pop!(args, :inviter) |
|
|
| email = |
| case invitee_or_email do |
| %{email: email} -> email |
| email when is_binary(email) -> email |
| end |
|
|
| insert( |
| :team_invitation, |
| Keyword.merge( |
| [ |
| team: team, |
| email: email, |
| inviter: inviter, |
| role: role |
| ], |
| args |
| ) |
| ) |
| end |
|
|
| def invite_transfer(site, invitee_or_email, args \\ []) do |
| {inviter, args} = Keyword.pop!(args, :inviter) |
|
|
| email = |
| case invitee_or_email do |
| %{email: email} -> email |
| email when is_binary(email) -> email |
| end |
|
|
| insert( |
| :site_transfer, |
| Keyword.merge( |
| [ |
| email: email, |
| site: site, |
| initiator: inviter |
| ], |
| args |
| ) |
| ) |
| end |
|
|
| def revoke_membership(site, user) do |
| Repo.delete_all( |
| from tm in Plausible.Teams.Membership, |
| where: tm.user_id == ^user.id and tm.team_id == ^site.team.id |
| ) |
|
|
| user |> Repo.preload(:team_memberships) |
| end |
|
|
| def subscribe_to_starter_plan(user, attrs \\ []) do |
| {:ok, team} = Teams.get_or_create(user) |
| attrs = Keyword.merge([team: team], attrs) |
|
|
| insert(:starter_subscription, attrs) |
| user |
| end |
|
|
| def subscribe_to_growth_plan(user_or_team, attrs \\ []) |
|
|
| def subscribe_to_growth_plan(%Plausible.Auth.User{} = user, attrs) do |
| {:ok, team} = Teams.get_or_create(user) |
| attrs = Keyword.merge([team: team], attrs) |
|
|
| subscribe_to_growth_plan(team, attrs) |
| user |
| end |
|
|
| def subscribe_to_growth_plan(%Plausible.Teams.Team{} = team, attrs) do |
| attrs = Keyword.merge([team: team], attrs) |
|
|
| insert(:growth_subscription, attrs) |
| team |
| end |
|
|
| def subscribe_to_business_plan(%Plausible.Auth.User{} = user) do |
| {:ok, team} = Teams.get_or_create(user) |
| subscribe_to_business_plan(team) |
|
|
| user |
| end |
|
|
| def subscribe_to_business_plan(%Plausible.Teams.Team{} = team) do |
| insert(:business_subscription, team: team) |
| team |
| end |
|
|
| def subscribe_to_plan(user, paddle_plan_id, attrs \\ []) do |
| {:ok, team} = Teams.get_or_create(user) |
| attrs = Keyword.merge([team: team, paddle_plan_id: paddle_plan_id], attrs) |
|
|
| insert(:subscription, attrs) |
|
|
| user |
| end |
|
|
| def subscribe_to_enterprise_plan(user, attrs \\ []) 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([team: team], attrs)) |
|
|
| if subscription? do |
| insert( |
| :subscription, |
| Keyword.merge( |
| [ |
| team: team, |
| paddle_plan_id: enterprise_plan.paddle_plan_id |
| ], |
| subscription_attrs |
| ) |
| ) |
| end |
|
|
| user |
| end |
|
|
| def assert_team_exists(user, team_id \\ nil) do |
| assert %{team_memberships: memberships} = Repo.preload(user, team_memberships: :team) |
|
|
| tm = |
| case memberships do |
| [tm] -> tm |
| _ -> raise "Team doesn't exist for user #{user.id}" |
| end |
|
|
| assert tm.role == :owner |
| assert tm.team.id |
|
|
| if team_id do |
| assert tm.team.id == team_id |
| end |
|
|
| tm.team |
| end |
|
|
| def assert_team_membership(user, team, role \\ :owner) do |
| assert membership = |
| Repo.get_by(Teams.Membership, |
| team_id: team.id, |
| user_id: user.id, |
| role: role |
| ) |
|
|
| membership |
| end |
|
|
| def refute_team_member(user, team) do |
| refute Repo.get_by(Teams.Membership, |
| team_id: team.id, |
| user_id: user.id |
| ) |
| end |
|
|
| def assert_team_attached(site, team_id \\ nil) do |
| assert site = %{team: team} = site |> Repo.reload!() |> Repo.preload([:team, :owners]) |
|
|
| for owner <- site.owners do |
| assert membership = assert_team_membership(owner, team) |
|
|
| assert membership.team_id == team.id |
| end |
|
|
| if team_id do |
| assert team.id == team_id |
| end |
|
|
| team |
| end |
|
|
| def assert_guest_invitation(team, site, email, role) do |
| assert team_invitation = |
| Repo.get_by(Plausible.Teams.Invitation, |
| email: email, |
| team_id: team.id, |
| role: :guest |
| ) |
|
|
| assert Repo.get_by(Plausible.Teams.GuestInvitation, |
| team_invitation_id: team_invitation.id, |
| site_id: site.id, |
| role: role |
| ) |
| end |
|
|
| def refute_team_invitation(team, email) do |
| refute Repo.get_by(Plausible.Teams.Invitation, |
| email: email, |
| team_id: team.id |
| ) |
| end |
|
|
| def assert_site_transfer(site, %Plausible.Auth.User{} = user) do |
| assert_site_transfer(site, user.email) |
| end |
|
|
| def assert_site_transfer(site, email) when is_binary(email) do |
| assert Repo.get_by(Plausible.Teams.SiteTransfer, |
| site_id: site.id, |
| email: email |
| ) |
| end |
|
|
| def assert_guest_membership(team, site, user, role) do |
| assert team_membership = |
| Repo.get_by(Plausible.Teams.Membership, |
| user_id: user.id, |
| team_id: team.id, |
| role: :guest |
| ) |
|
|
| assert Repo.get_by(Plausible.Teams.GuestMembership, |
| team_membership_id: team_membership.id, |
| site_id: site.id, |
| role: role |
| ) |
| end |
|
|
| def assert_non_guest_membership(team, site, user) do |
| assert team_membership = |
| Repo.get_by(Plausible.Teams.Membership, |
| user_id: user.id, |
| team_id: team.id |
| ) |
|
|
| assert team_membership.role != :guest |
|
|
| refute Repo.get_by(Plausible.Teams.GuestMembership, |
| team_membership_id: team_membership.id, |
| site_id: site.id |
| ) |
| end |
|
|
| def subscription_of(%Plausible.Auth.User{} = user) do |
| user |
| |> team_of() |
| |> subscription_of() |
| end |
|
|
| def subscription_of(team) do |
| team |
| |> Plausible.Teams.with_subscription() |
| |> Map.fetch!(:subscription) |
| end |
|
|
| on_ee do |
| def audited_entry(name, attrs \\ []) do |
| attrs = Keyword.put(attrs, :name, name) |
|
|
| case Plausible.Audit.list_entries(attrs) do |
| [entry] -> |
| entry |
|
|
| _ -> |
| raise "Expected audited entry #{inspect(attrs)} but only found #{inspect(Plausible.Audit.list_entries([]), pretty: true)}." |
| end |
| end |
|
|
| def audited_entries(length, name, attrs \\ []) do |
| attrs = Keyword.put(attrs, :name, name) |
|
|
| case Plausible.Audit.list_entries(attrs) do |
| entries when is_list(entries) and length(entries) == length -> |
| entries |
|
|
| _ -> |
| raise "Expected audited entry #{inspect(attrs)} but only found #{inspect(Plausible.Audit.list_entries([]), pretty: true)}." |
| end |
| end |
| end |
| end |
|
|