Skip to content

Commit d94c251

Browse files
begedinjoshsmith
authored andcommitted
Restructure WebhookProcessor to make testing easier
1 parent 51d3426 commit d94c251

17 files changed

Lines changed: 427 additions & 539 deletions
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
defmodule CodeCorps.StripeService.Events.AccountUpdated do
2-
def handle(%{"data" => %{"object" => %{"id" => id_from_stripe}}}) do
2+
def handle(%{data: %{object: %{id: id_from_stripe}}}) do
33
CodeCorps.StripeService.StripeConnectAccountService.update_from_stripe(id_from_stripe)
44
end
55
end
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
defmodule CodeCorps.StripeService.Events.ConnectExternalAccountCreated do
2-
def handle(%{"data" => %{"object" => %{"account" => account_id_from_stripe, "id" => id_from_stripe}}}) do
2+
def handle(%{data: %{object: %{account: account_id_from_stripe, id: id_from_stripe}}}) do
33
CodeCorps.StripeService.StripeConnectExternalAccountService.create(id_from_stripe, account_id_from_stripe)
44
end
55
end
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
defmodule CodeCorps.StripeService.Events.CustomerSourceUpdated do
2-
def handle(%{"data" => %{"object" => %{"id" => card_id, "object" => "card"}}}) do
2+
def handle(%{data: %{object: %Stripe.Card{id: card_id}}}) do
33
CodeCorps.StripeService.StripePlatformCardService.update_from_stripe(card_id)
44
end
55

6-
def handle(%{"data" => %{"object" => %{"id" => _, "object" => _}}}), do: {:error, :unsupported_object}
6+
def handle(_data), do: {:error, :unsupported_object}
77
end
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
defmodule CodeCorps.StripeService.Events.CustomerSubscriptionDeleted do
2-
def handle(%{"data" => %{"object" => %{"id" => stripe_sub_id, "customer" => connect_customer_id}}}) do
2+
def handle(%{data: %{object: %{id: stripe_sub_id, customer: connect_customer_id}}}) do
33
CodeCorps.StripeService.StripeConnectSubscriptionService.update_from_stripe(stripe_sub_id, connect_customer_id)
44
end
55
end
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
defmodule CodeCorps.StripeService.Events.CustomerSubscriptionUpdated do
2-
def handle(%{"data" => %{"object" => %{"id" => stripe_sub_id, "customer" => connect_customer_id}}}) do
2+
def handle(%{data: %{object: %{id: stripe_sub_id, customer: connect_customer_id}}}) do
33
CodeCorps.StripeService.StripeConnectSubscriptionService.update_from_stripe(stripe_sub_id, connect_customer_id)
44
end
55
end
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
defmodule CodeCorps.StripeService.Events.CustomerUpdated do
2-
def handle(%{"data" => %{"object" => %{"id" => id_from_stripe}}}) do
2+
def handle(%{data: %{object: %{id: id_from_stripe}}}) do
33
CodeCorps.StripeService.StripePlatformCustomerService.update_from_stripe(id_from_stripe)
44
end
55
end
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
defmodule CodeCorps.StripeService.Events.InvoicePaymentSucceeded do
2-
def handle(%{"data" => %{"object" => %{"id" => id_from_stripe, "customer" => customer_id_from_stripe}}}) do
2+
def handle(%{data: %{object:
3+
%{id: id_from_stripe, customer: customer_id_from_stripe}
4+
}}) do
35
CodeCorps.StripeService.StripeInvoiceService.create(id_from_stripe, customer_id_from_stripe)
46
end
57
end

lib/code_corps/stripe_service/webhook_processing/connect_event_handler.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ defmodule CodeCorps.StripeService.WebhookProcessing.ConnectEventHandler do
1313
in which the first member is `:ok`, followed by one or more other elements, usually modified records.
1414
* `{:ok, :unhandled_event}` if the specific event is not supported yet or at all
1515
"""
16-
def handle_event(%{"type" => type} = attributes), do: do_handle(type, attributes)
16+
def handle_event(%{type: type} = attributes), do: do_handle(type, attributes)
1717

1818
defp do_handle("account.updated", attributes), do: Events.AccountUpdated.handle(attributes)
1919
defp do_handle("account.external_account.created", attributes), do: Events.ConnectExternalAccountCreated.handle(attributes)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
defmodule CodeCorps.StripeService.WebhookProcessing.EnvironmentFilter do
2+
@moduledoc """
3+
Used to filter events based on environment
4+
"""
5+
6+
@doc """
7+
Returns true if the livemode attribute of the event matches
8+
the current environment of the Phoenix application.
9+
10+
- livemode events are processed only in production.
11+
- non-livemode events are processed in all other environments
12+
"""
13+
def environment_matches?(%{"livemode" => livemode}) do
14+
case Application.get_env(:code_corps, :stripe_env) do
15+
:prod -> livemode
16+
_ -> !livemode
17+
end
18+
end
19+
end
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
defmodule CodeCorps.StripeService.WebhookProcessing.EventHandler do
2+
alias CodeCorps.{StripeEvent, Repo}
3+
alias CodeCorps.StripeService.WebhookProcessing.{ConnectEventHandler, PlatformEventHandler}
4+
alias CodeCorps.StripeService.Adapters.StripeEventAdapter
5+
6+
def handle(%Stripe.Event{} = api_event, handler) do
7+
with {:ok, endpoint} <- infer_endpoint_from_handler(handler),
8+
{:ok, %StripeEvent{} = local_event} <- find_or_create_event(api_event, endpoint)
9+
do
10+
call_handler(api_event, local_event, handler)
11+
else
12+
failure -> failure
13+
end
14+
end
15+
16+
defp infer_endpoint_from_handler(ConnectEventHandler), do: {:ok, "connect"}
17+
defp infer_endpoint_from_handler(PlatformEventHandler), do: {:ok, "platform"}
18+
19+
defp find_or_create_event(%Stripe.Event{} = api_event, endpoint) do
20+
case find_event(api_event.id) do
21+
%StripeEvent{status: "processing"} -> {:error, :already_processing}
22+
%StripeEvent{} = local_event -> {:ok, local_event}
23+
nil -> create_event(api_event, endpoint)
24+
end
25+
end
26+
27+
defp find_event(id_from_stripe) do
28+
Repo.get_by(StripeEvent, id_from_stripe: id_from_stripe)
29+
end
30+
31+
defp create_event(%Stripe.Event{} = api_event, endpoint) do
32+
with {:ok, params} <- StripeEventAdapter.to_params(api_event, %{"endpoint" => endpoint}) do
33+
%StripeEvent{} |> StripeEvent.create_changeset(params) |> Repo.insert
34+
end
35+
end
36+
37+
defp call_handler(api_event, local_event, handler) do
38+
# results are multiple, so we convert the tuple to list for easier matching
39+
case api_event |> handler.handle_event |> Tuple.to_list do
40+
[:ok, :unhandled_event] -> local_event |> set_unhandled
41+
[:ok | _results] -> local_event |> set_processed
42+
[:error | _error] -> local_event |> set_errored
43+
end
44+
end
45+
46+
defp set_errored(%StripeEvent{} = local_event) do
47+
local_event |> StripeEvent.update_changeset(%{status: "errored"}) |> Repo.update
48+
end
49+
50+
defp set_processed(%StripeEvent{} = local_event) do
51+
local_event |> StripeEvent.update_changeset(%{status: "processed"}) |> Repo.update
52+
end
53+
54+
defp set_unhandled(%StripeEvent{} = local_event) do
55+
local_event |> StripeEvent.update_changeset(%{status: "unhandled"}) |> Repo.update
56+
end
57+
end

0 commit comments

Comments
 (0)