Skip to content

Commit 7711fe6

Browse files
begedinjoshsmith
authored andcommitted
Add explicit ignoring of some event types during webhook processing
1 parent d94c251 commit 7711fe6

7 files changed

Lines changed: 122 additions & 9 deletions

File tree

lib/code_corps/stripe_service/webhook_processing/event_handler.ex

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
defmodule CodeCorps.StripeService.WebhookProcessing.EventHandler do
22
alias CodeCorps.{StripeEvent, Repo}
3-
alias CodeCorps.StripeService.WebhookProcessing.{ConnectEventHandler, PlatformEventHandler}
43
alias CodeCorps.StripeService.Adapters.StripeEventAdapter
4+
alias CodeCorps.StripeService.WebhookProcessing.{
5+
ConnectEventHandler, IgnoredEventHandler, PlatformEventHandler
6+
}
57

6-
def handle(%Stripe.Event{} = api_event, handler) do
8+
def handle(%Stripe.Event{type: type} = api_event, handler) do
79
with {:ok, endpoint} <- infer_endpoint_from_handler(handler),
810
{:ok, %StripeEvent{} = local_event} <- find_or_create_event(api_event, endpoint)
911
do
10-
call_handler(api_event, local_event, handler)
12+
case IgnoredEventHandler.should_handle?(type) do
13+
true -> call_ignored_handler(local_event)
14+
false -> call_handler(api_event, local_event, handler)
15+
end
1116
else
1217
failure -> failure
1318
end
@@ -34,6 +39,8 @@ defmodule CodeCorps.StripeService.WebhookProcessing.EventHandler do
3439
end
3540
end
3641

42+
defp call_ignored_handler(local_event), do: IgnoredEventHandler.handle(local_event)
43+
3744
defp call_handler(api_event, local_event, handler) do
3845
# results are multiple, so we convert the tuple to list for easier matching
3946
case api_event |> handler.handle_event |> Tuple.to_list do
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
defmodule CodeCorps.StripeService.WebhookProcessing.IgnoredEventHandler do
2+
alias CodeCorps.{StripeEvent, Repo}
3+
4+
@ignored_event_types [
5+
"application_fee.created",
6+
"customer.created",
7+
"customer.source.created",
8+
"customer.subscription.created",
9+
"invoice.created",
10+
"plan.created"
11+
]
12+
13+
@doc """
14+
Determines if an event type should be handled by __MODULE__
15+
16+
Returns true or false depending on specified type
17+
"""
18+
@spec should_handle?(String.t) :: boolean
19+
def should_handle?(type), do: Enum.member?(ignored_event_types, type)
20+
21+
@doc """
22+
Returns a list of event types which are being explicitly ignored by the application.
23+
"""
24+
@spec ignored_event_types :: list
25+
def ignored_event_types, do: @ignored_event_types
26+
27+
@doc """
28+
Takes in a `CodeCorps.StripeEvent` to be processed as "ignored".
29+
Determines the reason for ignoring the event, then updates the record to
30+
`status: "ignored"` and `ignored_reason: inferred_message`
31+
32+
Returns `{:ok, %CodeCorps.StripeEvent{}}
33+
"""
34+
@spec handle(StripeEvent.t) :: {:ok, StripeEvent.t}
35+
def handle(%StripeEvent{type: type} = local_event) do
36+
with ignored_reason <- get_reason(type) do
37+
local_event |> set_ignored(ignored_reason)
38+
end
39+
end
40+
41+
@spec get_reason(String.t) :: String.t
42+
defp get_reason("application_fee.created"), do: "We don't make use of the application fee object."
43+
defp get_reason("customer.created"), do: "Customers are only created from the client."
44+
defp get_reason("customer.source.created"), do: "Cards are only created from the client. No need to handle"
45+
defp get_reason("customer.subscription.created"), do: "Subscriptions are only created from the client."
46+
defp get_reason("invoice.created"), do: "We prefer to handle other lifecycle events for invoices, like payment_succeeded."
47+
defp get_reason("plan.created"), do: "Plans are only created from the client."
48+
49+
@spec set_ignored(StripeEvent.t, String.t) :: {:ok, StripeEvent.t}
50+
defp set_ignored(%StripeEvent{} = local_event, ignored_reason) do
51+
local_event
52+
|> StripeEvent.update_changeset(%{status: "ignored", ignored_reason: ignored_reason})
53+
|> Repo.update
54+
end
55+
end
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
defmodule CodeCorps.Repo.Migrations.AddIgnoredReasonToStripeEvents do
2+
use Ecto.Migration
3+
4+
def change do
5+
alter table(:stripe_events) do
6+
add :ignored_reason, :string
7+
end
8+
end
9+
end

priv/repo/structure.sql

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
-- PostgreSQL database dump
33
--
44

5-
-- Dumped from database version 9.5.4
6-
-- Dumped by pg_dump version 9.5.4
5+
-- Dumped from database version 9.5.1
6+
-- Dumped by pg_dump version 9.5.1
77

88
SET statement_timeout = 0;
99
SET lock_timeout = 0;
@@ -739,7 +739,8 @@ CREATE TABLE stripe_events (
739739
endpoint character varying(255) NOT NULL,
740740
user_id character varying(255),
741741
object_id character varying(255) NOT NULL,
742-
object_type character varying(255) NOT NULL
742+
object_type character varying(255) NOT NULL,
743+
ignored_reason character varying(255)
743744
);
744745

745746

@@ -2277,5 +2278,5 @@ ALTER TABLE ONLY user_skills
22772278
-- PostgreSQL database dump complete
22782279
--
22792280

2280-
INSERT INTO "schema_migrations" (version) VALUES (20160723215749), (20160804000000), (20160804001111), (20160805132301), (20160805203929), (20160808143454), (20160809214736), (20160810124357), (20160815125009), (20160815143002), (20160816020347), (20160816034021), (20160817220118), (20160818000944), (20160818132546), (20160820113856), (20160820164905), (20160822002438), (20160822004056), (20160822011624), (20160822020401), (20160822044612), (20160830081224), (20160830224802), (20160911233738), (20160912002705), (20160912145957), (20160918003206), (20160928232404), (20161003185918), (20161019090945), (20161019110737), (20161020144622), (20161021131026), (20161031001615), (20161121005339), (20161121014050), (20161121043941), (20161121045709), (20161122015942), (20161123081114), (20161123150943), (20161124085742), (20161125200620), (20161126045705), (20161127054559), (20161205024856), (20161207112519), (20161209192504), (20161212005641), (20161214005935), (20161215052051), (20161216051447), (20161218005913), (20161219160401), (20161219163909), (20161220141753), (20161221085759), (20161226213600), (20161231063614), (20170102130055), (20170102181053), (20170104113708), (20170104212623), (20170104235423), (20170106013143), (20170115035159);
2281+
INSERT INTO "schema_migrations" (version) VALUES (20160723215749), (20160804000000), (20160804001111), (20160805132301), (20160805203929), (20160808143454), (20160809214736), (20160810124357), (20160815125009), (20160815143002), (20160816020347), (20160816034021), (20160817220118), (20160818000944), (20160818132546), (20160820113856), (20160820164905), (20160822002438), (20160822004056), (20160822011624), (20160822020401), (20160822044612), (20160830081224), (20160830224802), (20160911233738), (20160912002705), (20160912145957), (20160918003206), (20160928232404), (20161003185918), (20161019090945), (20161019110737), (20161020144622), (20161021131026), (20161031001615), (20161121005339), (20161121014050), (20161121043941), (20161121045709), (20161122015942), (20161123081114), (20161123150943), (20161124085742), (20161125200620), (20161126045705), (20161127054559), (20161205024856), (20161207112519), (20161209192504), (20161212005641), (20161214005935), (20161215052051), (20161216051447), (20161218005913), (20161219160401), (20161219163909), (20161220141753), (20161221085759), (20161226213600), (20161231063614), (20170102130055), (20170102181053), (20170104113708), (20170104212623), (20170104235423), (20170106013143), (20170115035159), (20170115230549);
22812282

test/lib/code_corps/stripe_service/webhook_processing/event_handler_test.exs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,4 +234,14 @@ defmodule CodeCorps.StripeService.WebhookProcessing.EventHandlerTest do
234234
assert {:error, :already_processing} == EventHandler.handle(event, PlatformEventHandler)
235235
end
236236
end
237+
238+
describe "ignored events" do
239+
test "properly sets as ignored" do
240+
event = build_event("application_fee.created")
241+
{:ok, event} = EventHandler.handle(event, PlatformEventHandler)
242+
243+
assert event.status == "ignored"
244+
assert event.ignored_reason
245+
end
246+
end
237247
end
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
defmodule CodeCorps.StripeService.WebhookProcessing.IgnoredEventHandlerTest do
2+
use CodeCorps.ModelCase
3+
4+
alias CodeCorps.StripeService.WebhookProcessing.IgnoredEventHandler
5+
6+
defp ignored?(type) do
7+
event = insert(:stripe_event, type: type)
8+
{:ok, event} = IgnoredEventHandler.handle(event)
9+
10+
event.ignored_reason && event.status == "ignored"
11+
end
12+
13+
describe "handle/1" do
14+
test "ignores events from the ignored events list" do
15+
IgnoredEventHandler.ignored_event_types
16+
|> Enum.each(fn(type) -> assert ignored?(type) end)
17+
18+
assert_raise(FunctionClauseError, fn -> ignored?("some.other.type") end)
19+
end
20+
end
21+
22+
describe "should_handle?/1" do
23+
test "returns true for types from the ignored list" do
24+
IgnoredEventHandler.ignored_event_types
25+
|> Enum.each(fn(type) -> assert IgnoredEventHandler.should_handle?(type) end)
26+
27+
refute IgnoredEventHandler.should_handle?("some.other.type")
28+
end
29+
end
30+
end

web/models/stripe_event.ex

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ defmodule CodeCorps.StripeEvent do
2424
schema "stripe_events" do
2525
field :endpoint, :string, null: false
2626
field :id_from_stripe, :string, null: false
27+
field :ignored_reason, :string
2728
field :object_id, :string
2829
field :object_type, :string
2930
field :status, :string, default: "unprocessed"
@@ -54,7 +55,7 @@ defmodule CodeCorps.StripeEvent do
5455
"""
5556
def update_changeset(struct, params) do
5657
struct
57-
|> cast(params, [:status])
58+
|> cast(params, [:ignored_reason, :status])
5859
|> validate_required([:status])
5960
|> validate_inclusion(:status, states)
6061
end
@@ -64,6 +65,6 @@ defmodule CodeCorps.StripeEvent do
6465
end
6566

6667
defp states do
67-
~w{ errored processed processing unhandled unprocessed }
68+
~w{ errored ignored processed processing unhandled unprocessed }
6869
end
6970
end

0 commit comments

Comments
 (0)