Skip to content

Commit

Permalink
Add checks for elapsed events in ticketing (#734)
Browse files Browse the repository at this point in the history
* Add check on event end time in cart endpoint

* Add tests

* Tweak frontend toast

* Reinsert comment

* style

* Remove extra query

* Add check to add_to_cart

* Add test to add_to_cart

* Minor fix

* Minor fix

* Disable "Get Tickets" button for elapsed events
  • Loading branch information
aviupadhyayula authored Oct 14, 2024
1 parent c888c78 commit 6295feb
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 8 deletions.
38 changes: 33 additions & 5 deletions backend/clubs/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2418,10 +2418,17 @@ def add_to_cart(self, request, *args, **kwargs):
event = self.get_object()
cart, _ = Cart.objects.get_or_create(owner=self.request.user)

# Check if the event has already ended
if event.end_time < timezone.now():
return Response(
{"detail": "This event has already ended", "success": False},
status=status.HTTP_403_FORBIDDEN,
)

# Cannot add tickets that haven't dropped yet
if event.ticket_drop_time and timezone.now() < event.ticket_drop_time:
return Response(
{"detail": "Ticket drop time has not yet elapsed"},
{"detail": "Ticket drop time has not yet elapsed", "success": False},
status=status.HTTP_403_FORBIDDEN,
)

Expand Down Expand Up @@ -2465,7 +2472,10 @@ def add_to_cart(self, request, *args, **kwargs):

if tickets.count() < count:
return Response(
{"detail": f"Not enough tickets of type {type} left!"},
{
"detail": f"Not enough tickets of type {type} left!",
"success": False,
},
status=status.HTTP_403_FORBIDDEN,
)
cart.tickets.add(*tickets[:count])
Expand Down Expand Up @@ -5141,8 +5151,12 @@ def cart(self, request, *args, **kwargs):
owner=self.request.user
)

now = timezone.now()

tickets_to_replace = cart.tickets.filter(
Q(owner__isnull=False) | Q(holder__isnull=False)
Q(owner__isnull=False)
| Q(holder__isnull=False)
| Q(event__end_time__lt=now)
).exclude(holder=self.request.user)

# In most cases, we won't need to replace, so exit early
Expand All @@ -5154,16 +5168,30 @@ def cart(self, request, *args, **kwargs):
},
)

# Attempt to replace all tickets that have gone stale
# Attempt to replace all tickets that have gone stale or are for elapsed events
replacement_tickets, sold_out_tickets = [], []

tickets_in_cart = cart.tickets.values_list("id", flat=True)
tickets_to_replace = tickets_to_replace.select_related("event")

for ticket_class in tickets_to_replace.values(
"type", "event", "event__name"
"type", "event", "event__name", "event__end_time"
).annotate(count=Count("id")):
# we don't need to lock, since we aren't updating holder/owner
if ticket_class["event__end_time"] < now:
# Event has elapsed, mark all tickets as sold out
sold_out_tickets.append(
{
"type": ticket_class["type"],
"event": {
"id": ticket_class["event"],
"name": ticket_class["event__name"],
},
"count": ticket_class["count"],
}
)
continue

available_tickets = Ticket.objects.filter(
event=ticket_class["event"],
type=ticket_class["type"],
Expand Down
55 changes: 55 additions & 0 deletions backend/tests/clubs/test_ticketing.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,27 @@ def test_add_to_cart(self):
self.assertEqual(cart.tickets.filter(type="normal").count(), 2, cart.tickets)
self.assertEqual(cart.tickets.filter(type="premium").count(), 1, cart.tickets)

def test_add_to_cart_elapsed_event(self):
self.client.login(username=self.user1.username, password="test")

# Set the event end time to the past
self.event1.end_time = timezone.now() - timezone.timedelta(days=1)
self.event1.save()

tickets_to_add = {
"quantities": [
{"type": "normal", "count": 1},
]
}
resp = self.client.post(
reverse("club-events-add-to-cart", args=(self.club1.code, self.event1.pk)),
tickets_to_add,
format="json",
)

self.assertEqual(resp.status_code, 403, resp.content)
self.assertIn("This event has already ended", resp.data["detail"], resp.data)

def test_add_to_cart_twice_accumulates(self):
self.client.login(username=self.user1.username, password="test")

Expand Down Expand Up @@ -948,6 +969,40 @@ def test_get_cart_replacement_required_sold_out(self):
to_add = set(map(lambda t: str(t.id), tickets_to_add))
self.assertEqual(len(in_cart & to_add), 0, in_cart | to_add)

def test_get_cart_elapsed_event(self):
self.client.login(username=self.user1.username, password="test")

# Add a few tickets
cart, _ = Cart.objects.get_or_create(owner=self.user1)
tickets_to_add = self.tickets1[:5]
for ticket in tickets_to_add:
cart.tickets.add(ticket)
cart.save()

# Set the event end time to the past
self.event1.end_time = timezone.now() - timezone.timedelta(days=1)
self.event1.save()

resp = self.client.get(reverse("tickets-cart"), format="json")
data = resp.json()

# The cart should now be empty
self.assertEqual(len(data["tickets"]), 0, data)

# All tickets should be in the sold out array
self.assertEqual(len(data["sold_out"]), 1, data)

expected_sold_out = {
"type": self.tickets1[0].type,
"event": {
"id": self.event1.id,
"name": self.event1.name,
},
"count": 5,
}
for key, val in expected_sold_out.items():
self.assertEqual(data["sold_out"][0][key], val, data)

def test_place_hold_on_tickets(self):
from clubs.views import TicketViewSet

Expand Down
2 changes: 1 addition & 1 deletion frontend/components/Tickets/CartTickets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ const CartTickets: React.FC<CartTicketsProps> = ({ tickets, soldOut }) => {
.forEach(
(ticket) => {
toast.error(
`${ticket.event.name} - ${ticket.type} is sold out and ${ticket.count} ticket${ticket.count && ticket.count > 1 ? 's have' : ' has'} been removed from your cart.`,
`${ticket.event.name} - ${ticket.type} is no longer available and ${ticket.count} ticket${ticket.count && ticket.count > 1 ? 's have' : ' has'} been removed from your cart.`,
{
style: { color: WHITE },
autoClose: false,
Expand Down
6 changes: 4 additions & 2 deletions frontend/pages/events/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -362,10 +362,12 @@ const EventPage: React.FC<EventPageProps> = ({
))}
<button
className="button is-primary is-fullwidth mt-4"
disabled={totalAvailableTickets === 0}
disabled={
totalAvailableTickets === 0 || endTime < DateTime.now()
}
onClick={() => setShowTicketModal(true)}
>
Get Tickets
{endTime < DateTime.now() ? 'Event Ended' : 'Get Tickets'}
</button>
</Card>
)}
Expand Down

0 comments on commit 6295feb

Please sign in to comment.