From 34c04720a13408f269a0f1323124376db49d0648 Mon Sep 17 00:00:00 2001 From: LucasLvy Date: Tue, 15 Oct 2024 18:38:33 +0200 Subject: [PATCH 1/3] fuck phoenix parses everything as strings even integers fuck fuck fuck --- backend/lib/peach/events.ex | 77 +++++++++++++++++-- .../peach_web/controllers/event_controller.ex | 36 ++------- 2 files changed, 75 insertions(+), 38 deletions(-) diff --git a/backend/lib/peach/events.ex b/backend/lib/peach/events.ex index a1e8a6b..1437ec6 100644 --- a/backend/lib/peach/events.ex +++ b/backend/lib/peach/events.ex @@ -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. """ @@ -18,13 +21,73 @@ 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}) + when is_integer(after_event_id) and + is_integer(first) do + case NaiveDateTime.from_iso8601(after_datetime) do + {:ok, datetime} -> + {:ok, + Repo.all( + from e in Event, + where: e.end >= ^datetime and e.id > ^after_event_id, + order_by: [asc: e.start, asc: e.id], + limit: ^first + )} + + {:error, error} -> + {:error, %{after_datetime: error}} + end + end + + def get_events(%{after_datetime: after_datetime, after_event_id: after_event_id}) + when is_integer(after_event_id) do + {:ok, + 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: @default_limit + )} + end + + def get_events(%{after_datetime: after_datetime, limit: limit}) + when is_integer(limit) do + {:ok, + Repo.all( + from e in Event, + where: e.end >= ^after_datetime and e.id > @default_event_id, + order_by: [asc: e.start, asc: e.id], + limit: ^limit + )} + 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(%{after_datetime: _after_datetime, limit: _limit}) do + {:error, %{limit: "incorrect_type"}} + end + + def get_events(%{after_datetime: _after_datetime, after_event_id: _after_event_id}) do + {:error, %{after_event_id: "incorrect_type"}} + end + + def get_events(params) do + IO.inspect(params) + {:error, %{after_datetime: "Can't be blank"}} end @doc """ diff --git a/backend/lib/peach_web/controllers/event_controller.ex b/backend/lib/peach_web/controllers/event_controller.ex index 4775705..92ac05e 100644 --- a/backend/lib/peach_web/controllers/event_controller.ex +++ b/backend/lib/peach_web/controllers/event_controller.ex @@ -22,19 +22,11 @@ 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} -> + Enum.map(events, &format_event/1) + {:error, error} -> conn |> put_status(:unprocessable_entity) @@ -42,24 +34,6 @@ defmodule PeachWeb.EventController do 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, From 074f36a830ddf5d0aeca168480f39d5c6deafd7b Mon Sep 17 00:00:00 2001 From: LucasLvy Date: Wed, 16 Oct 2024 14:30:32 +0200 Subject: [PATCH 2/3] "better" error handling lol --- backend/lib/peach/events.ex | 88 +++++++++++-------- .../peach_web/controllers/event_controller.ex | 4 +- .../peach_web/controllers/get_events_test.exs | 31 +++++++ .../controllers/ticket_controller_test.exs | 20 ++--- 4 files changed, 95 insertions(+), 48 deletions(-) diff --git a/backend/lib/peach/events.ex b/backend/lib/peach/events.ex index 1437ec6..8c6b44b 100644 --- a/backend/lib/peach/events.ex +++ b/backend/lib/peach/events.ex @@ -21,47 +21,72 @@ 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_datetime, after_event_id: after_event_id, first: first}) - when is_integer(after_event_id) and - is_integer(first) do - case NaiveDateTime.from_iso8601(after_datetime) do - {:ok, datetime} -> + 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 > ^after_event_id, + where: e.end >= ^datetime and e.id > ^event_id, order_by: [asc: e.start, asc: e.id], limit: ^first )} - {:error, error} -> + {{: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}) - when is_integer(after_event_id) do - {:ok, - 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: @default_limit - )} + 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, limit: limit}) - when is_integer(limit) do - {:ok, - Repo.all( - from e in Event, - where: e.end >= ^after_datetime and e.id > @default_event_id, - order_by: [asc: e.start, asc: e.id], - limit: ^limit - )} + 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 + def get_events(%{"after_datetime" => after_datetime}) do case NaiveDateTime.from_iso8601(after_datetime) do {:ok, datetime} -> {:ok, @@ -77,16 +102,7 @@ defmodule Peach.Events do end end - def get_events(%{after_datetime: _after_datetime, limit: _limit}) do - {:error, %{limit: "incorrect_type"}} - end - - def get_events(%{after_datetime: _after_datetime, after_event_id: _after_event_id}) do - {:error, %{after_event_id: "incorrect_type"}} - end - - def get_events(params) do - IO.inspect(params) + def get_events(_params) do {:error, %{after_datetime: "Can't be blank"}} end diff --git a/backend/lib/peach_web/controllers/event_controller.ex b/backend/lib/peach_web/controllers/event_controller.ex index 92ac05e..0b0ced3 100644 --- a/backend/lib/peach_web/controllers/event_controller.ex +++ b/backend/lib/peach_web/controllers/event_controller.ex @@ -25,7 +25,9 @@ defmodule PeachWeb.EventController do # Fetch events and map them to desired structure case Events.get_events(params) do {:ok, events} -> - Enum.map(events, &format_event/1) + conn + |> put_status(:ok) + |> json(%{events: Enum.map(events, &format_event/1)}) {:error, error} -> conn diff --git a/backend/test/peach_web/controllers/get_events_test.exs b/backend/test/peach_web/controllers/get_events_test.exs index c4def76..52f208c 100644 --- a/backend/test/peach_web/controllers/get_events_test.exs +++ b/backend/test/peach_web/controllers/get_events_test.exs @@ -70,12 +70,43 @@ defmodule PeachWeb.GetEventControllerTest do 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 diff --git a/backend/test/peach_web/controllers/ticket_controller_test.exs b/backend/test/peach_web/controllers/ticket_controller_test.exs index 843d0d7..4e193f8 100644 --- a/backend/test/peach_web/controllers/ticket_controller_test.exs +++ b/backend/test/peach_web/controllers/ticket_controller_test.exs @@ -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 = @@ -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{ From 4c7337af7b5c791e6e4647077b968dd56b4e32e4 Mon Sep 17 00:00:00 2001 From: LucasLvy Date: Wed, 16 Oct 2024 15:17:40 +0200 Subject: [PATCH 3/3] fix coverage --- .github/workflows/elixir.yml | 18 ---- .../peach_web/controllers/get_events_test.exs | 92 ++++++++++++++----- 2 files changed, 68 insertions(+), 42 deletions(-) diff --git a/.github/workflows/elixir.yml b/.github/workflows/elixir.yml index f781866..d739017 100644 --- a/.github/workflows/elixir.yml +++ b/.github/workflows/elixir.yml @@ -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/setup-beam@v1.16 - 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 diff --git a/backend/test/peach_web/controllers/get_events_test.exs b/backend/test/peach_web/controllers/get_events_test.exs index 52f208c..3d515e5 100644 --- a/backend/test/peach_web/controllers/get_events_test.exs +++ b/backend/test/peach_web/controllers/get_events_test.exs @@ -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) @@ -61,10 +37,33 @@ 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 @@ -126,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