diff --git a/crud.py b/crud.py index 9642a83..8996a2e 100644 --- a/crud.py +++ b/crud.py @@ -1,4 +1,3 @@ -import json from datetime import datetime, timedelta, timezone from typing import Optional @@ -7,30 +6,6 @@ from lnbits.helpers import urlsafe_short_hash from .models import CreateEvent, Event, Ticket, TicketExtra - -def _parse_ticket_row(row) -> dict: - """ - Parse a database row into a dict suitable for Ticket model creation. - Handles: - - Empty string to None conversion for name/email - - JSON string to dict conversion for extra field - """ - ticket_data = dict(row) - - # Convert empty strings back to None for the model - if ticket_data.get("name") == "": - ticket_data["name"] = None - if ticket_data.get("email") == "": - ticket_data["email"] = None - - # Parse extra field from JSON string if needed - # (db.insert() serializes to JSON, but manual fetchone/fetchall returns string) - extra = ticket_data.get("extra") - if isinstance(extra, str): - ticket_data["extra"] = json.loads(extra) - - return ticket_data - db = Database("ext_events") @@ -119,7 +94,14 @@ async def get_ticket(payment_hash: str) -> Optional[Ticket]: if not row: return None - return Ticket(**_parse_ticket_row(row)) + # Convert empty strings back to None for the model + ticket_data = dict(row) + if ticket_data.get("name") == "": + ticket_data["name"] = None + if ticket_data.get("email") == "": + ticket_data["email"] = None + + return Ticket(**ticket_data) async def get_tickets(wallet_ids: str | list[str]) -> list[Ticket]: @@ -128,7 +110,17 @@ async def get_tickets(wallet_ids: str | list[str]) -> list[Ticket]: q = ",".join([f"'{wallet_id}'" for wallet_id in wallet_ids]) rows = await db.fetchall(f"SELECT * FROM events.ticket WHERE wallet IN ({q})") - return [Ticket(**_parse_ticket_row(row)) for row in rows] + tickets = [] + for row in rows: + # Convert empty strings back to None for the model + ticket_data = dict(row) + if ticket_data.get("name") == "": + ticket_data["name"] = None + if ticket_data.get("email") == "": + ticket_data["email"] = None + tickets.append(Ticket(**ticket_data)) + + return tickets async def get_tickets_by_user_id(user_id: str) -> list[Ticket]: @@ -138,7 +130,17 @@ async def get_tickets_by_user_id(user_id: str) -> list[Ticket]: {"user_id": user_id} ) - return [Ticket(**_parse_ticket_row(row)) for row in rows] + tickets = [] + for row in rows: + # Convert empty strings back to None for the model + ticket_data = dict(row) + if ticket_data.get("name") == "": + ticket_data["name"] = None + if ticket_data.get("email") == "": + ticket_data["email"] = None + tickets.append(Ticket(**ticket_data)) + + return tickets async def delete_ticket(payment_hash: str) -> None: @@ -200,26 +202,6 @@ async def get_all_events() -> list[Event]: ) -async def get_public_events() -> list[Event]: - """Get approved, non-canceled events for public display.""" - return await db.fetchall( - """ - SELECT * FROM events.events - WHERE status = 'approved' AND canceled = FALSE - ORDER BY event_start_date ASC - """, - model=Event, - ) - - -async def get_pending_events() -> list[Event]: - """Get proposed events awaiting admin approval.""" - return await db.fetchall( - "SELECT * FROM events.events WHERE status = 'proposed' ORDER BY time DESC", - model=Event, - ) - - async def delete_event(event_id: str) -> None: await db.execute("DELETE FROM events.events WHERE id = :id", {"id": event_id}) @@ -230,4 +212,14 @@ async def get_event_tickets(event_id: str) -> list[Ticket]: {"event": event_id}, ) - return [Ticket(**_parse_ticket_row(row)) for row in rows] + tickets = [] + for row in rows: + # Convert empty strings back to None for the model + ticket_data = dict(row) + if ticket_data.get("name") == "": + ticket_data["name"] = None + if ticket_data.get("email") == "": + ticket_data["email"] = None + tickets.append(Ticket(**ticket_data)) + + return tickets diff --git a/migrations.py b/migrations.py index 357c3ed..9ed982b 100644 --- a/migrations.py +++ b/migrations.py @@ -191,14 +191,3 @@ async def m007_add_extra_fields(db): # Add 'extra' column to ticket table await db.execute("ALTER TABLE events.ticket ADD COLUMN extra TEXT;") - - -async def m008_add_event_status(db): - """ - Add status column to events table for proposal/approval workflow. - Values: 'proposed', 'approved', 'rejected'. - Default 'approved' for backward compatibility with existing events. - """ - await db.execute( - "ALTER TABLE events.events ADD COLUMN status TEXT NOT NULL DEFAULT 'approved';" - ) diff --git a/models.py b/models.py index 78917d4..b05a5da 100644 --- a/models.py +++ b/models.py @@ -39,7 +39,6 @@ class CreateEvent(BaseModel): price_per_ticket: float = Query(..., ge=0) banner: Optional[str] = None extra: EventExtra = Field(default_factory=EventExtra) - status: str = "approved" # proposed, approved, rejected class CreateTicket(BaseModel): @@ -79,7 +78,6 @@ class Event(BaseModel): sold: int = 0 banner: str | None = None extra: EventExtra = Field(default_factory=EventExtra) - status: str = "approved" # proposed, approved, rejected class TicketExtra(BaseModel): diff --git a/views_api.py b/views_api.py index 6fae87a..ada7323 100644 --- a/views_api.py +++ b/views_api.py @@ -24,8 +24,6 @@ from .crud import ( get_event, get_event_tickets, get_events, - get_pending_events, - get_public_events, get_ticket, get_tickets, get_tickets_by_user_id, @@ -56,10 +54,12 @@ async def api_events( @events_api_router.get("/api/v1/events/public") async def api_events_public(): """ - Retrieve approved, non-canceled events for public display. - No authentication required. + Retrieve all events in the database with read-only access. + This endpoint allows access to all events using any valid API key (read access). """ - events = await get_public_events() + # Get all events from the database without wallet filtering + from .crud import get_all_events + events = await get_all_events() return [event.dict() for event in events] @@ -128,75 +128,6 @@ async def api_form_delete( return "", HTTPStatus.NO_CONTENT -#########Event Approval########## - - -@events_api_router.post("/api/v1/events/propose") -async def api_event_propose( - data: CreateEvent, - wallet: WalletTypeInfo = Depends(require_invoice_key), -): - """ - Propose a new event for admin approval. - Requires invoice key (any authenticated user, not admin-only). - """ - data.status = "proposed" - data.wallet = wallet.wallet.id - event = await create_event(data) - return event.dict() - - -@events_api_router.get("/api/v1/events/pending") -async def api_events_pending( - wallet: WalletTypeInfo = Depends(require_admin_key), -): - """Get all proposed events awaiting approval. Admin only.""" - events = await get_pending_events() - return [event.dict() for event in events] - - -@events_api_router.put("/api/v1/events/{event_id}/approve") -async def api_event_approve( - event_id: str, - wallet: WalletTypeInfo = Depends(require_admin_key), -): - """Approve a proposed event. Admin only.""" - event = await get_event(event_id) - if not event: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="Event does not exist." - ) - if event.status != "proposed": - raise HTTPException( - status_code=HTTPStatus.BAD_REQUEST, - detail=f"Event is already {event.status}.", - ) - event.status = "approved" - event = await update_event(event) - return event.dict() - - -@events_api_router.put("/api/v1/events/{event_id}/reject") -async def api_event_reject( - event_id: str, - wallet: WalletTypeInfo = Depends(require_admin_key), -): - """Reject a proposed event. Admin only.""" - event = await get_event(event_id) - if not event: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="Event does not exist." - ) - if event.status != "proposed": - raise HTTPException( - status_code=HTTPStatus.BAD_REQUEST, - detail=f"Event is already {event.status}.", - ) - event.status = "rejected" - event = await update_event(event) - return event.dict() - - #########Tickets########## @@ -276,7 +207,7 @@ async def api_ticket_make_ticket_user_id(event_id: str, user_id: str): @events_api_router.get("/api/v1/tickets/{event_id}/{name}/{email}") -async def api_ticket_make_ticket(event_id, name, email, promo_code=None, refund_address=None): +async def api_ticket_make_ticket(event_id, name, email, promo_code, refund_address): event = await get_event(event_id) if not event: raise HTTPException(