Skip to content

Commit

Permalink
feat(backend): return all the owner's tickets
Browse files Browse the repository at this point in the history
  • Loading branch information
0xLucqs committed Oct 14, 2024
1 parent 0ec8231 commit 0f96cc8
Show file tree
Hide file tree
Showing 7 changed files with 172 additions and 8 deletions.
10 changes: 5 additions & 5 deletions backend/lib/peach/ticket.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ defmodule Peach.Ticket do

schema "tickets" do
field :owner, :string
field :balance, :integer
field :tier_id, :id

belongs_to :ticket_tier, Peach.TicketTier

timestamps(type: :utc_datetime)
end

@doc false
def changeset(ticket, attrs) do
ticket
|> cast(attrs, [:owner, :balance, :tier_id])
|> validate_required([:owner, :balance, :tier_id])
|> validate_length(:owner, max: 66)
|> cast(attrs, [:owner])
|> validate_required([:owner])
|> validate_format(:owner, ~r/^0x[0-9a-fA-F]{1,64}$/)

Check warning on line 21 in backend/lib/peach/ticket.ex

View check run for this annotation

Codecov / codecov/patch

backend/lib/peach/ticket.ex#L21

Added line #L21 was not covered by tests
end
end
18 changes: 18 additions & 0 deletions backend/lib/peach/tickets.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
defmodule Peach.Tickets do
@moduledoc """
Manages the tickets for the peach app
"""
alias Peach.Repo
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
end
39 changes: 39 additions & 0 deletions backend/lib/peach_web/controllers/ticket_controller.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
defmodule PeachWeb.TicketController do
use PeachWeb, :controller
alias Peach.Tickets

def get_tickets_with_event_by_address(conn, %{"address" => address}) do
# Fetch the tickets with preloaded ticket_tier and event associations
tickets = Tickets.list_tickets_with_event_by_owner(address)

# 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.map(fn {event, tickets} ->
# Group tickets by tier within each event
tickets_by_tier =
tickets
|> Enum.group_by(fn ticket -> ticket.ticket_tier end)
|> Enum.map(fn {tier, tickets} ->
%{
"tier_id" => tier.id,
"name" => tier.name,
"description" => tier.description,
"ticket_ids" => Enum.map(tickets, & &1.id) |> Enum.sort()
}
end)

%{
"name" => event.name,
"location" => event.location,
"date" => event.date,
"cover" => event.cover,
"tickets" => tickets_by_tier
}
end)

# Wrap the result in a top-level map with "events" key
json(conn, %{events: events_with_tickets})
end
end
1 change: 1 addition & 0 deletions backend/lib/peach_web/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ 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
get "/tickets/:address", TicketController, :get_tickets_with_event_by_address
end

# Enable LiveDashboard and Swoosh mailbox preview in development
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ defmodule Peach.Repo.Migrations.CreateTickets do
def change do
create table(:tickets) do
add :owner, :string
add :balance, :integer
add :tier_id, references(:ticket_tiers, on_delete: :nothing)
add :ticket_tier_id, references(:ticket_tiers, on_delete: :nothing)

timestamps(type: :utc_datetime)
end

create index(:tickets, [:tier_id])
create index(:tickets, [:ticket_tier_id])
end
end
105 changes: 105 additions & 0 deletions backend/test/peach_web/controllers/ticket_controller_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
defmodule PeachWeb.TicketControllerTest do
use PeachWeb.ConnCase, async: true
alias Peach.{Event, Repo, Ticket, TicketTier}

setup do
# Create an event
event =
Repo.insert!(%Event{
name: "Blockchain Conference",
date: ~N[2024-11-10 00:00:00],
description: "A blockchain event",
location: "San Francisco, CA",
cover: "https://example.com/cover.jpg",
treasury: "0x1234567890abcdef1234567890abcdef12345678"
})

# Create ticket tiers associated with the event
vip_tier =
Repo.insert!(%TicketTier{
name: "VIP",
description: "Access to VIP sessions",
max_supply: 100,
event_id: event.id
})

standard_tier =
Repo.insert!(%TicketTier{
name: "Standard",
description: "General admission",
max_supply: 200,
event_id: event.id
})

# 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
})

# 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
})

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

# Make the created data available for all tests
{:ok, event: event, vip_ticket: vip_ticket, standard_ticket: standard_ticket}
end

test "returns events with tickets grouped by event for a given owner", %{
conn: conn,
vip_ticket: vip_ticket,
standard_ticket: standard_ticket
} do
# Send the GET request to the endpoint
conn = get(conn, "/api/tickets/0xdead")

# Expected JSON structure
expected_response = %{
"events" => [
%{
"name" => "Blockchain Conference",
"location" => "San Francisco, CA",
"date" => "2024-11-10T00:00:00",
"cover" => "https://example.com/cover.jpg",
"tickets" => [
%{
"tier_id" => vip_ticket.ticket_tier_id,
"name" => "VIP",
"description" => "Access to VIP sessions",
"ticket_ids" => [1, 2]
},
%{
"tier_id" => standard_ticket.ticket_tier_id,
"name" => "Standard",
"description" => "General admission",
"ticket_ids" => [3]
}
]
}
]
}

# Assert that the response matches the expected JSON structure
assert json_response(conn, 200) == expected_response
end

test "returns an empty events list if no tickets are found for the address", %{conn: conn} do
# Send the GET request to the endpoint with an address that has no tickets
conn = get(conn, "/api/tickets/0xnonexistentaddress")

# Assert that the response is an empty list under "events"
assert json_response(conn, 200) == %{"events" => []}
end
end
2 changes: 2 additions & 0 deletions backend/test/support/data_case.ex
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ defmodule Peach.DataCase do
pid = Sandbox.start_owner!(Peach.Repo, shared: not tags[:async])
# Reset the sequence for the `events` table before each test
Peach.Repo.query!("ALTER SEQUENCE events_id_seq RESTART WITH 1")
Peach.Repo.query!("ALTER SEQUENCE tickets_id_seq RESTART WITH 1")
Peach.Repo.query!("ALTER SEQUENCE ticket_tiers_id_seq RESTART WITH 1")
on_exit(fn -> Sandbox.stop_owner(pid) end)
end

Expand Down

0 comments on commit 0f96cc8

Please sign in to comment.