mirror of
https://github.com/plausible/analytics.git
synced 2024-09-11 18:07:33 +03:00
Prepare business tier for release (#3464)
* Change limits for trials * Keep legacy trial limits for users that registered before the business tier * Change private preview notice for release * Run formatter * Add countdown to private preview notice
This commit is contained in:
parent
38b1834b3f
commit
c9bf5827e9
@ -101,8 +101,8 @@ defmodule Plausible.Billing.Feature do
|
||||
@impl true
|
||||
def check_availability(%Plausible.Auth.User{} = user) do
|
||||
cond do
|
||||
not FunWithFlags.enabled?(:business_tier, for: user) -> :ok
|
||||
Keyword.get(unquote(opts), :free) -> :ok
|
||||
FunWithFlags.enabled?(:premium_features_private_preview) -> :ok
|
||||
__MODULE__ in Quota.allowed_features_for(user) -> :ok
|
||||
true -> {:error, :upgrade_required}
|
||||
end
|
||||
|
@ -27,7 +27,8 @@ defmodule Plausible.Billing.Plans do
|
||||
Module.put_attribute(__MODULE__, :external_resource, path)
|
||||
end
|
||||
|
||||
@business_tier_launch ~N[2023-12-01 12:00:00]
|
||||
@business_tier_launch ~N[2023-11-08 12:00:00]
|
||||
def business_tier_launch, do: @business_tier_launch
|
||||
|
||||
@spec growth_plans_for(User.t()) :: [Plan.t()]
|
||||
@doc """
|
||||
|
@ -39,16 +39,28 @@ defmodule Plausible.Billing.Quota do
|
||||
end
|
||||
end
|
||||
|
||||
@site_limit_for_trials 50
|
||||
@site_limit_for_trials 10
|
||||
@site_limit_for_legacy_trials 50
|
||||
@site_limit_for_free_10k 50
|
||||
defp get_site_limit_from_plan(user) do
|
||||
user = Plausible.Users.with_subscription(user)
|
||||
|
||||
case Plans.get_subscription_plan(user.subscription) do
|
||||
%EnterprisePlan{} -> :unlimited
|
||||
%Plan{site_limit: site_limit} -> site_limit
|
||||
:free_10k -> @site_limit_for_free_10k
|
||||
nil -> @site_limit_for_trials
|
||||
%EnterprisePlan{} ->
|
||||
:unlimited
|
||||
|
||||
%Plan{site_limit: site_limit} ->
|
||||
site_limit
|
||||
|
||||
:free_10k ->
|
||||
@site_limit_for_free_10k
|
||||
|
||||
nil ->
|
||||
if Timex.before?(user.inserted_at, Plans.business_tier_launch()) do
|
||||
@site_limit_for_legacy_trials
|
||||
else
|
||||
@site_limit_for_trials
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -101,7 +113,8 @@ defmodule Plausible.Billing.Quota do
|
||||
|> Tuple.sum()
|
||||
end
|
||||
|
||||
@team_member_limit_for_trials 5
|
||||
@team_member_limit_for_trials 3
|
||||
@team_member_limit_for_legacy_trials :unlimited
|
||||
@spec team_member_limit(Plausible.Auth.User.t()) :: non_neg_integer()
|
||||
@doc """
|
||||
Returns the limit of team members a user can have in their sites.
|
||||
@ -110,10 +123,21 @@ defmodule Plausible.Billing.Quota do
|
||||
user = Plausible.Users.with_subscription(user)
|
||||
|
||||
case Plans.get_subscription_plan(user.subscription) do
|
||||
%EnterprisePlan{} -> :unlimited
|
||||
%Plan{team_member_limit: limit} -> limit
|
||||
:free_10k -> :unlimited
|
||||
nil -> @team_member_limit_for_trials
|
||||
%EnterprisePlan{} ->
|
||||
:unlimited
|
||||
|
||||
%Plan{team_member_limit: limit} ->
|
||||
limit
|
||||
|
||||
:free_10k ->
|
||||
:unlimited
|
||||
|
||||
nil ->
|
||||
if Timex.before?(user.inserted_at, Plans.business_tier_launch()) do
|
||||
@team_member_limit_for_legacy_trials
|
||||
else
|
||||
@team_member_limit_for_trials
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -55,8 +55,7 @@ defmodule Plausible.Sites do
|
||||
)
|
||||
|> maybe_filter_by_domain(domain_filter)
|
||||
|
||||
result =
|
||||
Repo.paginate(sites_query, pagination_params)
|
||||
result = Repo.paginate(sites_query, pagination_params)
|
||||
|
||||
entries =
|
||||
Enum.map(result.entries, fn
|
||||
|
@ -231,8 +231,7 @@ defmodule Plausible.Stats.Clickhouse do
|
||||
%{total_visitors: total, site_id: site_id}, acc -> Map.put_new(acc, site_id, total)
|
||||
end)
|
||||
|
||||
total_q =
|
||||
visitors_24h_total(now, -24, 0, site_id_to_domain_mapping)
|
||||
total_q = visitors_24h_total(now, -24, 0, site_id_to_domain_mapping)
|
||||
|
||||
current_q =
|
||||
from(
|
||||
|
@ -5,7 +5,7 @@ defmodule PlausibleWeb.Components.Billing do
|
||||
import PlausibleWeb.Components.Generic
|
||||
require Plausible.Billing.Subscription.Status
|
||||
alias PlausibleWeb.Router.Helpers, as: Routes
|
||||
alias Plausible.Billing.Subscription
|
||||
alias Plausible.{Billing.Subscription, Billing.Plans}
|
||||
|
||||
attr(:billable_user, Plausible.Auth.User, required: true)
|
||||
attr(:current_user, Plausible.Auth.User, required: true)
|
||||
@ -16,21 +16,27 @@ defmodule PlausibleWeb.Components.Billing do
|
||||
|
||||
# credo:disable-for-next-line Credo.Check.Refactor.CyclomaticComplexity
|
||||
def premium_feature_notice(assigns) do
|
||||
private_preview? = not FunWithFlags.enabled?(:business_tier, for: assigns.current_user)
|
||||
billable_user = Plausible.Users.with_subscription(assigns.billable_user)
|
||||
plan = Plans.get_regular_plan(billable_user.subscription, only_non_expired: true)
|
||||
growth? = plan && plan.kind == :growth
|
||||
|
||||
private_preview? = FunWithFlags.enabled?(:premium_features_private_preview)
|
||||
display_upgrade_link? = assigns.current_user.id == assigns.billable_user.id
|
||||
has_access? = assigns.feature_mod.check_availability(assigns.billable_user) == :ok
|
||||
|
||||
message =
|
||||
cond do
|
||||
private_preview? && assigns.grandfathered? ->
|
||||
"#{assigns.feature_mod.display_name()} is an upcoming premium functionality that's free-to-use during the private preview. Existing subscribers will be grandfathered and will keep having access to this feature without any change to their plan."
|
||||
|
||||
private_preview? ->
|
||||
"#{assigns.feature_mod.display_name()} is an upcoming premium functionality that's free-to-use during the private preview. Pricing will be announced soon."
|
||||
|
||||
Plausible.Billing.on_trial?(assigns.billable_user) ->
|
||||
"#{assigns.feature_mod.display_name()} is part of the Plausible Business plan. You can access it during your trial, but you'll need to subscribe to the Business plan to retain access after the trial ends."
|
||||
|
||||
private_preview? && display_upgrade_link? && growth? ->
|
||||
~H"""
|
||||
Business plans are now live! The private preview of <%= @feature_mod.display_name() %> for Plausible Growth plans ends <%= private_preview_days_remaining() %>. If you wish to continue using this feature, please
|
||||
<.link class="underline" href={Routes.billing_path(PlausibleWeb.Endpoint, :upgrade)}>
|
||||
upgrade your subscription
|
||||
</.link> to the Plausible Business plan.
|
||||
"""
|
||||
|
||||
not has_access? && display_upgrade_link? ->
|
||||
~H"""
|
||||
<%= @feature_mod.display_name() %> is part of the Plausible Business plan. To get access to it, please
|
||||
@ -55,6 +61,18 @@ defmodule PlausibleWeb.Components.Billing do
|
||||
"""
|
||||
end
|
||||
|
||||
defp private_preview_days_remaining do
|
||||
private_preview_ends_at = Timex.shift(Plausible.Billing.Plans.business_tier_launch(), days: 7)
|
||||
|
||||
days_remaining = Timex.diff(private_preview_ends_at, NaiveDateTime.utc_now(), :day)
|
||||
|
||||
if days_remaining <= 0 do
|
||||
"today"
|
||||
else
|
||||
"in #{days_remaining} days"
|
||||
end
|
||||
end
|
||||
|
||||
slot(:inner_block, required: true)
|
||||
attr(:rest, :global)
|
||||
|
||||
|
@ -15,10 +15,10 @@ defmodule PlausibleWeb.Api.ExternalSitesController do
|
||||
|
||||
{:error, :limit, limit, _} ->
|
||||
conn
|
||||
|> put_status(403)
|
||||
|> put_status(402)
|
||||
|> json(%{
|
||||
error:
|
||||
"Your account has reached the limit of #{limit} sites per account. Please contact hello@plausible.io to unlock more sites."
|
||||
"Your account has reached the limit of #{limit} sites. To unlock more sites, please upgrade your subscription."
|
||||
})
|
||||
|
||||
{:error, _, changeset, _} ->
|
||||
|
@ -128,8 +128,7 @@ defmodule PlausibleWeb.BillingController do
|
||||
business_tier_enabled? = FunWithFlags.enabled?(:business_tier, for: user)
|
||||
|
||||
with {:ok, {subscription, preview_info}} <- preview_subscription(user, new_plan_id) do
|
||||
back_action =
|
||||
if business_tier_enabled?, do: :choose_plan, else: :change_plan_form
|
||||
back_action = if business_tier_enabled?, do: :choose_plan, else: :change_plan_form
|
||||
|
||||
render(conn, "change_plan_preview.html",
|
||||
back_link: Routes.billing_path(conn, back_action),
|
||||
|
@ -73,8 +73,7 @@ defmodule PlausibleWeb.Live.Components.Visitors do
|
||||
defp scale(data, target_range) do
|
||||
max_value = Enum.max_by(data, fn %{visitors: visitors} -> visitors end)
|
||||
|
||||
scaling_factor =
|
||||
if max_value.visitors > 0, do: target_range / max_value.visitors, else: 0
|
||||
scaling_factor = if max_value.visitors > 0, do: target_range / max_value.visitors, else: 0
|
||||
|
||||
Enum.map(data, fn %{visitors: visitors} ->
|
||||
round(target_range - visitors * scaling_factor)
|
||||
|
@ -41,8 +41,23 @@ defmodule Plausible.Billing.QuotaTest do
|
||||
assert :unlimited == Quota.site_limit(user)
|
||||
end
|
||||
|
||||
test "returns 50 when user in on trial" do
|
||||
user = insert(:user, trial_expiry_date: Timex.shift(Timex.now(), days: 7))
|
||||
test "returns 10 when user in on trial" do
|
||||
user =
|
||||
insert(:user,
|
||||
trial_expiry_date: Timex.shift(Timex.now(), days: 7),
|
||||
inserted_at: ~U[2024-01-01T00:00:00Z]
|
||||
)
|
||||
|
||||
assert 10 == Quota.site_limit(user)
|
||||
end
|
||||
|
||||
test "returns 50 when user in on trial but registered before the business tier was live" do
|
||||
user =
|
||||
insert(:user,
|
||||
trial_expiry_date: Timex.shift(Timex.now(), days: 7),
|
||||
inserted_at: ~U[2023-10-01T00:00:00Z]
|
||||
)
|
||||
|
||||
assert 50 == Quota.site_limit(user)
|
||||
end
|
||||
|
||||
@ -56,14 +71,15 @@ defmodule Plausible.Billing.QuotaTest do
|
||||
assert 50 == Quota.site_limit(user)
|
||||
end
|
||||
|
||||
test "returns 50 for enterprise users who have not upgraded yet and are on trial" do
|
||||
test "returns 10 for enterprise users who have not upgraded yet and are on trial" do
|
||||
user =
|
||||
insert(:user,
|
||||
enterprise_plan: build(:enterprise_plan, paddle_plan_id: "123321"),
|
||||
subscription: nil
|
||||
subscription: nil,
|
||||
inserted_at: ~U[2024-01-01T00:00:00Z]
|
||||
)
|
||||
|
||||
assert 50 == Quota.site_limit(user)
|
||||
assert 10 == Quota.site_limit(user)
|
||||
end
|
||||
|
||||
test "is unlimited for enterprise customers" do
|
||||
@ -371,8 +387,23 @@ defmodule Plausible.Billing.QuotaTest do
|
||||
end
|
||||
|
||||
test "returns 5 when user in on trial" do
|
||||
user = insert(:user, trial_expiry_date: Timex.shift(Timex.now(), days: 7))
|
||||
assert 5 == Quota.team_member_limit(user)
|
||||
user =
|
||||
insert(:user,
|
||||
trial_expiry_date: Timex.shift(Timex.now(), days: 7),
|
||||
inserted_at: ~U[2024-01-01T00:00:00Z]
|
||||
)
|
||||
|
||||
assert 3 == Quota.team_member_limit(user)
|
||||
end
|
||||
|
||||
test "returns unlimited when user in on trial but registered before the business tier was live" do
|
||||
user =
|
||||
insert(:user,
|
||||
trial_expiry_date: Timex.shift(Timex.now(), days: 7),
|
||||
inserted_at: ~U[2023-10-01T00:00:00Z]
|
||||
)
|
||||
|
||||
assert :unlimited == Quota.team_member_limit(user)
|
||||
end
|
||||
|
||||
test "is unlimited for enterprise customers" do
|
||||
|
@ -67,7 +67,7 @@ defmodule Plausible.Site.Memberships.CreateInvitationTest do
|
||||
end
|
||||
|
||||
test "returns error when owner is over their team member limit" do
|
||||
[owner, inviter, invitee] = insert_list(3, :user)
|
||||
[owner, inviter, invitee] = insert_list(3, :user, inserted_at: ~N[2024-01-01T00:00:00Z])
|
||||
|
||||
memberships =
|
||||
[
|
||||
@ -77,7 +77,7 @@ defmodule Plausible.Site.Memberships.CreateInvitationTest do
|
||||
|
||||
site = insert(:site, memberships: memberships)
|
||||
|
||||
assert {:error, {:over_limit, 5}} =
|
||||
assert {:error, {:over_limit, 3}} =
|
||||
CreateInvitation.create_invitation(site, inviter, invitee.email, :viewer)
|
||||
end
|
||||
|
||||
|
@ -93,8 +93,7 @@ defmodule Plausible.SitesTest do
|
||||
page_number: 1,
|
||||
total_entries: 0,
|
||||
total_pages: 1
|
||||
} =
|
||||
Sites.list(user, %{})
|
||||
} = Sites.list(user, %{})
|
||||
end
|
||||
|
||||
test "returns invitations and sites" do
|
||||
|
@ -2,11 +2,12 @@ defmodule PlausibleWeb.Api.ExternalSitesControllerTest do
|
||||
use PlausibleWeb.ConnCase, async: false
|
||||
use Plausible.Repo
|
||||
|
||||
setup %{conn: conn} do
|
||||
user = insert(:user)
|
||||
setup :create_user
|
||||
|
||||
setup %{conn: conn, user: user} do
|
||||
api_key = insert(:api_key, user: user, scopes: ["sites:provision:*"])
|
||||
conn = Plug.Conn.put_req_header(conn, "authorization", "Bearer #{api_key.key}")
|
||||
{:ok, user: user, api_key: api_key, conn: conn}
|
||||
{:ok, api_key: api_key, conn: conn}
|
||||
end
|
||||
|
||||
describe "POST /api/v1/sites" do
|
||||
@ -70,9 +71,9 @@ defmodule PlausibleWeb.Api.ExternalSitesControllerTest do
|
||||
"timezone" => "Europe/Tallinn"
|
||||
})
|
||||
|
||||
assert json_response(conn, 403) == %{
|
||||
assert json_response(conn, 402) == %{
|
||||
"error" =>
|
||||
"Your account has reached the limit of 50 sites per account. Please contact hello@plausible.io to unlock more sites."
|
||||
"Your account has reached the limit of 10 sites. To unlock more sites, please upgrade your subscription."
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -44,7 +44,7 @@ defmodule PlausibleWeb.Site.MembershipControllerTest do
|
||||
})
|
||||
|
||||
assert html_response(conn, 200) =~
|
||||
"Your account is limited to 5 team members. You can upgrade your plan to increase this limit."
|
||||
"Your account is limited to 3 team members. You can upgrade your plan to increase this limit."
|
||||
end
|
||||
|
||||
test "fails to create invitation with insufficient permissions", %{conn: conn, user: user} do
|
||||
|
@ -272,7 +272,7 @@ defmodule PlausibleWeb.SiteControllerTest do
|
||||
|
||||
assert html = html_response(conn, 200)
|
||||
assert html =~ "Upgrade required"
|
||||
assert html =~ "Your account is limited to 50 sites"
|
||||
assert html =~ "Your account is limited to 10 sites"
|
||||
assert html =~ "Please contact support"
|
||||
refute Repo.get_by(Plausible.Site, domain: "over-limit.example.com")
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user