Skip to content

Commit

Permalink
modify pricing and fix policy bug
Browse files Browse the repository at this point in the history
  • Loading branch information
yujonglee committed Oct 28, 2024
1 parent 8ad75c2 commit 358a981
Show file tree
Hide file tree
Showing 11 changed files with 172 additions and 148 deletions.
1 change: 1 addition & 0 deletions core/config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
20 changes: 4 additions & 16 deletions core/lib/canary/checks/filter_invite_access.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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
9 changes: 2 additions & 7 deletions core/lib/canary/checks/membership_source_create.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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 ->
Expand Down
10 changes: 4 additions & 6 deletions core/lib/canary/checks/membership_team_invite.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
78 changes: 50 additions & 28 deletions core/lib/canary/membership.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ defmodule Canary.Membership do
:free -> false
:starter -> true
:admin -> true
_ -> false
end
end

Expand All @@ -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

Expand All @@ -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
38 changes: 22 additions & 16 deletions core/lib/canary_web/live/billing_live/plans.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ defmodule CanaryWeb.BillingLive.Plans do
def render(assigns) do
~H"""
<div>
<div class="mb-2">
For more information, please refer to our <a href="https://getcanary.dev/docs/cloud/platform/pricing">pricing page</a>.
</div>
<div class="overflow-x-auto">
<table class="min-w-full bg-white border border-gray-300">
<thead>
Expand All @@ -14,8 +17,9 @@ defmodule CanaryWeb.BillingLive.Plans do
value <- [
"Name",
"Price",
"Projects",
"Users",
"Source",
"Sources",
"Reindex",
"Search",
"Ask AI",
Expand All @@ -36,13 +40,14 @@ defmodule CanaryWeb.BillingLive.Plans do
value <- [
"Free",
"$0 / mo",
"<= 1",
"<= 1, Webpage only",
"Every 72 hours",
(1000 * 1000)
|> Integer.to_string()
|> String.pad_leading(3, "0"),
"100",
"<= #{Canary.Membership.max_projects(:free)}",
"<= #{Canary.Membership.max_members(:free)}",
"<= #{Canary.Membership.max_sources(:free)}",
"Every #{Canary.Membership.refetch_interval_hours(:free)} hours",
Canary.Membership.max_searches(:free)
|> Number.Delimit.number_to_delimited(precision: 0),
Canary.Membership.max_asks(:free)
|> Number.Delimit.number_to_delimited(precision: 0),
"X",
nil
]
Expand All @@ -61,14 +66,15 @@ defmodule CanaryWeb.BillingLive.Plans do
:for={
value <- [
"Starter",
"$59 / mo",
"<= 3",
"<= 3, All types",
"Every 24 hours",
(5000 * 1000)
|> Integer.to_string()
|> String.pad_leading(3, "0"),
1000,
"$79 / mo",
"<= #{Canary.Membership.max_projects(:starter)}",
"<= #{Canary.Membership.max_members(:starter)}",
"<= #{Canary.Membership.max_sources(:starter)}",
"Every #{Canary.Membership.refetch_interval_hours(:starter)} hours",
Canary.Membership.max_searches(:starter)
|> Number.Delimit.number_to_delimited(precision: 0),
Canary.Membership.max_asks(:starter)
|> Number.Delimit.number_to_delimited(precision: 0),
"O",
:action
]
Expand Down
Loading

0 comments on commit 358a981

Please sign in to comment.