feat: tickets-by-user endpoint + Nostr-driven inventory sync #15

Merged
padreug merged 3 commits from tickets-nostr-sync into main 2026-05-23 18:50:53 +00:00
Showing only changes of commit 814581f307 - Show all commits

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>
Padreug 2026-05-23 20:30:03 +02:00

View file

@ -14,11 +14,12 @@ from fastapi import (
) )
from lnbits.core.crud import get_user from lnbits.core.crud import get_user
from lnbits.core.crud.wallets import get_wallet 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.models.payments import CreateInvoice
from lnbits.core.services import create_payment_request from lnbits.core.services import create_payment_request
from lnbits.decorators import ( from lnbits.decorators import (
check_admin, check_admin,
check_user_exists,
require_admin_key, require_admin_key,
require_invoice_key, require_invoice_key,
) )
@ -45,6 +46,7 @@ from .crud import (
get_settings, get_settings,
get_ticket, get_ticket,
get_tickets, get_tickets,
get_tickets_by_user_id,
purge_unpaid_tickets, purge_unpaid_tickets,
update_event, update_event,
update_settings, update_settings,
@ -399,6 +401,27 @@ async def api_tickets(
return await get_tickets(wallet_ids) 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) @tickets_api_router.get("/{ticket_id}", response_model=PublicTicket)
async def api_get_ticket(ticket_id: str) -> Ticket: async def api_get_ticket(ticket_id: str) -> Ticket:
ticket = await get_ticket(ticket_id) ticket = await get_ticket(ticket_id)