From daa6bdafa3d49612abca0bb45bf10f5a0d666d4f Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Thu, 14 Dec 2023 19:52:43 +0800 Subject: [PATCH 1/5] feat: partner upgrade/downgrade tiers --- lib/logflare/billing.ex | 4 ++++ lib/logflare/partners.ex | 23 +++++++++++++++++++ lib/logflare/partners/partner_user.ex | 1 + .../api/partner/user_controller.ex | 14 +++++++++++ lib/logflare_web/router.ex | 2 ++ ...upgraded_column_to_partner_users_table.exs | 17 ++++++++++++++ test/logflare/billing_test.exs | 15 ++++++++++++ test/logflare/partners_test.exs | 14 +++++++++++ .../api/partner/user_controller_test.exs | 23 +++++++++++++++++++ 9 files changed, 113 insertions(+) create mode 100644 priv/repo/migrations/20231213013433_add_upgraded_column_to_partner_users_table.exs diff --git a/lib/logflare/billing.ex b/lib/logflare/billing.ex index bff3e8265..f9c9bc2dd 100644 --- a/lib/logflare/billing.ex +++ b/lib/logflare/billing.ex @@ -14,6 +14,7 @@ defmodule Logflare.Billing do Billing.PaymentMethod } + alias Logflare.Partners alias Logflare.SingleTenant require Protocol @@ -329,6 +330,9 @@ defmodule Logflare.Billing do SingleTenant.single_tenant?() -> get_plan_by(name: "Enterprise") + Partners.user_upgraded?(user) == true -> + get_plan_by(name: "Enterprise") + user.billing_enabled == false -> legacy_plan() diff --git a/lib/logflare/partners.ex b/lib/logflare/partners.ex index e9c0e1c38..59127fa30 100644 --- a/lib/logflare/partners.ex +++ b/lib/logflare/partners.ex @@ -117,4 +117,27 @@ defmodule Logflare.Partners do |> Multi.delete_all(:delete, query) |> Repo.transaction() end + + def user_upgraded?(%User{id: id}) do + query = + from(pu in PartnerUser, where: pu.user_id == ^id, select: pu.upgraded) + + Repo.one(query) + |> case do + nil -> false + value -> value + end + end + + def upgrade_user(p, u), do: do_upgrade_downgrade(p, u, true) + def downgrade_user(p, u), do: do_upgrade_downgrade(p, u, false) + + def do_upgrade_downgrade(%Partner{id: partner_id}, %User{id: user_id}, value) do + query = + from(pu in PartnerUser, where: pu.partner_id == ^partner_id and pu.user_id == ^user_id) + + Repo.update_all(query, set: [upgraded: value]) + + {:ok, Repo.one(query)} + end end diff --git a/lib/logflare/partners/partner_user.ex b/lib/logflare/partners/partner_user.ex index b893557ae..912020ddb 100644 --- a/lib/logflare/partners/partner_user.ex +++ b/lib/logflare/partners/partner_user.ex @@ -8,6 +8,7 @@ defmodule Logflare.Partners.PartnerUser do schema "partner_users" do belongs_to :partner, Logflare.Partners.Partner belongs_to :user, Logflare.User + field :upgraded, :boolean, default: false end def changeset(partner_user, params) do diff --git a/lib/logflare_web/controllers/api/partner/user_controller.ex b/lib/logflare_web/controllers/api/partner/user_controller.ex index f862b2653..aa6aea5d8 100644 --- a/lib/logflare_web/controllers/api/partner/user_controller.ex +++ b/lib/logflare_web/controllers/api/partner/user_controller.ex @@ -61,6 +61,20 @@ defmodule LogflareWeb.Api.Partner.UserController do end end + def upgrade(%{assigns: %{partner: partner}} = conn, %{"user_token" => user_token}) do + with user when not is_nil(user) <- Partners.get_user_by_token(partner, user_token), + {:ok, %_{}} <- Partners.upgrade_user(partner, user) do + json(conn, %{tier: "metered"}) + end + end + + def downgrade(%{assigns: %{partner: partner}} = conn, %{"user_token" => user_token}) do + with user when not is_nil(user) <- Partners.get_user_by_token(partner, user_token), + {:ok, %_{}} <- Partners.downgrade_user(partner, user) do + json(conn, %{tier: "free"}) + end + end + defp sanitize_response(user) do Enum.reduce(@allowed_fields, %{}, fn key, acc -> Map.put(acc, key, Map.get(user, key)) end) end diff --git a/lib/logflare_web/router.ex b/lib/logflare_web/router.ex index f6cc6d8fb..7f50fb44e 100644 --- a/lib/logflare_web/router.ex +++ b/lib/logflare_web/router.ex @@ -390,6 +390,8 @@ defmodule LogflareWeb.Router do get("/users", Api.Partner.UserController, :index) post("/users", Api.Partner.UserController, :create) + put("/users/:user_token/upgrade", Api.Partner.UserController, :upgrade) + put("/users/:user_token/downgrade", Api.Partner.UserController, :downgrade) get("/users/:user_token", Api.Partner.UserController, :get_user) get("/users/:user_token/usage", Api.Partner.UserController, :get_user_usage) diff --git a/priv/repo/migrations/20231213013433_add_upgraded_column_to_partner_users_table.exs b/priv/repo/migrations/20231213013433_add_upgraded_column_to_partner_users_table.exs new file mode 100644 index 000000000..da16b1847 --- /dev/null +++ b/priv/repo/migrations/20231213013433_add_upgraded_column_to_partner_users_table.exs @@ -0,0 +1,17 @@ +defmodule Logflare.Repo.Migrations.AddUpgradedColumnToPartnerUsersTable do + use Ecto.Migration + + def up do + + alter table(:partner_users) do + add :upgraded, :boolean, default: false, null: false + end + end + + def down do + + alter table(:partner_users) do + remove :upgraded + end + end +end diff --git a/test/logflare/billing_test.exs b/test/logflare/billing_test.exs index 7e3193fa9..e45830f51 100644 --- a/test/logflare/billing_test.exs +++ b/test/logflare/billing_test.exs @@ -2,6 +2,8 @@ defmodule Logflare.BillingTest do use Logflare.DataCase alias Logflare.{User, Billing, Billing.BillingAccount, Billing.PaymentMethod, Billing.Plan} + alias Logflare.Partners + describe "billing accounts" do @valid_attrs %{stripe_customer: "some stripe id"} @update_attrs %{stripe_customer: "some stripe other id"} @@ -216,6 +218,19 @@ defmodule Logflare.BillingTest do assert %Plan{name: "Custom"} = Billing.get_plan_by_user(ba.user) end + test "get_plan_by_user/1 with partner upgrade/downgrade" do + insert(:plan, name: "Free") + insert(:plan, name: "Enterprise") + user = insert(:user) + partner = insert(:partner, users: [user]) + assert %Plan{name: "Free"} = Billing.get_plan_by_user(user) + # upgrade user + Partners.upgrade_user(partner,user ) + assert %Plan{name: "Enterprise"} = Billing.get_plan_by_user(user) + + + end + test "change_plan/1 returns changeset" do plan = insert(:plan) assert %Ecto.Changeset{} = Billing.change_plan(plan) diff --git a/test/logflare/partners_test.exs b/test/logflare/partners_test.exs index fc3227556..45d2fef0c 100644 --- a/test/logflare/partners_test.exs +++ b/test/logflare/partners_test.exs @@ -2,6 +2,7 @@ defmodule Logflare.PartnerTest do use Logflare.DataCase alias Logflare.Partners + alias Logflare.Partners.PartnerUser alias Logflare.Repo alias Logflare.User @@ -102,4 +103,17 @@ defmodule Logflare.PartnerTest do assert {:error, :not_found} = Partners.delete_user(partner, user) end end + + test "upgrade_user/2, downgrade_user/2, user_upgraded?/1" do + user = insert(:user) + partner = insert(:partner, users: [user]) +assert Partners.user_upgraded?(user) == false + assert {:ok, %PartnerUser{upgraded: true}} = Partners.upgrade_user(partner, user) + assert Partners.user_upgraded?(user) + assert {:ok, %PartnerUser{upgraded: false}} = Partners.downgrade_user(partner, user) + assert Partners.user_upgraded?(user) == false + + assert Partners.user_upgraded?(insert(:user)) == false + end + end diff --git a/test/logflare_web/controllers/api/partner/user_controller_test.exs b/test/logflare_web/controllers/api/partner/user_controller_test.exs index f7b20167f..ad738eb21 100644 --- a/test/logflare_web/controllers/api/partner/user_controller_test.exs +++ b/test/logflare_web/controllers/api/partner/user_controller_test.exs @@ -134,6 +134,29 @@ defmodule LogflareWeb.Api.Partner.UserControllerTest do end end + describe "PUT user tiers" do + test "upgrade/downgrade", %{conn: conn} do + user = insert(:user) + partner = insert(:partner, users: [user]) + + # upgrade + assert %{"tier"=> "metered"} = + conn + |> add_partner_access_token(partner) + |> put(~p"/api/partner/users/#{user.token}/upgrade") + |> json_response(200) + + # downgrade + assert %{"tier"=> "free"} = + conn + |> recycle() + |> add_partner_access_token(partner) + |> put(~p"/api/partner/users/#{user.token}/downgrade") + |> json_response(200) + + end + end + describe "GET user usage" do test "returns 200 and the usage for a given user", %{ conn: conn, From f7c788009edd88e240de46c2ce58d80f8d619d3f Mon Sep 17 00:00:00 2001 From: Ziinc Date: Tue, 19 Dec 2023 15:45:25 +0800 Subject: [PATCH 2/5] Update lib/logflare/partners.ex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Łukasz Jan Niemier --- lib/logflare/partners.ex | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/logflare/partners.ex b/lib/logflare/partners.ex index 59127fa30..f2062c7ec 100644 --- a/lib/logflare/partners.ex +++ b/lib/logflare/partners.ex @@ -122,11 +122,7 @@ defmodule Logflare.Partners do query = from(pu in PartnerUser, where: pu.user_id == ^id, select: pu.upgraded) - Repo.one(query) - |> case do - nil -> false - value -> value - end + Repo.one(query) || false end def upgrade_user(p, u), do: do_upgrade_downgrade(p, u, true) From 1107e8eac07724076f61f0544bc8b413140bc7a4 Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Tue, 19 Dec 2023 15:52:41 +0800 Subject: [PATCH 3/5] chore: PR comments --- lib/logflare/partners.ex | 12 ++++++++---- test/logflare/partners_test.exs | 12 +++++++----- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/lib/logflare/partners.ex b/lib/logflare/partners.ex index f2062c7ec..2cc477bf7 100644 --- a/lib/logflare/partners.ex +++ b/lib/logflare/partners.ex @@ -130,10 +130,14 @@ defmodule Logflare.Partners do def do_upgrade_downgrade(%Partner{id: partner_id}, %User{id: user_id}, value) do query = - from(pu in PartnerUser, where: pu.partner_id == ^partner_id and pu.user_id == ^user_id) - - Repo.update_all(query, set: [upgraded: value]) + from(pu in PartnerUser, + where: pu.partner_id == ^partner_id and pu.user_id == ^user_id, + select: pu + ) - {:ok, Repo.one(query)} + case Repo.update_all(query, set: [upgraded: value]) do + {1, [partner_user]} -> {:ok, partner_user} + _ -> {:error, :not_found} + end end end diff --git a/test/logflare/partners_test.exs b/test/logflare/partners_test.exs index 45d2fef0c..4149246a5 100644 --- a/test/logflare/partners_test.exs +++ b/test/logflare/partners_test.exs @@ -107,13 +107,15 @@ defmodule Logflare.PartnerTest do test "upgrade_user/2, downgrade_user/2, user_upgraded?/1" do user = insert(:user) partner = insert(:partner, users: [user]) -assert Partners.user_upgraded?(user) == false - assert {:ok, %PartnerUser{upgraded: true}} = Partners.upgrade_user(partner, user) - assert Partners.user_upgraded?(user) - assert {:ok, %PartnerUser{upgraded: false}} = Partners.downgrade_user(partner, user) - assert Partners.user_upgraded?(user) == false + assert Partners.user_upgraded?(user) == false + assert {:ok, %PartnerUser{upgraded: true}} = Partners.upgrade_user(partner, user) + assert Partners.user_upgraded?(user) + assert {:ok, %PartnerUser{upgraded: false}} = Partners.downgrade_user(partner, user) + assert Partners.user_upgraded?(user) == false assert Partners.user_upgraded?(insert(:user)) == false + + assert {:error, :not_found} = Partners.upgrade_user(partner, insert(:user)) end end From 64976f01add3d8f65818acb4e46825048790fa72 Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Thu, 21 Dec 2023 02:22:39 +0800 Subject: [PATCH 4/5] chore: version bump --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index b7fd43df7..b068c030e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.5.12 \ No newline at end of file +1.5.13 \ No newline at end of file From 0fbfec5eb614e90d7b89b06e6ae0b46b8681a4bb Mon Sep 17 00:00:00 2001 From: Ziinc Date: Thu, 21 Dec 2023 02:46:58 +0800 Subject: [PATCH 5/5] Update lib/logflare/billing.ex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Łukasz Jan Niemier --- lib/logflare/billing.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/logflare/billing.ex b/lib/logflare/billing.ex index f9c9bc2dd..1005ebac7 100644 --- a/lib/logflare/billing.ex +++ b/lib/logflare/billing.ex @@ -330,7 +330,7 @@ defmodule Logflare.Billing do SingleTenant.single_tenant?() -> get_plan_by(name: "Enterprise") - Partners.user_upgraded?(user) == true -> + Partners.user_upgraded?(user) -> get_plan_by(name: "Enterprise") user.billing_enabled == false ->