Refunds can double-pay, and the public GET /api/v1/events/{id} cancels and refunds as a side effect #70
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
refund_tickets(services.py:494-506) fires the LNURL payout and only afterwards setsticket.extra.refunded = True. There is no claim beforeexecute(), so two overlapping runs both seerefunded == Falseand both pay. One of the triggers isapi_get_event(views_api.py:310-315): an unauthenticated GET that, for a conditional event whose window closed undermin_tickets, setsevent.canceled = True, persists it, and callsrefund_tickets. Any crawler, double-click or retry storm on the public event page can fan out concurrent refund loops; the organiser's wallet pays out N times per ticket.Fix direction: add a
refund_statuscolumn (none -> refunding -> refunded) and claim each ticket with a conditional UPDATE before paying, releasing the claim if the payout fails; makeapi_get_eventread-only and move auto-cancel of underfunded, closed events to a scheduled task plus the owner-onlyapi_event_cancel. Sandbox PR #14 (second commit) implements exactly this, includingtests/test_refund_idempotency.py. Also worth folding in:purge_unpaid_ticketsis still a DELETE executed from the same GET (views_api.py:281).Found during reforge run #1 (sandbox events#4).