From d140ae45ccc418d5ef15afa023bd5467e335ba88 Mon Sep 17 00:00:00 2001 From: Nikola Begedin Date: Thu, 19 Jan 2017 23:54:24 +0100 Subject: [PATCH] Separate IgnoredEventHandler behavior for connect and platform events. --- .../webhook_processing/event_handler.ex | 6 +- .../ignored_event_handler.ex | 62 ++++++++++++++----- .../ignored_event_handler_test.exs | 43 +++++++++---- 3 files changed, 79 insertions(+), 32 deletions(-) diff --git a/lib/code_corps/stripe_service/webhook_processing/event_handler.ex b/lib/code_corps/stripe_service/webhook_processing/event_handler.ex index c23626c41..2f57e789a 100644 --- a/lib/code_corps/stripe_service/webhook_processing/event_handler.ex +++ b/lib/code_corps/stripe_service/webhook_processing/event_handler.ex @@ -9,8 +9,8 @@ defmodule CodeCorps.StripeService.WebhookProcessing.EventHandler do with {:ok, endpoint} <- infer_endpoint_from_handler(handler), {:ok, %StripeEvent{} = local_event} <- find_or_create_event(api_event, endpoint) do - case IgnoredEventHandler.should_handle?(type) do - true -> call_ignored_handler(local_event) + case IgnoredEventHandler.should_handle?(type, handler) do + true -> call_ignored_handler(local_event, handler) false -> call_handler(api_event, local_event, handler) end else @@ -39,7 +39,7 @@ defmodule CodeCorps.StripeService.WebhookProcessing.EventHandler do end end - defp call_ignored_handler(local_event), do: IgnoredEventHandler.handle(local_event) + defp call_ignored_handler(local_event, handler), do: IgnoredEventHandler.handle(local_event, handler) defp call_handler(api_event, local_event, handler) do # results are multiple, so we convert the tuple to list for easier matching diff --git a/lib/code_corps/stripe_service/webhook_processing/ignored_event_handler.ex b/lib/code_corps/stripe_service/webhook_processing/ignored_event_handler.ex index 2f348bcd6..8c8080b7e 100644 --- a/lib/code_corps/stripe_service/webhook_processing/ignored_event_handler.ex +++ b/lib/code_corps/stripe_service/webhook_processing/ignored_event_handler.ex @@ -1,7 +1,10 @@ defmodule CodeCorps.StripeService.WebhookProcessing.IgnoredEventHandler do alias CodeCorps.{StripeEvent, Repo} + alias CodeCorps.StripeService.WebhookProcessing.{ + ConnectEventHandler, PlatformEventHandler + } - @ignored_event_types [ + @ignored_platform_event_types [ "account.external_account.created", "application_fee.created", "customer.created", @@ -11,19 +14,31 @@ defmodule CodeCorps.StripeService.WebhookProcessing.IgnoredEventHandler do "plan.created" ] + @ignored_connect_event_types [ + "account.external_account.created", + "application_fee.created", + "customer.created", + "customer.updated", + "customer.source.created", + "customer.subscription.created", + "invoice.created", + "plan.created" + ] + @doc """ Determines if an event type should be handled by __MODULE__ Returns true or false depending on specified type """ - @spec should_handle?(String.t) :: boolean - def should_handle?(type), do: Enum.member?(ignored_event_types, type) + @spec should_handle?(String.t, Module.t) :: boolean + def should_handle?(type, handler), do: handler |> ignored_event_types |> Enum.member?(type) @doc """ Returns a list of event types which are being explicitly ignored by the application. """ - @spec ignored_event_types :: list - def ignored_event_types, do: @ignored_event_types + @spec ignored_event_types(Module.t) :: list + def ignored_event_types(ConnectEventHandler), do: @ignored_connect_event_types + def ignored_event_types(PlatformEventHandler), do: @ignored_platform_event_types @doc """ Takes in a `CodeCorps.StripeEvent` to be processed as "ignored". @@ -32,21 +47,36 @@ defmodule CodeCorps.StripeService.WebhookProcessing.IgnoredEventHandler do Returns `{:ok, %CodeCorps.StripeEvent{}} """ - @spec handle(StripeEvent.t) :: {:ok, StripeEvent.t} - def handle(%StripeEvent{type: type} = local_event) do - with ignored_reason <- get_reason(type) do + @spec handle(StripeEvent.t, Module.t) :: {:ok, StripeEvent.t} + def handle(%StripeEvent{type: type} = local_event, handler) do + with ignored_reason <- get_reason(type, handler) do local_event |> set_ignored(ignored_reason) end end - @spec get_reason(String.t) :: String.t - defp get_reason("account.external_account.created"), do: "External accounts are stored locally upon updating a connect account." - defp get_reason("application_fee.created"), do: "We don't make use of the application fee object." - defp get_reason("customer.created"), do: "Customers are only created from the client." - defp get_reason("customer.source.created"), do: "Cards are only created from the client. No need to handle" - defp get_reason("customer.subscription.created"), do: "Subscriptions are only created from the client." - defp get_reason("invoice.created"), do: "We prefer to handle other lifecycle events for invoices, like payment_succeeded." - defp get_reason("plan.created"), do: "Plans are only created from the client." + @spec get_reason(String.t, Module.t) :: String.t + defp get_reason(type, ConnectEventHandler), do: get_connect_reason(type) + defp get_reason(type, PlatformEventHandler), do: get_platform_reason(type) + + @spec get_connect_reason(String.t) :: String.t + defp get_connect_reason("account.external_account.created"), do: "External accounts are stored locally upon updating a connect account." + defp get_connect_reason("application_fee.created"), do: "We don't make use of the application fee object." + defp get_connect_reason("customer.created"), do: "Customers are only created from the client." + defp get_connect_reason("customer.updated"), do: "We already propagate connect customer updates when a platform customer update is handled." + defp get_connect_reason("customer.source.created"), do: "Cards are only created from the client. No need to handle" + defp get_connect_reason("customer.subscription.created"), do: "Subscriptions are only created from the client." + defp get_connect_reason("invoice.created"), do: "We prefer to handle other lifecycle events for invoices, like payment_succeeded." + defp get_connect_reason("plan.created"), do: "Plans are only created from the client." + + @spec get_platform_reason(String.t) :: String.t + defp get_platform_reason("account.external_account.created"), do: "External accounts are stored locally upon updating a connect account." + defp get_platform_reason("application_fee.created"), do: "We don't make use of the application fee object." + defp get_platform_reason("customer.created"), do: "Customers are only created from the client." + defp get_platform_reason("customer.source.created"), do: "Cards are only created from the client. No need to handle" + defp get_platform_reason("customer.subscription.created"), do: "Subscriptions are only created from the client." + defp get_platform_reason("invoice.created"), do: "We prefer to handle other lifecycle events for invoices, like payment_succeeded." + defp get_platform_reason("plan.created"), do: "Plans are only created from the client." + @spec set_ignored(StripeEvent.t, String.t) :: {:ok, StripeEvent.t} defp set_ignored(%StripeEvent{} = local_event, ignored_reason) do diff --git a/test/lib/code_corps/stripe_service/webhook_processing/ignored_event_handler_test.exs b/test/lib/code_corps/stripe_service/webhook_processing/ignored_event_handler_test.exs index a7648c08a..14052a823 100644 --- a/test/lib/code_corps/stripe_service/webhook_processing/ignored_event_handler_test.exs +++ b/test/lib/code_corps/stripe_service/webhook_processing/ignored_event_handler_test.exs @@ -1,30 +1,47 @@ defmodule CodeCorps.StripeService.WebhookProcessing.IgnoredEventHandlerTest do use CodeCorps.ModelCase - alias CodeCorps.StripeService.WebhookProcessing.IgnoredEventHandler + alias CodeCorps.StripeService.WebhookProcessing.{ + ConnectEventHandler, IgnoredEventHandler, PlatformEventHandler + } - defp ignored?(type) do + @spec ignored?(String.t, Module.t) :: boolean + defp ignored?(type, handler) do event = insert(:stripe_event, type: type) - {:ok, event} = IgnoredEventHandler.handle(event) + {:ok, event} = IgnoredEventHandler.handle(event, handler) event.ignored_reason && event.status == "ignored" end - describe "handle/1" do - test "ignores events from the ignored events list" do - IgnoredEventHandler.ignored_event_types - |> Enum.each(fn(type) -> assert ignored?(type) end) + describe "handle/2" do + test "ignores events from the ignored platform events list" do + IgnoredEventHandler.ignored_event_types(PlatformEventHandler) + |> Enum.each(fn(type) -> assert ignored?(type, PlatformEventHandler) end) - assert_raise(FunctionClauseError, fn -> ignored?("some.other.type") end) + assert_raise(FunctionClauseError, fn -> ignored?("some.other.type", PlatformEventHandler) end) + end + + test "ignores events from the ignored connect events list" do + IgnoredEventHandler.ignored_event_types(ConnectEventHandler) + |> Enum.each(fn(type) -> assert ignored?(type, ConnectEventHandler) end) + + assert_raise(FunctionClauseError, fn -> ignored?("some.other.type", ConnectEventHandler) end) end end - describe "should_handle?/1" do - test "returns true for types from the ignored list" do - IgnoredEventHandler.ignored_event_types - |> Enum.each(fn(type) -> assert IgnoredEventHandler.should_handle?(type) end) + describe "should_handle?/2" do + test "returns true for types from the ignored platform events list" do + IgnoredEventHandler.ignored_event_types(PlatformEventHandler) + |> Enum.each(fn(type) -> assert IgnoredEventHandler.should_handle?(type, PlatformEventHandler) end) + + refute IgnoredEventHandler.should_handle?("some.other.type", PlatformEventHandler) + end + + test "returns true for types from the ignored connect events list" do + IgnoredEventHandler.ignored_event_types(ConnectEventHandler) + |> Enum.each(fn(type) -> assert IgnoredEventHandler.should_handle?(type, ConnectEventHandler) end) - refute IgnoredEventHandler.should_handle?("some.other.type") + refute IgnoredEventHandler.should_handle?("some.other.type", ConnectEventHandler) end end end