diff --git a/core/config/config.exs b/core/config/config.exs index c0655629..4a02d9ea 100644 --- a/core/config/config.exs +++ b/core/config/config.exs @@ -95,6 +95,7 @@ config :mime, :extensions, %{"json" => "application/vnd.api+json"} config :canary, :github_app_url, "https://github.com/apps/getcanary-dev/installations/new" config :ash, :missed_notifications, :ignore +config :ash, :policies, log_policy_breakdowns: :error config :floki, :html_parser, Floki.HTMLParser.Html5ever diff --git a/core/lib/canary/checks/filter_invite_access.ex b/core/lib/canary/checks/filter_invite_access.ex index 0cd3c144..95514155 100644 --- a/core/lib/canary/checks/filter_invite_access.ex +++ b/core/lib/canary/checks/filter_invite_access.ex @@ -7,25 +7,13 @@ defmodule Canary.Checks.Filter.InviteAccess do end @impl true - def filter( - _, - %Ash.Policy.Authorizer{ - resource: Canary.Accounts.Invite, - actor: %Canary.Accounts.Account{id: _} - }, - _opts - ) do + def filter(%Canary.Accounts.Account{id: _}, %Ash.Policy.Authorizer{} = _authorizer, _opts) do expr(account_id == ^actor(:id)) end - def filter( - _, - %Ash.Policy.Authorizer{ - resource: Canary.Accounts.Invite, - actor: %Canary.Accounts.User{email: _} - }, - _opts - ) do + def filter(%Canary.Accounts.User{email: _}, %Ash.Policy.Authorizer{} = _authorizer, _opts) do expr(email == ^actor(:email)) end + + def filter(_actor, _authorizer, _opts), do: false end diff --git a/core/lib/canary/checks/membership_source_create.ex b/core/lib/canary/checks/membership_source_create.ex index 27c5add4..f9c7eeb1 100644 --- a/core/lib/canary/checks/membership_source_create.ex +++ b/core/lib/canary/checks/membership_source_create.ex @@ -9,20 +9,15 @@ defmodule Canary.Checks.Membership.SourceCreate do %Canary.Accounts.Account{} = account, %Ash.Policy.Authorizer{ resource: Canary.Sources.Source, - changeset: %Ash.Changeset{relationships: %{project: [{[%{id: id}], _}]}} = changeset + changeset: %Ash.Changeset{relationships: %{project: [{[%{id: id}], _}]}} }, _opts ) do with {:ok, %{billing: billing}} <- Ash.load(account, billing: [:membership]), {:ok, %{num_sources: num_sources}} <- Ash.get(Canary.Accounts.Project, id, load: [:num_sources]) do - %Ash.Union{type: source_type} = Ash.Changeset.get_attribute(changeset, :config) - cond do - billing.membership.tier == :free and source_type == :webpage and num_sources < 1 -> - {:ok, true} - - billing.membership.tier == :starter and num_sources < 4 -> + num_sources < Canary.Membership.max_sources(billing.membership.tier) -> {:ok, true} true -> diff --git a/core/lib/canary/checks/membership_team_invite.ex b/core/lib/canary/checks/membership_team_invite.ex index 92d09a8d..b60479ba 100644 --- a/core/lib/canary/checks/membership_team_invite.ex +++ b/core/lib/canary/checks/membership_team_invite.ex @@ -24,18 +24,16 @@ defmodule Canary.Checks.Membership.TeamInvite do account != account_id -> {:ok, false} - billing.membership.tier == :free -> - {:ok, false} - - billing.membership.tier == :starter and num_invites + num_members < 4 -> + num_invites + num_members <= Canary.Membership.max_members(billing.membership.tier) -> {:ok, true} true -> {:ok, false} end + else + _ -> + {:ok, false} end - - {:ok, true} end def match?(_, _, _), do: false diff --git a/core/lib/canary/membership.ex b/core/lib/canary/membership.ex index 4ab6538e..0b002286 100644 --- a/core/lib/canary/membership.ex +++ b/core/lib/canary/membership.ex @@ -6,7 +6,6 @@ defmodule Canary.Membership do :free -> false :starter -> true :admin -> true - _ -> false end end @@ -17,72 +16,90 @@ defmodule Canary.Membership do :free -> false :starter -> true :admin -> true - _ -> false end end - def max_sources(%Canary.Accounts.Account{} = account) do + def max_projects(:free), do: 1 + def max_projects(:starter), do: 3 + def max_projects(:admin), do: 9999 + + def max_projects(%Canary.Accounts.Account{} = account) do account = ensure_membership(account) case account.billing.membership.tier do - :free -> 1 - :starter -> 3 - :admin -> 9999 - _ -> 0 + :free -> Canary.Membership.max_projects(:free) + :starter -> Canary.Membership.max_projects(:starter) + :admin -> Canary.Membership.max_projects(:admin) end end - def max_projects(%Canary.Accounts.Account{} = account) do + def max_sources(:free), do: 3 + def max_sources(:starter), do: 9 + def max_sources(:admin), do: 9999 + + def max_sources(%Canary.Accounts.Account{} = account) do account = ensure_membership(account) case account.billing.membership.tier do - :free -> 1 - :starter -> 3 - :admin -> 9999 - _ -> 0 + :free -> Canary.Membership.max_sources(:free) + :starter -> Canary.Membership.max_sources(:starter) + :admin -> Canary.Membership.max_sources(:admin) end end + def max_members(:free), do: 1 + def max_members(:starter), do: 3 + def max_members(:admin), do: 9999 + def max_members(%Canary.Accounts.Account{} = account) do account = ensure_membership(account) case account.billing.membership.tier do - :free -> 1 - :starter -> 3 - :admin -> 9999 - _ -> 0 + :free -> Canary.Membership.max_members(:free) + :starter -> Canary.Membership.max_members(:starter) + :admin -> Canary.Membership.max_members(:admin) end end + def max_searches(:free), do: 1000 * 1000 + def max_searches(:starter), do: 10 * 1000 * 1000 + def max_searches(:admin), do: 1000 * 1000 * 1000 + def max_searches(%Canary.Accounts.Account{} = account) do account = ensure_membership(account) case account.billing.membership.tier do - :free -> 30 * 1000 - :starter -> 1000 * 1000 - :admin -> 1000 * 1000 - _ -> 0 + :free -> Canary.Membership.max_searches(:free) + :starter -> Canary.Membership.max_searches(:starter) + :admin -> Canary.Membership.max_searches(:admin) end end + def max_asks(:free), do: 0 + def max_asks(:starter), do: 3 * 1000 + def max_asks(:admin), do: 1000 * 1000 + def max_asks(%Canary.Accounts.Account{} = account) do account = ensure_membership(account) case account.billing.membership.tier do - :free -> 100 - :starter -> 1000 - :admin -> 1000 * 1000 - _ -> 0 + :free -> Canary.Membership.max_asks(:free) + :starter -> Canary.Membership.max_asks(:starter) + :admin -> Canary.Membership.max_asks(:admin) end end + def refetch_interval_hours(:free), do: 24 * 4 + def refetch_interval_hours(:starter), do: 24 * 1 + def refetch_interval_hours(:admin), do: 24 * 30 * 12 * 10 + def refetch_interval_hours(%Canary.Accounts.Account{} = account) do account = ensure_membership(account) case account.billing.membership.tier do - :free -> 24 * 3 - :starter -> 24 * 1 - _ -> 24 * 30 * 12 * 10 + :free -> Canary.Membership.refetch_interval_hours(:free) + :starter -> Canary.Membership.refetch_interval_hours(:starter) + :admin -> Canary.Membership.refetch_interval_hours(:admin) end end @@ -92,7 +109,12 @@ defmodule Canary.Membership do account rescue _ -> - account |> Ash.load!(billing: [:membership]) + billing_query = + Canary.Accounts.Billing + |> Ash.Query.select([:id]) + |> Ash.Query.load(:membership) + + account |> Ash.load!(billing: billing_query) end end end diff --git a/core/lib/canary_web/live/billing_live/plans.ex b/core/lib/canary_web/live/billing_live/plans.ex index ae0e9004..e755cf95 100644 --- a/core/lib/canary_web/live/billing_live/plans.ex +++ b/core/lib/canary_web/live/billing_live/plans.ex @@ -5,6 +5,9 @@ defmodule CanaryWeb.BillingLive.Plans do def render(assigns) do ~H"""