Skip to content

Commit

Permalink
Merge pull request #647 from code-corps/645-split-up-event-handler
Browse files Browse the repository at this point in the history
Separate IgnoredEventHandler behavior for connect and platform events.
  • Loading branch information
begedin committed Jan 19, 2017
2 parents e8a931c + deb8f5b commit 339e94d
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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",
Expand All @@ -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".
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 339e94d

Please sign in to comment.