Some checks failed
lint.yml / fix(nostr): always publish tickets_available, zero is not unlimited (pull_request) Failing after 0s
Omitting the tag used to mean "unlimited capacity". Nothing else in the codebase agreed: `api_get_event` and `api_ticket_create` both treat `amount_tickets < 1` as sold out. So a zero-capacity event advertised "Unlimited tickets" on the card while the detail page and the purchase both returned 410. Observed on aio-demo — three approved, listed, free events in that state. For `PKBVuusKikfJFU4PYGtBTW`: relay tickets_available absent -> webapp renders "Unlimited" GET event 410 "Event is sold out." POST ticket 410 "Event is sold out." The admin form was advertising it too (`min="0"`, `hint="0 = unlimited"`), so organizers were being invited into the broken state. Now the tag is always emitted and zero reads as sold out, which is what every other part of the system already believed. Clients that must handle an absent tag — a NIP-52 event from another publisher — are unaffected, since we simply never omit it. Scoped to removing the contradiction. Making capacity a *required* field is the other half of #34 and is blocked on the webapp: its create dialog uses a falsy check (`if (formValues.amount_tickets)`), so a 0 omits the field entirely and a server-side `ge=1` would 422 it. Refs #34
56 lines
1.7 KiB
Python
56 lines
1.7 KiB
Python
"""`tickets_available` is always published, including zero (#34).
|
|
|
|
Omitting the tag used to mean "unlimited", which contradicted every other
|
|
reader: `api_get_event` and `api_ticket_create` both treat
|
|
`amount_tickets < 1` as sold out. On aio-demo three zero-capacity events
|
|
advertised "Unlimited tickets" on the card while the detail endpoint and
|
|
the purchase both returned 410.
|
|
"""
|
|
|
|
from datetime import datetime, timezone
|
|
|
|
import pytest
|
|
|
|
from ..models import Event
|
|
from ..nostr_publisher import build_nip52_event
|
|
|
|
PUBKEY = "a" * 64
|
|
|
|
|
|
def _event(amount_tickets: int, sold: int = 0) -> Event:
|
|
return Event(
|
|
id="evt",
|
|
wallet="w",
|
|
name="Availability",
|
|
info="",
|
|
closing_date="2030-01-01",
|
|
event_start_date="2030-01-01T18:00",
|
|
event_end_date="2030-01-01T22:00",
|
|
currency="sat",
|
|
price_per_ticket=0,
|
|
amount_tickets=amount_tickets,
|
|
sold=sold,
|
|
time=datetime.now(timezone.utc),
|
|
status="approved",
|
|
)
|
|
|
|
|
|
def _tags(event: Event) -> dict[str, str]:
|
|
return {t[0]: t[1] for t in build_nip52_event(event, PUBKEY).tags if len(t) > 1}
|
|
|
|
|
|
@pytest.mark.parametrize("amount", [0, 1, 50])
|
|
def test_tickets_available_is_always_present(amount):
|
|
assert _tags(_event(amount))["tickets_available"] == str(amount)
|
|
|
|
|
|
def test_zero_capacity_reads_as_sold_out_not_unlimited():
|
|
"""The regression: an absent tag is what clients render as unlimited."""
|
|
tags = _tags(_event(0, sold=0))
|
|
assert "tickets_available" in tags
|
|
assert tags["tickets_available"] == "0"
|
|
|
|
|
|
def test_sold_out_after_selling_through_still_publishes_zero():
|
|
assert _tags(_event(0, sold=25))["tickets_available"] == "0"
|
|
assert _tags(_event(0, sold=25))["tickets_sold"] == "25"
|