Skip to content

Commit

Permalink
Merge pull request #5 from keep-starknet-strange/lucas/backend
Browse files Browse the repository at this point in the history
refacto(backend): improve error handling
  • Loading branch information
0xLucqs authored Oct 16, 2024
2 parents fbe7195 + 4c7337a commit c83064f
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 91 deletions.
18 changes: 0 additions & 18 deletions .github/workflows/elixir.yml
Original file line number Diff line number Diff line change
Expand Up @@ -137,21 +137,3 @@ jobs:
run: mix deps.compile
- name: Run credo
run: mix credo --strict
coverage:
name: Elixir coverage
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./backend
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Elixir
uses: erlef/[email protected]
with:
elixir-version: ${{ env.ELIXIR_VERSION_SPEC }}
otp-version: ${{ env.OTP_VERSION_SPEC }}
- name: Install dependencies
run: mix deps.get
- name: Compile dependencies
run: mix deps.compile
93 changes: 86 additions & 7 deletions backend/lib/peach/events.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ defmodule Peach.Events do
alias Peach.Repo
import Ecto.Query

@default_limit 50
@default_event_id 0

@doc """
Creates an event with the given attributes.
"""
Expand All @@ -18,13 +21,89 @@ defmodule Peach.Events do
@doc """
Returns the `first` events that end after `after_time` and their id is after `after_event_id`
"""
def get_events(after_datetime, after_event_id, first) do
Repo.all(
from e in Event,
where: e.end >= ^after_datetime and e.id > ^after_event_id,
order_by: [asc: e.start, asc: e.id],
limit: ^first
)
def get_events(%{
"after_datetime" => after_datetime,
"after_event_id" => after_event_id,
"first" => first
}) do
case {NaiveDateTime.from_iso8601(after_datetime), Integer.parse(after_event_id),
Integer.parse(first)} do
{{:ok, datetime}, {event_id, _}, {first, _}} ->
{:ok,
Repo.all(
from e in Event,
where: e.end >= ^datetime and e.id > ^event_id,
order_by: [asc: e.start, asc: e.id],
limit: ^first
)}

{{:error, error}, _, _} ->
{:error, %{after_datetime: error}}

{_, :error, _} ->
{:error, %{after_event_id: "invalid_type"}}

{_, _, :error} ->
{:error, %{first: "invalid_type"}}
end
end

def get_events(%{"after_datetime" => after_datetime, "after_event_id" => after_event_id}) do
case {NaiveDateTime.from_iso8601(after_datetime), Integer.parse(after_event_id)} do
{{:ok, datetime}, {event_id, _}} ->
{:ok,
Repo.all(
from e in Event,
where: e.end >= ^datetime and e.id > ^event_id,
order_by: [asc: e.start, asc: e.id],
limit: ^@default_limit
)}

{{:error, error}, _} ->
{:error, %{after_datetime: error}}

{_, :error} ->
{:error, %{after_event_id: "invalid_type"}}
end
end

def get_events(%{"after_datetime" => after_datetime, "first" => limit}) do
case {NaiveDateTime.from_iso8601(after_datetime), Integer.parse(limit)} do
{{:ok, datetime}, {first, _}} ->
{:ok,
Repo.all(
from e in Event,
where: e.end >= ^datetime and e.id > ^@default_event_id,
order_by: [asc: e.start, asc: e.id],
limit: ^first
)}

{{:error, error}, _} ->
{:error, %{after_datetime: error}}

{_, :error} ->
{:error, %{first: "invalid_type"}}
end
end

def get_events(%{"after_datetime" => after_datetime}) do
case NaiveDateTime.from_iso8601(after_datetime) do
{:ok, datetime} ->
{:ok,
Repo.all(
from e in Event,
where: e.end >= ^datetime and e.id > @default_event_id,
order_by: [asc: e.start, asc: e.id],
limit: @default_limit
)}

{:error, error} ->
{:error, %{after_datetime: error}}
end
end

def get_events(_params) do
{:error, %{after_datetime: "Can't be blank"}}
end

@doc """
Expand Down
38 changes: 7 additions & 31 deletions backend/lib/peach_web/controllers/event_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -22,44 +22,20 @@ defmodule PeachWeb.EventController do
end

def events(conn, params) do
with {:ok, after_datetime} <- validate_datetime(Map.get(params, "after_datetime")),
{:ok, after_event_id} <-
validate_integer(Map.get(params, "after_event_id", 0), "after_event_id"),
{:ok, first} <- validate_integer(Map.get(params, "first", 50), "first") do
# Fetch events and map them to desired structure
events =
Events.get_events(after_datetime, after_event_id, first)
|> Enum.map(&format_event/1)

conn
|> put_status(:ok)
|> json(%{events: events})
else
# Fetch events and map them to desired structure
case Events.get_events(params) do
{:ok, events} ->
conn
|> put_status(:ok)
|> json(%{events: Enum.map(events, &format_event/1)})

{:error, error} ->
conn
|> put_status(:unprocessable_entity)
|> json(%{errors: error})
end
end

defp validate_datetime(nil), do: {:error, %{after_datetime: "Can't be blank"}}

defp validate_datetime(datetime_str) do
case NaiveDateTime.from_iso8601(datetime_str) do
{:ok, datetime} -> {:ok, datetime}
{:error, reason} -> {:error, %{after_datetime: reason}}
end
end

defp validate_integer(value, _field) when is_integer(value), do: {:ok, value}

defp validate_integer(value, field) do
case Integer.parse(value) do
{int, ""} -> {:ok, int}
_ -> {:error, %{field => "invalid_type"}}
end
end

defp format_event(event),
do: %{
"id" => event.id,
Expand Down
123 changes: 99 additions & 24 deletions backend/test/peach_web/controllers/get_events_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -29,30 +29,6 @@ defmodule PeachWeb.GetEventControllerTest do
{:ok, event1: event1, event2: event2, event3: event3}
end

test "returns events after specified time and id", %{conn: conn, event2: event2, event3: event3} do
after_datetime = "2024-11-08T00:00:00"
after_event_id = "#{event2.id}"
first = "10"

conn =
get(
conn,
"/api/events?after_datetime=#{after_datetime}&after_event_id=#{after_event_id}&first=#{first}"
)

assert json_response(conn, 200)["events"] == [
%{
"id" => event3.id,
"name" => event3.name,
"description" => event3.description,
"start" => NaiveDateTime.to_iso8601(event3.start),
"end" => NaiveDateTime.to_iso8601(event3.end),
"location" => event3.location,
"cover" => event3.cover
}
]
end

test "returns events without optional params", %{conn: conn} do
conn = get(conn, "/api/events")
response = json_response(conn, 422)
Expand All @@ -61,21 +37,75 @@ defmodule PeachWeb.GetEventControllerTest do

test "returns validation error for invalid after_datetime", %{conn: conn} do
after_datetime = "invalid-time-format"
after_event_id = 1
first = 10
conn = get(conn, "/api/events?after_datetime=#{after_datetime}")

response = json_response(conn, 422)
assert response["errors"]["after_datetime"] == "invalid_format"

conn =
get(conn, "/api/events?after_datetime=#{after_datetime}&after_event_id=#{after_event_id}")

response = json_response(conn, 422)
assert response["errors"]["after_datetime"] == "invalid_format"

conn =
get(conn, "/api/events?after_datetime=#{after_datetime}&first=#{first}")

response = json_response(conn, 422)
assert response["errors"]["after_datetime"] == "invalid_format"

conn =
get(
conn,
"/api/events?after_datetime=#{after_datetime}&after_event_id=#{after_event_id}&first=#{first}"
)

response = json_response(conn, 422)
assert response["errors"]["after_datetime"] == "invalid_format"
end

test "returns validation error for non-integer after_event_id", %{conn: conn} do
after_datetime = "2024-11-08T00:00:00"
after_event_id = "not-an-integer"
first = 10

conn =
get(conn, "/api/events?after_datetime=#{after_datetime}&after_event_id=#{after_event_id}")

response = json_response(conn, 422)
assert response["errors"]["after_event_id"] == "invalid_type"

conn =
get(
conn,
"/api/events?after_datetime=#{after_datetime}&after_event_id=#{after_event_id}&first=#{first}"
)

response = json_response(conn, 422)
assert response["errors"]["after_event_id"] == "invalid_type"
end

test "returns validation error for non-integer first", %{conn: conn} do
after_datetime = "2024-11-08T00:00:00"
after_event_id = 1
first = "not an integer"

conn =
get(conn, "/api/events?after_datetime=#{after_datetime}&first=#{first}")

response = json_response(conn, 422)
assert response["errors"]["first"] == "invalid_type"

conn =
get(
conn,
"/api/events?after_datetime=#{after_datetime}&after_event_id=#{after_event_id}&first=#{first}"
)

response = json_response(conn, 422)
assert response["errors"]["first"] == "invalid_type"
end

test "limits the number of events returned with first param", %{conn: conn, event2: event2} do
Expand All @@ -95,4 +125,49 @@ defmodule PeachWeb.GetEventControllerTest do
}
]
end

test "returns events after specified time and id", %{conn: conn, event2: event2, event3: event3} do
after_datetime = "2024-11-08T00:00:00"
after_event_id = "#{event2.id}"
first = "10"

expected_event =
[
%{
"id" => event3.id,
"name" => event3.name,
"description" => event3.description,
"start" => NaiveDateTime.to_iso8601(event3.start),
"end" => NaiveDateTime.to_iso8601(event3.end),
"location" => event3.location,
"cover" => event3.cover
}
]

conn =
get(
conn,
"/api/events?after_datetime=#{after_datetime}&after_event_id=#{after_event_id}&first=#{first}"
)

assert json_response(conn, 200)["events"] == expected_event

conn =
get(
conn,
"/api/events?after_datetime=#{after_datetime}&after_event_id=#{after_event_id}"
)

assert json_response(conn, 200)["events"] == expected_event

after_datetime = "2024-11-16T00:00:00"

conn =
get(
conn,
"/api/events?after_datetime=#{after_datetime}"
)

assert json_response(conn, 200)["events"] == expected_event
end
end
20 changes: 9 additions & 11 deletions backend/test/peach_web/controllers/ticket_controller_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,11 @@ defmodule PeachWeb.TicketControllerTest do
})

# Create tickets for the user address associated with the tiers
vip_ticket =
Repo.insert!(%Ticket{
owner: "0xdead",
# Using tier_id from the association
ticket_tier_id: vip_tier.id
})
Repo.insert!(%Ticket{
owner: "0xdead",
# Using tier_id from the association
ticket_tier_id: vip_tier.id
})

# Create tickets for the user address associated with the tiers
vip_ticket =
Expand All @@ -48,11 +47,10 @@ defmodule PeachWeb.TicketControllerTest do
ticket_tier_id: vip_tier.id
})

standard_ticket =
Repo.insert!(%Ticket{
owner: "0xdead",
ticket_tier_id: standard_tier.id
})
Repo.insert!(%Ticket{
owner: "0xdead",
ticket_tier_id: standard_tier.id
})

standard_ticket =
Repo.insert!(%Ticket{
Expand Down

0 comments on commit c83064f

Please sign in to comment.