fix: require a capacity on every ticket wave
Some checks failed
lint.yml / fix: require a capacity on every ticket wave (pull_request) Failing after 0s
Some checks failed
lint.yml / fix: require a capacity on every ticket wave (pull_request) Failing after 0s
"Capacity is always required, there is no unlimited" was settled on #34 and enforced in #62 — but as a single number on the event. Since v1.6.8 capacity is per-wave and `event.amount_tickets` is a derived roll-up (`sync_event_ticket_waves`), so the rule had nothing holding it up at the level organisers actually set: the wave form's capacity input had no minimum, and nothing on the backend checked one at all. A zero-capacity wave can never be active — `get_active_ticket_waves` requires `amount_tickets > 0` — so it is the wave-level form of exactly what #62 removed: an event that looks on sale but refuses every purchase, on the card and at checkout both. `_validate_wave_capacity` now runs on create and update. Two details that matter: - it checks `ensure_ticket_waves(data)` rather than the raw list, so an event submitted with no waves is checked through the primary wave it is about to be given, not vacuously passed - on an edit it only checks waves NEW to the event. Selling out is the legitimate route to zero, and rejecting it would make a sold-out event uneditable — including the legacy zero-capacity rows this rule exists to let organisers fix Frontend: the wave dialog's capacity input gains the `min="1"` and hint the event-level field already had, and a new wave opens at 1 rather than 0. That default uses `??`, not `||` — a sold-out wave holds 0 and must keep showing it instead of silently regaining stock when saved. Also drops the stale `0 = unlimited / not ticketed` contract still documented on `CreateEvent.amount_tickets`, which has not been true since #62. 6 new tests; 120 pass. ruff, black, prettier clean; mypy error set unchanged from baseline.
This commit is contained in:
parent
15c2276e57
commit
ecd05b4168
5 changed files with 166 additions and 2 deletions
35
views_api.py
35
views_api.py
|
|
@ -328,6 +328,37 @@ async def api_get_event(event_id: str) -> Event:
|
|||
return event
|
||||
|
||||
|
||||
def _validate_wave_capacity(data: CreateEvent, existing: Event | None = None) -> None:
|
||||
"""Every ticket wave must state a real capacity.
|
||||
|
||||
"Capacity is always required, there is no unlimited" (#34, #62) was
|
||||
settled when capacity was a single number on the event. Since v1.6.8 it
|
||||
is per-wave and `event.amount_tickets` is a derived roll-up, so the rule
|
||||
has to be enforced where the organiser actually sets it — otherwise it
|
||||
only survives as a `min="1"` on one HTML input, which no API client is
|
||||
bound by.
|
||||
|
||||
A zero-capacity wave can never be active (`get_active_ticket_waves`
|
||||
requires `amount_tickets > 0`), so it is the wave-level form of exactly
|
||||
what #62 removed: an event that looks on sale but refuses every
|
||||
purchase.
|
||||
|
||||
Selling out is the one legitimate route to zero, so an edit only checks
|
||||
waves that are NEW to the event; waves already stored keep whatever
|
||||
sales decremented them to. `ensure_ticket_waves` is used rather than the
|
||||
raw list so an event submitted with no waves is checked through the
|
||||
primary wave it will be given.
|
||||
"""
|
||||
known = {wave.id for wave in (existing.extra.ticket_waves if existing else [])}
|
||||
for wave in ensure_ticket_waves(data):
|
||||
if wave.id in known or wave.amount_tickets >= 1:
|
||||
continue
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.BAD_REQUEST,
|
||||
detail=f"Ticket wave '{wave.title}' needs a capacity of at least 1.",
|
||||
)
|
||||
|
||||
|
||||
@events_api_router.post("")
|
||||
async def api_event_create(
|
||||
data: CreateEvent,
|
||||
|
|
@ -341,6 +372,8 @@ async def api_event_create(
|
|||
if not data.wallet:
|
||||
data.wallet = wallet.wallet.id
|
||||
|
||||
_validate_wave_capacity(data)
|
||||
|
||||
from lnbits.settings import settings
|
||||
|
||||
ext_settings = await get_settings()
|
||||
|
|
@ -383,6 +416,8 @@ async def api_event_update(
|
|||
if event.wallet != wallet.wallet.id:
|
||||
raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="Not your event.")
|
||||
|
||||
_validate_wave_capacity(data, event)
|
||||
|
||||
from lnbits.settings import settings
|
||||
|
||||
ext_settings = await get_settings()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue