Skip to content

Commit

Permalink
Switch sites creation to read teams schemas (#4823)
Browse files Browse the repository at this point in the history
* Expose site limit, usage, ensure_can_add_new_site via Adapter

* Print to stdout if TEST_READ_TEAM_SCHEMAS is enabled

* Add factory wrappers for remaining subscription types

* Ensure consistent ordering when fetching latest subscription

* Switch creating new site to read team schemas

* Dedup code based on read team schemas switching

* Switch to transitional factory where necessary

* Update yet another test requiring transitional factory
  • Loading branch information
aerosol authored Nov 14, 2024
1 parent 9b6961c commit 0d6bec1
Show file tree
Hide file tree
Showing 13 changed files with 174 additions and 105 deletions.
3 changes: 1 addition & 2 deletions lib/plausible/sites.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ defmodule Plausible.Sites do
import Ecto.Query

alias Plausible.Auth
alias Plausible.Billing.Quota
alias Plausible.Repo
alias Plausible.Site
alias Plausible.Site.SharedLink
Expand Down Expand Up @@ -84,7 +83,7 @@ defmodule Plausible.Sites do
end

def create(user, params) do
with :ok <- Quota.ensure_can_add_new_site(user) do
with :ok <- Plausible.Teams.Adapter.Read.Billing.ensure_can_add_new_site(user) do
Ecto.Multi.new()
|> Ecto.Multi.put(:site_changeset, Site.new(params))
|> Ecto.Multi.run(:create_team, fn _repo, _context ->
Expand Down
2 changes: 1 addition & 1 deletion lib/plausible/teams.ex
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ defmodule Plausible.Teams do

defp last_subscription_query() do
from(subscription in Plausible.Billing.Subscription,
order_by: [desc: subscription.inserted_at],
order_by: [desc: subscription.inserted_at, desc: subscription.id],
limit: 1
)
end
Expand Down
38 changes: 38 additions & 0 deletions lib/plausible/teams/adapter.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
defmodule Plausible.Teams.Adapter do
@moduledoc """
Commonly used teams-transition functions
"""
alias Plausible.Teams

defmacro __using__(_) do
quote do
alias Plausible.Teams
import Teams.Adapter
end
end

def team_or_user(user) do
switch(
user,
team_fn: &Function.identity/1,
user_fn: &Function.identity/1
)
end

def switch(user, opts \\ []) do
team_fn = Keyword.fetch!(opts, :team_fn)
user_fn = Keyword.fetch!(opts, :user_fn)

if Teams.read_team_schemas?(user) do
team =
case Teams.get_by_owner(user) do
{:ok, team} -> team
{:error, _} -> nil
end

team_fn.(team)
else
user_fn.(user)
end
end
end
39 changes: 28 additions & 11 deletions lib/plausible/teams/adapter/read/billing.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,36 @@ defmodule Plausible.Teams.Adapter.Read.Billing do
@moduledoc """
Transition adapter for new schema reads
"""
alias Plausible.Teams
use Plausible.Teams.Adapter

def check_needs_to_upgrade(user) do
if Teams.read_team_schemas?(user) do
team =
case Teams.get_by_owner(user) do
{:ok, team} -> team
{:error, _} -> nil
end
switch(
user,
team_fn: &Teams.Billing.check_needs_to_upgrade/1,
user_fn: &Plausible.Billing.check_needs_to_upgrade/1
)
end

def site_limit(user) do
switch(
user,
team_fn: &Teams.Billing.site_limit/1,
user_fn: &Plausible.Billing.Quota.Limits.site_limit/1
)
end

def ensure_can_add_new_site(user) do
switch(
user,
team_fn: &Teams.Billing.ensure_can_add_new_site/1,
user_fn: &Plausible.Billing.Quota.ensure_can_add_new_site/1
)
end

Teams.Billing.check_needs_to_upgrade(team)
else
Plausible.Billing.check_needs_to_upgrade(user)
end
def site_usage(user) do
switch(user,
team_fn: &Teams.Billing.site_usage/1,
user_fn: &Plausible.Billing.Quota.Usage.site_usage/1
)
end
end
58 changes: 23 additions & 35 deletions lib/plausible/teams/adapter/read/ownership.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,59 +3,47 @@ defmodule Plausible.Teams.Adapter.Read.Ownership do
Transition adapter for new schema reads
"""
use Plausible
use Plausible.Teams.Adapter
alias Plausible.Site
alias Plausible.Auth
alias Plausible.Teams
alias Plausible.Site.Memberships.Invitations

def ensure_can_take_ownership(site, user) do
if Teams.read_team_schemas?(user) do
team =
case Teams.get_by_owner(user) do
{:ok, team} -> team
{:error, _} -> nil
end

Teams.Invitations.ensure_can_take_ownership(site, team)
else
Invitations.ensure_can_take_ownership(site, user)
end
switch(
user,
team_fn: &Teams.Invitations.ensure_can_take_ownership(site, &1),
user_fn: &Invitations.ensure_can_take_ownership(site, &1)
)
end

def has_sites?(user) do
if Teams.read_team_schemas?(user) do
Teams.Users.has_sites?(user, include_pending?: true)
else
Site.Memberships.any_or_pending?(user)
end
switch(
user,
team_fn: fn _ -> Teams.Users.has_sites?(user, include_pending?: true) end,
user_fn: &Site.Memberships.any_or_pending?/1
)
end

def owns_sites?(user, sites) do
if Teams.read_team_schemas?(user) do
Teams.Users.owns_sites?(user, include_pending?: true)
else
Enum.any?(sites.entries, fn site ->
length(site.invitations) > 0 && List.first(site.invitations).role == :owner
end) ||
Auth.user_owns_sites?(user)
end
switch(
user,
team_fn: fn _ -> Teams.Users.owns_sites?(user, include_pending?: true) end,
user_fn: fn user ->
Enum.any?(sites.entries, fn site ->
length(site.invitations) > 0 && List.first(site.invitations).role == :owner
end) ||
Auth.user_owns_sites?(user)
end
)
end

on_ee do
def check_feature_access(site, new_owner) do
user_or_team =
if Teams.read_team_schemas?(new_owner) do
case Teams.get_by_owner(new_owner) do
{:ok, team} -> team
{:error, _} -> nil
end
else
new_owner
end
team_or_user = team_or_user(new_owner)

missing_features =
Plausible.Billing.Quota.Usage.features_usage(nil, [site.id])
|> Enum.filter(&(&1.check_availability(user_or_team) != :ok))
|> Enum.filter(&(&1.check_availability(team_or_user) != :ok))

if missing_features == [] do
:ok
Expand Down
32 changes: 15 additions & 17 deletions lib/plausible/teams/adapter/read/sites.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,29 @@ defmodule Plausible.Teams.Adapter.Read.Sites do

import Ecto.Query

alias Plausible.Auth
alias Plausible.Repo
alias Plausible.Site
alias Plausible.Teams
use Plausible.Teams.Adapter

def list(user, pagination_params, opts \\ []) do
if Plausible.Teams.read_team_schemas?(user) do
Plausible.Teams.Sites.list(user, pagination_params, opts)
else
old_list(user, pagination_params, opts)
end
switch(
user,
team_fn: fn _ -> Plausible.Teams.Sites.list(user, pagination_params, opts) end,
user_fn: fn _ -> old_list(user, pagination_params, opts) end
)
end

def list_with_invitations(user, pagination_params, opts \\ []) do
if Plausible.Teams.read_team_schemas?(user) do
Plausible.Teams.Sites.list_with_invitations(user, pagination_params, opts)
else
old_list_with_invitations(user, pagination_params, opts)
end
switch(
user,
team_fn: fn _ ->
Plausible.Teams.Sites.list_with_invitations(user, pagination_params, opts)
end,
user_fn: fn _ -> old_list_with_invitations(user, pagination_params, opts) end
)
end

@type list_opt() :: {:filter_by_domain, String.t()}
@spec old_list(Auth.User.t(), map(), [list_opt()]) :: Scrivener.Page.t()
def old_list(user, pagination_params, opts \\ []) do
defp old_list(user, pagination_params, opts) do
domain_filter = Keyword.get(opts, :filter_by_domain)

from(s in Site,
Expand Down Expand Up @@ -60,8 +59,7 @@ defmodule Plausible.Teams.Adapter.Read.Sites do
|> Repo.paginate(pagination_params)
end

@spec old_list_with_invitations(Auth.User.t(), map(), [list_opt()]) :: Scrivener.Page.t()
def old_list_with_invitations(user, pagination_params, opts \\ []) do
defp old_list_with_invitations(user, pagination_params, opts) do
domain_filter = Keyword.get(opts, :filter_by_domain)

result =
Expand Down
13 changes: 12 additions & 1 deletion lib/plausible/teams/billing.ex
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ defmodule Plausible.Teams.Billing do
end
end

def ensure_can_add_new_site(nil) do
:ok
end

def ensure_can_add_new_site(team) do
team = Teams.with_subscription(team)

Expand All @@ -61,6 +65,10 @@ defmodule Plausible.Teams.Billing do
end
end

def site_limit(nil) do
@site_limit_for_trials
end

def site_limit(team) do
if Timex.before?(team.inserted_at, @limit_sites_since) do
:unlimited
Expand All @@ -69,14 +77,17 @@ defmodule Plausible.Teams.Billing do
end
end

def site_usage(nil), do: 0

def site_usage(team) do
team
|> Teams.owned_sites()
|> length()
end

defp get_site_limit_from_plan(team) do
team = Teams.with_subscription(team)
team =
Teams.with_subscription(team)

case Plans.get_subscription_plan(team.subscription) do
%{site_limit: site_limit} -> site_limit
Expand Down
10 changes: 5 additions & 5 deletions lib/plausible_web/controllers/site_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ defmodule PlausibleWeb.SiteController do
use Plausible

alias Plausible.Sites
alias Plausible.Billing.Quota

plug(PlausibleWeb.RequireAccountPlug)

Expand All @@ -19,16 +18,17 @@ defmodule PlausibleWeb.SiteController do

render(conn, "new.html",
changeset: Plausible.Site.changeset(%Plausible.Site{}),
site_limit: Quota.Limits.site_limit(current_user),
site_limit_exceeded?: Quota.ensure_can_add_new_site(current_user) != :ok,
site_limit: Plausible.Teams.Adapter.Read.Billing.site_limit(current_user),
site_limit_exceeded?:
Plausible.Teams.Adapter.Read.Billing.ensure_can_add_new_site(current_user) != :ok,
form_submit_url: "/sites?flow=#{flow}",
flow: flow
)
end

def create_site(conn, %{"site" => site_params}) do
user = conn.assigns[:current_user]
first_site? = Quota.Usage.site_usage(user) == 0
first_site? = Plausible.Teams.Adapter.Read.Billing.site_usage(user) == 0
flow = conn.params["flow"]

case Sites.create(user, site_params) do
Expand Down Expand Up @@ -60,7 +60,7 @@ defmodule PlausibleWeb.SiteController do
render(conn, "new.html",
changeset: changeset,
first_site?: first_site?,
site_limit: Quota.Limits.site_limit(user),
site_limit: Plausible.Teams.Adapter.Read.Billing.site_limit(user),
site_limit_exceeded?: false,
flow: flow,
form_submit_url: "/sites?flow=#{flow}"
Expand Down
Loading

0 comments on commit 0d6bec1

Please sign in to comment.