feat: expose GET /tickets/user/{user_id} endpoint

The webapp My Tickets view + the owned-ticket badges in the
activities feed both rely on this endpoint to enumerate a buyer's
tickets across all events. The CRUD function already existed
(`get_tickets_by_user_id`); just expose it.

Auth: Bearer access token (the same shape the webapp already sends
to other LNbits endpoints). The path param must match the token-
bound user.id — users can only enumerate their own tickets, not
anyone else's by ID-guessing.

Returns full `Ticket` rows rather than `PublicTicket` because the
owner needs the payment_hash (for the QR) + the `extra` envelope
(for refund / promo / notification state) in My Tickets.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Padreug 2026-05-23 20:30:03 +02:00
commit 814581f307

View file

@ -14,11 +14,12 @@ from fastapi import (
)
from lnbits.core.crud import get_user
from lnbits.core.crud.wallets import get_wallet
from lnbits.core.models import Account, WalletTypeInfo
from lnbits.core.models import Account, User, WalletTypeInfo
from lnbits.core.models.payments import CreateInvoice
from lnbits.core.services import create_payment_request
from lnbits.decorators import (
check_admin,
check_user_exists,
require_admin_key,
require_invoice_key,
)
@ -45,6 +46,7 @@ from .crud import (
get_settings,
get_ticket,
get_tickets,
get_tickets_by_user_id,
purge_unpaid_tickets,
update_event,
update_settings,
@ -399,6 +401,27 @@ async def api_tickets(
return await get_tickets(wallet_ids)
@tickets_api_router.get("/user/{user_id}")
async def api_tickets_by_user(
user_id: str,
user: User = Depends(check_user_exists),
) -> list[Ticket]:
"""All tickets for the authenticated user.
The `user_id` path param must match the token-bound user so a
Bearer-authenticated session can only enumerate its own tickets.
Returns full `Ticket` rows (not `PublicTicket`) since the owner
needs the payment_hash to render the QR + the `extra` envelope
to surface payment/refund state in My Tickets.
"""
if user_id != user.id:
raise HTTPException(
status_code=HTTPStatus.FORBIDDEN,
detail="Can only fetch your own tickets.",
)
return await get_tickets_by_user_id(user_id)
@tickets_api_router.get("/{ticket_id}", response_model=PublicTicket)
async def api_get_ticket(ticket_id: str) -> Ticket:
ticket = await get_ticket(ticket_id)