Skip to content

Commit dcc7921

Browse files
committed
refactor controller for better control and o11y
1 parent e3589d2 commit dcc7921

File tree

5 files changed

+65
-46
lines changed

5 files changed

+65
-46
lines changed

lib/algora/bounties/bounties.ex

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ defmodule Algora.Bounties do
5656
{:error, %{errors: [ticket_id: {_, [constraint: :unique, constraint_name: _]}]}} ->
5757
{:error, :already_exists}
5858

59-
{:error, _changeset} ->
60-
{:error, :internal_server_error}
59+
{:error, _changeset} = error ->
60+
error
6161
end
6262
end
6363

@@ -147,8 +147,8 @@ defmodule Algora.Bounties do
147147
{:error, %{errors: [ticket_id: {_, [constraint: :unique, constraint_name: _]}]}} ->
148148
{:error, :already_exists}
149149

150-
{:error, _changeset} ->
151-
{:error, :internal_server_error}
150+
{:error, _changeset} = error ->
151+
error
152152
end
153153
end
154154

lib/algora_web/controllers/webhooks/github_controller.ex

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,23 @@ defmodule AlgoraWeb.Webhooks.GithubController do
1313
# TODO: auto-retry failed deliveries with exponential backoff
1414

1515
def new(conn, params) do
16-
case Webhook.new(conn) do
17-
{:ok, %Webhook{delivery: _delivery, event: event, installation_id: _installation_id}} ->
18-
author = get_author(event, params)
19-
body = get_body(event, params)
20-
process_commands(body, author, params)
21-
22-
conn |> put_status(:accepted) |> json(%{status: "ok"})
23-
16+
with {:ok, %Webhook{event: event}} <- Webhook.new(conn),
17+
{:ok, _} <- process_commands(event, params) do
18+
conn |> put_status(:accepted) |> json(%{status: "ok"})
19+
else
2420
{:error, :missing_header} ->
2521
conn |> put_status(:bad_request) |> json(%{error: "Missing header"})
2622

2723
{:error, :signature_mismatch} ->
2824
conn |> put_status(:unauthorized) |> json(%{error: "Signature mismatch"})
25+
26+
{:error, reason} ->
27+
Logger.error("Error processing webhook: #{inspect(reason)}")
28+
conn |> put_status(:internal_server_error) |> json(%{error: "Internal server error"})
2929
end
3030
rescue
3131
e ->
3232
Logger.error("Unexpected error: #{inspect(e)}")
33-
3433
conn |> put_status(:internal_server_error) |> json(%{error: "Internal server error"})
3534
end
3635

@@ -137,19 +136,33 @@ defmodule AlgoraWeb.Webhooks.GithubController do
137136
end
138137
end
139138

140-
defp execute_command({command, _} = args, _author, _params),
141-
do: Logger.info("Unhandled command: #{command} #{inspect(args)}")
139+
defp execute_command(_command, _author, _params) do
140+
{:error, :unhandled_command}
141+
end
142+
143+
def process_commands(event, params) do
144+
author = get_author(event, params)
145+
body = get_body(event, params)
142146

143-
def process_commands(body, author, params) when is_binary(body) do
144147
case Github.Command.parse(body) do
145-
{:ok, commands} -> Enum.map(commands, &execute_command(&1, author, params))
146-
# TODO: handle errors
147-
{:error, error} -> Logger.error("Error parsing commands: #{inspect(error)}")
148+
{:ok, commands} ->
149+
Enum.reduce_while(commands, {:ok, []}, fn command, {:ok, results} ->
150+
case execute_command(command, author, params) do
151+
{:ok, result} ->
152+
{:cont, {:ok, [result | results]}}
153+
154+
error ->
155+
Logger.error("Command execution failed for #{inspect(command)}: #{inspect(error)}")
156+
{:halt, error}
157+
end
158+
end)
159+
160+
{:error, reason} = error ->
161+
Logger.error("Error parsing commands: #{inspect(reason)}")
162+
error
148163
end
149164
end
150165

151-
def process_commands(_body, _author, _params), do: nil
152-
153166
defp get_author("issues", params), do: params["issue"]["user"]
154167
defp get_author("issue_comment", params), do: params["comment"]["user"]
155168
defp get_author("pull_request", params), do: params["pull_request"]["user"]

lib/algora_web/live/org/bounty_hook.ex

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,6 @@ defmodule AlgoraWeb.Org.BountyHook do
2727
{:error, :already_exists} ->
2828
{:halt, put_flash(socket, :warning, "You have already created a bounty for this ticket")}
2929

30-
{:error, :internal_server_error} ->
31-
{:halt, put_flash(socket, :error, "Something went wrong")}
32-
3330
{:error, _reason} ->
3431
changeset = add_error(socket.assigns.new_bounty_form.changeset, :github_issue_url, "Invalid URL")
3532
{:halt, assign(socket, :new_bounty_form, to_form(changeset))}

lib/algora_web/live/org/create_bounty_live.ex

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -468,9 +468,6 @@ defmodule AlgoraWeb.Org.CreateBountyLive do
468468
{:error, :already_exists} ->
469469
{:noreply, put_flash(socket, :warning, "You have already created a bounty for this ticket")}
470470

471-
{:error, :internal_server_error} ->
472-
{:noreply, put_flash(socket, :error, "Something went wrong")}
473-
474471
{:error, _reason} ->
475472
changeset = add_error(socket.assigns.new_bounty_form.changeset, :github_issue_url, "Invalid URL")
476473
{:noreply, assign(socket, :new_bounty_form, to_form(changeset))}

test/algora_web/controllers/webhooks/github_controller_test.exs

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -47,57 +47,66 @@ defmodule AlgoraWeb.Webhooks.GithubControllerTest do
4747

4848
@tag user: @unauthorized_user
4949
test "handles bounty command with unauthorized user", %{user: user} do
50-
assert process_bounty_command("/bounty $100", user)[:ok] == nil
51-
assert process_bounty_command("/bounty $100", user)[:error] == :unauthorized
50+
assert {:error, :unauthorized} = process_bounty_command("/bounty $100", user)
5251
end
5352

5453
test "handles bounty command without amount" do
55-
assert process_bounty_command("/bounty")[:ok] == nil
56-
assert process_bounty_command("/bounty")[:error] == nil
54+
assert {:ok, []} = process_bounty_command("/bounty")
5755
end
5856

5957
test "handles valid bounty command with $ prefix" do
60-
assert process_bounty_command("/bounty $100")[:ok].amount == ~M[100]usd
58+
assert {:ok, [bounty]} = process_bounty_command("/bounty $100")
59+
assert bounty.amount == ~M[100]usd
6160
end
6261

6362
test "handles invalid bounty command with $ suffix" do
64-
assert process_bounty_command("/bounty 100$")[:ok].amount == ~M[100]usd
63+
assert {:ok, [bounty]} = process_bounty_command("/bounty 100$")
64+
assert bounty.amount == ~M[100]usd
6565
end
6666

6767
test "handles bounty command without $ symbol" do
68-
assert process_bounty_command("/bounty 100")[:ok].amount == ~M[100]usd
68+
assert {:ok, [bounty]} = process_bounty_command("/bounty 100")
69+
assert bounty.amount == ~M[100]usd
6970
end
7071

7172
test "handles bounty command with decimal amount" do
72-
assert process_bounty_command("/bounty 100.50")[:ok].amount == ~M[100.50]usd
73+
assert {:ok, [bounty]} = process_bounty_command("/bounty 100.50")
74+
assert bounty.amount == ~M[100.50]usd
7375
end
7476

7577
test "handles bounty command with partial decimal amount" do
76-
assert process_bounty_command("/bounty 100.5")[:ok].amount == ~M[100.5]usd
78+
assert {:ok, [bounty]} = process_bounty_command("/bounty 100.5")
79+
assert bounty.amount == ~M[100.5]usd
7780
end
7881

7982
test "handles bounty command with decimal amount and $ prefix" do
80-
assert process_bounty_command("/bounty $100.50")[:ok].amount == ~M[100.50]usd
83+
assert {:ok, [bounty]} = process_bounty_command("/bounty $100.50")
84+
assert bounty.amount == ~M[100.50]usd
8185
end
8286

8387
test "handles bounty command with partial decimal amount and $ prefix" do
84-
assert process_bounty_command("/bounty $100.5")[:ok].amount == ~M[100.5]usd
88+
assert {:ok, [bounty]} = process_bounty_command("/bounty $100.5")
89+
assert bounty.amount == ~M[100.5]usd
8590
end
8691

8792
test "handles bounty command with decimal amount and $ suffix" do
88-
assert process_bounty_command("/bounty 100.50$")[:ok].amount == ~M[100.50]usd
93+
assert {:ok, [bounty]} = process_bounty_command("/bounty 100.50$")
94+
assert bounty.amount == ~M[100.50]usd
8995
end
9096

9197
test "handles bounty command with partial decimal amount and $ suffix" do
92-
assert process_bounty_command("/bounty 100.5$")[:ok].amount == ~M[100.5]usd
98+
assert {:ok, [bounty]} = process_bounty_command("/bounty 100.5$")
99+
assert bounty.amount == ~M[100.5]usd
93100
end
94101

95102
test "handles bounty command with comma separator" do
96-
assert process_bounty_command("/bounty 1,000")[:ok].amount == ~M[1000]usd
103+
assert {:ok, [bounty]} = process_bounty_command("/bounty 1,000")
104+
assert bounty.amount == ~M[1000]usd
97105
end
98106

99107
test "handles bounty command with comma separator and decimal amount" do
100-
assert process_bounty_command("/bounty 1,000.50")[:ok].amount == ~M[1000.50]usd
108+
assert {:ok, [bounty]} = process_bounty_command("/bounty 1,000.50")
109+
assert bounty.amount == ~M[1000.50]usd
101110
end
102111
end
103112

@@ -184,14 +193,17 @@ defmodule AlgoraWeb.Webhooks.GithubControllerTest do
184193
end
185194

186195
# Helper function to process bounty commands
187-
defp process_bounty_command(body, author \\ @admin_user) do
188-
full_body = """
196+
defp process_bounty_command(command, author \\ @admin_user) do
197+
body = """
189198
Lorem
190-
ipsum #{body} dolor
199+
ipsum #{command} dolor
191200
sit
192201
amet
193202
"""
194203

195-
GithubController.process_commands(full_body, %{"login" => author}, @params)
204+
GithubController.process_commands(
205+
"issue_comment",
206+
Map.put(@params, "comment", %{"user" => %{"login" => author}, "body" => body})
207+
)
196208
end
197209
end

0 commit comments

Comments
 (0)