Skip to content

Commit

Permalink
Merge pull request #4 from keep-starknet-strange/lucas/backend
Browse files Browse the repository at this point in the history
feat(backend): get events with pagination
  • Loading branch information
0xLucqs authored Oct 15, 2024
2 parents 46780e7 + 4d83c50 commit fbe7195
Show file tree
Hide file tree
Showing 12 changed files with 272 additions and 39 deletions.
24 changes: 19 additions & 5 deletions backend/lib/peach/event.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ defmodule Peach.Event do
@derive Jason.Encoder
schema "events" do
field :name, :string
field :date, :naive_datetime
field :start, :naive_datetime
field :end, :naive_datetime
field :description, :string
field :location, :string
field :cover, :string
Expand All @@ -23,16 +24,29 @@ defmodule Peach.Event do
@doc false
def changeset(event, attrs) do
event
|> cast(attrs, [:name, :description, :location, :date, :cover, :treasury])
|> cast(attrs, [:name, :description, :location, :start, :end, :cover, :treasury])
|> cast_assoc(:ticket_tiers, with: &Peach.TicketTier.changeset/2, required: true)
|> validate_required([:name, :description, :location, :date, :cover, :treasury])
|> validate_required([:name, :description, :location, :start, :end, :cover, :treasury])
|> validate_format(:treasury, ~r/^0x[0-9a-fA-F]{1,64}$/)
|> validate_end_after_start()
end

def update_changeset(event, attrs) do
event
|> cast(attrs, [:name, :description, :location, :date, :cover, :treasury])
|> validate_required([:name, :description, :location, :date, :cover, :treasury])
|> cast(attrs, [:name, :description, :location, :start, :end, :cover, :treasury])
|> validate_required([:name, :description, :location, :start, :end, :cover, :treasury])
|> validate_format(:treasury, ~r/^0x[0-9a-fA-F]{1,64}$/)
|> validate_end_after_start()
end

defp validate_end_after_start(changeset) do
start_time = get_field(changeset, :start)
end_time = get_field(changeset, :end)

if start_time && end_time && NaiveDateTime.compare(end_time, start_time) != :gt do
add_error(changeset, :end, "must be after the start date and time")
else
changeset
end
end
end
36 changes: 30 additions & 6 deletions backend/lib/peach/events.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ defmodule Peach.Events do
"""
alias Peach.Event
alias Peach.Repo
import Ecto.Query

@doc """
Creates an event with the given attributes.
Expand All @@ -14,6 +15,18 @@ defmodule Peach.Events do
|> Repo.insert()
end

@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
)
end

@doc """
Updates the `name` field
"""
Expand All @@ -26,24 +39,35 @@ defmodule Peach.Events do
end

@doc """
Updates the `date` field
Updates the `description` field
"""
def update_event_date(event_id, date) do
def update_event_description(event_id, description) do
event = Repo.get!(Event, event_id)

event
|> Event.update_changeset(%{date: date})
|> Event.update_changeset(%{description: description})
|> Repo.update()
end

@doc """
Updates the `description` field
Updates the `end` field
"""
def update_event_description(event_id, description) do
def update_event_end(event_id, end_date) do
event = Repo.get!(Event, event_id)

event
|> Event.update_changeset(%{description: description})
|> Event.update_changeset(%{end: end_date})
|> Repo.update()
end

@doc """
Updates the `start` field
"""
def update_event_start(event_id, start) do
event = Repo.get!(Event, event_id)

event
|> Event.update_changeset(%{start: start})
|> Repo.update()
end

Expand Down
18 changes: 9 additions & 9 deletions backend/lib/peach/tickets.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ defmodule Peach.Tickets do
alias Peach.Ticket
import Ecto.Query

def list_tickets_with_event_by_owner(owner_address) do
Repo.all(
from t in Ticket,
where: t.owner == ^owner_address,
join: tier in assoc(t, :ticket_tier),
join: event in assoc(tier, :event),
preload: [ticket_tier: {tier, event: event}]
)
end
def list_tickets_with_event_by_owner(owner_address),
do:
Repo.all(
from t in Ticket,
where: t.owner == ^owner_address,
join: tier in assoc(t, :ticket_tier),
join: event in assoc(tier, :event),
preload: [ticket_tier: {tier, event: event}]
)
end
79 changes: 75 additions & 4 deletions backend/lib/peach_web/controllers/event_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,82 @@ defmodule PeachWeb.EventController do
end
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
{: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,
"name" => event.name,
"description" => event.description,
"start" => event.start,
"end" => event.end,
"location" => event.location,
"cover" => event.cover
}

@doc """
Updates the name of an event.
"""
def update_event_name(conn, %{"id" => id, "name" => name}) do
case Peach.Events.update_event_name(id, name) do
case Events.update_event_name(id, name) do
{:ok, _event} ->
conn
|> put_status(:no_content)

{:error, changeset} ->
errors =
Ecto.Changeset.traverse_errors(changeset, fn {msg, _opts} ->
Phoenix.Naming.humanize(msg)
end)

conn
|> put_status(:bad_request)
|> json(%{errors: errors})
end
end

@doc """
Updates the starting datetime of an event.
"""
def update_event_start(conn, %{"id" => id, "start" => start}) do
case Events.update_event_start(id, start) do
{:ok, _event} ->
conn
|> put_status(:no_content)
Expand All @@ -43,10 +114,10 @@ defmodule PeachWeb.EventController do
end

@doc """
Updates the date of an event.
Updates the ending datetime of an event.
"""
def update_event_date(conn, %{"id" => id, "date" => date}) do
case Events.update_event_cover(id, date) do
def update_event_end(conn, %{"id" => id, "end" => end_date}) do
case Events.update_event_end(id, end_date) do
{:ok, _event} ->
conn
|> put_status(:no_content)
Expand Down
5 changes: 3 additions & 2 deletions backend/lib/peach_web/controllers/ticket_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ defmodule PeachWeb.TicketController do
# Group tickets by event and then by tier_id within each event
events_with_tickets =
tickets
|> Enum.group_by(fn ticket -> ticket.ticket_tier.event end)
|> Enum.group_by(& &1.ticket_tier.event)
|> Enum.map(fn {event, tickets} ->
# Group tickets by tier within each event
tickets_by_tier =
Expand All @@ -27,7 +27,8 @@ defmodule PeachWeb.TicketController do
%{
"name" => event.name,
"location" => event.location,
"date" => event.date,
"start" => event.start,
"end" => event.end,
"cover" => event.cover,
"tickets" => tickets_by_tier
}
Expand Down
3 changes: 3 additions & 0 deletions backend/lib/peach_web/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ defmodule PeachWeb.Router do
patch "/events/:id/location", EventController, :update_event_location
patch "/events/:id/cover", EventController, :update_event_cover
patch "/events/:id/treasury", EventController, :update_event_treasury
patch "/events/:id/start", EventController, :update_event_start
patch "/events/:id/end", EventController, :update_event_end
get "/events", EventController, :events
get "/tickets/:address", TicketController, :get_tickets_with_event_by_address
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ defmodule Peach.Repo.Migrations.CreateEvents do
add :name, :string
add :description, :string
add :location, :string
add :date, :utc_datetime
add :start, :utc_datetime
add :end, :utc_datetime
add :cover, :string
add :onchain, :boolean, default: false
add :treasury, :string
Expand Down
23 changes: 17 additions & 6 deletions backend/test/peach/events/event_db_setters_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ defmodule Peach.Events.EventDBSettersTest do
{:ok, event} =
Repo.insert(%Event{
name: "Original Name",
date: ~N[2024-01-01 10:00:00],
start: ~N[2024-01-01 10:00:00],
end: ~N[2024-01-01 15:00:00],
description: "Original description",
location: "Original location",
cover: "https://example.com/original_cover.jpg",
Expand All @@ -31,14 +32,24 @@ defmodule Peach.Events.EventDBSettersTest do
assert updated_event.name == updated_name
end

test "updates date in the database", %{event: event} do
test "updates end date in the database", %{event: event} do
new_date = ~N[2025-12-31 23:59:59]
Events.update_event_date(event.id, new_date)
Events.update_event_end(event.id, new_date)
updated_event = Repo.get!(Event, event.id)
assert updated_event.date == new_date
Events.update_event_date(event.id, 1)
assert updated_event.end == new_date
Events.update_event_end(event.id, 1)
updated_event = Repo.get!(Event, event.id)
assert updated_event.date == new_date
assert updated_event.end == new_date
end

test "updates start date in the database", %{event: event} do
new_date = ~N[2024-01-01 11:00:00]
Events.update_event_start(event.id, new_date)
updated_event = Repo.get!(Event, event.id)
assert updated_event.start == new_date
Events.update_event_start(event.id, 1)
updated_event = Repo.get!(Event, event.id)
assert updated_event.start == new_date
end

test "updates description in the database", %{event: event} do
Expand Down
7 changes: 4 additions & 3 deletions backend/test/peach_web/controllers/create_event_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ defmodule PeachWeb.EventCreateControllerTest do

@valid_event_attrs %{
"name" => "Blockchain Conference",
"date" => "2024-11-10T10:00:00",
"start" => "2024-11-10T10:00:00",
"end" => "2024-11-10T13:00:00",
"description" => "A conference about blockchain technology.",
"location" => "San Francisco, CA",
"cover" => "https://example.com/cover.jpg",
Expand Down Expand Up @@ -51,7 +52,7 @@ defmodule PeachWeb.EventCreateControllerTest do
end

test "returns error when required fields are missing", %{conn: conn} do
required_fields = ["name", "date", "description", "location", "cover", "ticket_tiers"]
required_fields = ["name", "start", "end", "description", "location", "cover", "ticket_tiers"]

Enum.each(required_fields, fn field ->
# Remove one required field at a time
Expand All @@ -70,7 +71,7 @@ defmodule PeachWeb.EventCreateControllerTest do
end

test "returns error when fields are in the wrong format", %{conn: conn} do
required_fields = ["name", "date", "description", "location", "cover", "ticket_tiers"]
required_fields = ["name", "start", "end", "description", "location", "cover", "ticket_tiers"]

Enum.each(required_fields, fn field ->
invalid_attrs =
Expand Down
Loading

0 comments on commit fbe7195

Please sign in to comment.