From e65e37afc06c39ce2984354571fa2be6ebce6aca Mon Sep 17 00:00:00 2001 From: Adrian Gruntkowski Date: Mon, 17 Jun 2024 13:11:53 +0200 Subject: [PATCH] Implement CRM enterprise plan definition QoL improvements (#4230) * Implement autoprefill of enterprise plan fields on user change * Implement sanitizing input attrs in enterprise plan CRM form * Implement number formatting for monthly pageview limit input in CRM form --- .../billing/enterprise_plan_admin.ex | 45 ++++++++++- lib/plausible/crm_extensions.ex | 77 +++++++++++++++++++ .../controllers/admin_controller.ex | 32 ++++++++ lib/plausible_web/router.ex | 1 + .../billing/enterprise_plan_admin_test.exs | 52 +++++++++++++ .../controllers/admin_controller_test.exs | 55 +++++++++++++ 6 files changed, 261 insertions(+), 1 deletion(-) create mode 100644 test/plausible/billing/enterprise_plan_admin_test.exs diff --git a/lib/plausible/billing/enterprise_plan_admin.ex b/lib/plausible/billing/enterprise_plan_admin.ex index bab737530..b88b1944b 100644 --- a/lib/plausible/billing/enterprise_plan_admin.ex +++ b/lib/plausible/billing/enterprise_plan_admin.ex @@ -1,6 +1,15 @@ defmodule Plausible.Billing.EnterprisePlanAdmin do use Plausible.Repo + @numeric_fields [ + "user_id", + "paddle_plan_id", + "monthly_pageview_limit", + "site_limit", + "team_member_limit", + "hourly_api_request_limit" + ] + def search_fields(_schema) do [ :paddle_plan_id, @@ -40,8 +49,42 @@ defmodule Plausible.Billing.EnterprisePlanAdmin do defp get_user_email(plan), do: plan.user.email + def create_changeset(schema, attrs) do + attrs = sanitize_attrs(attrs) + Plausible.Billing.EnterprisePlan.changeset(schema, attrs) + end + def update_changeset(enterprise_plan, attrs) do - attrs = Map.put_new(attrs, "features", []) + attrs = + attrs + |> Map.put_new("features", []) + |> sanitize_attrs() + Plausible.Billing.EnterprisePlan.changeset(enterprise_plan, attrs) end + + defp sanitize_attrs(attrs) do + attrs + |> Enum.map(&clear_attr/1) + |> Enum.reject(&(&1 == "")) + |> Map.new() + end + + defp clear_attr({key, value}) when key in @numeric_fields do + value = + value + |> to_string() + |> String.replace(~r/[^0-9-]/, "") + |> String.trim() + + {key, value} + end + + defp clear_attr({key, value}) when is_binary(value) do + {key, String.trim(value)} + end + + defp clear_attr(other) do + other + end end diff --git a/lib/plausible/crm_extensions.ex b/lib/plausible/crm_extensions.ex index 3f1988876..4bc23f341 100644 --- a/lib/plausible/crm_extensions.ex +++ b/lib/plausible/crm_extensions.ex @@ -24,6 +24,83 @@ defmodule Plausible.CrmExtensions do """) ] end + + def javascripts(%{assigns: %{context: "billing", resource: "enterprise_plan", changeset: %{}}}) do + [ + Phoenix.HTML.raw(""" + + """), + Phoenix.HTML.raw(""" + + """) + ] + end end def javascripts(_) do diff --git a/lib/plausible_web/controllers/admin_controller.ex b/lib/plausible_web/controllers/admin_controller.ex index 865417f8c..fd68c75bd 100644 --- a/lib/plausible_web/controllers/admin_controller.ex +++ b/lib/plausible_web/controllers/admin_controller.ex @@ -24,6 +24,38 @@ defmodule PlausibleWeb.AdminController do |> send_resp(200, html_response) end + def current_plan(conn, params) do + user = + params["user_id"] + |> String.to_integer() + |> Plausible.Users.with_subscription() + + plan = + case user && user.subscription && + Plausible.Billing.Plans.get_subscription_plan(user.subscription) do + %{} = plan -> + plan + |> Map.take([ + :billing_interval, + :monthly_pageview_limit, + :site_limit, + :team_member_limit, + :hourly_api_request_limit, + :features + ]) + |> Map.update(:features, [], fn features -> Enum.map(features, & &1.name()) end) + + _ -> + %{features: []} + end + + json_response = Jason.encode!(plan) + + conn + |> put_resp_content_type("application/json") + |> send_resp(200, json_response) + end + defp usage_and_limits_html(user, usage, limits, embed?) do content = """