diff --git a/lnbits/extensions/events/README.md b/lnbits/extensions/events/README.md deleted file mode 100644 index 11b62fecb..000000000 --- a/lnbits/extensions/events/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# Events - -## Sell tickets for events and use the built-in scanner for registering attendants - -Events alows you to make tickets for an event. Each ticket is in the form of a uniqque QR code. After registering, and paying for ticket, the user gets a QR code to present at registration/entrance. - -Events includes a shareable ticket scanner, which can be used to register attendees. - -## Usage - -1. Create an event\ - ![create event](https://i.imgur.com/dadK1dp.jpg) -2. Fill out the event information: - - - event name - - wallet (normally there's only one) - - event information - - closing date for event registration - - begin and end date of the event - - ![event info](https://imgur.com/KAv68Yr.jpg) - -3. Share the event registration link\ - ![event ticket](https://imgur.com/AQWUOBY.jpg) - - - ticket example\ - ![ticket example](https://i.imgur.com/trAVSLd.jpg) - - - QR code ticket, presented after invoice paid, to present at registration\ - ![event ticket](https://i.imgur.com/M0ROM82.jpg) - -4. Use the built-in ticket scanner to validate registered, and paid, attendees\ - ![ticket scanner](https://i.imgur.com/zrm9202.jpg) diff --git a/lnbits/extensions/events/__init__.py b/lnbits/extensions/events/__init__.py deleted file mode 100644 index b9283368b..000000000 --- a/lnbits/extensions/events/__init__.py +++ /dev/null @@ -1,35 +0,0 @@ -import asyncio - -from fastapi import APIRouter -from fastapi.staticfiles import StaticFiles - -from lnbits.db import Database -from lnbits.helpers import template_renderer -from lnbits.tasks import catch_everything_and_restart - -db = Database("ext_events") - - -events_ext: APIRouter = APIRouter(prefix="/events", tags=["Events"]) - -events_static_files = [ - { - "path": "/events/static", - "app": StaticFiles(packages=[("lnbits", "extensions/events/static")]), - "name": "events_static", - } -] - - -def events_renderer(): - return template_renderer(["lnbits/extensions/events/templates"]) - - -from .tasks import wait_for_paid_invoices -from .views import * # noqa: F401,F403 -from .views_api import * # noqa: F401,F403 - - -def events_start(): - loop = asyncio.get_event_loop() - loop.create_task(catch_everything_and_restart(wait_for_paid_invoices)) diff --git a/lnbits/extensions/events/config.json b/lnbits/extensions/events/config.json deleted file mode 100644 index a62bcc47a..000000000 --- a/lnbits/extensions/events/config.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "Events", - "short_description": "Sell and register event tickets", - "tile": "/events/static/image/events.png", - "contributors": ["benarc"] -} diff --git a/lnbits/extensions/events/crud.py b/lnbits/extensions/events/crud.py deleted file mode 100644 index 12cc73275..000000000 --- a/lnbits/extensions/events/crud.py +++ /dev/null @@ -1,144 +0,0 @@ -from typing import List, Optional, Union - -from lnbits.helpers import urlsafe_short_hash - -from . import db -from .models import CreateEvent, Events, Tickets - -# TICKETS - - -async def create_ticket( - payment_hash: str, wallet: str, event: str, name: str, email: str -) -> Tickets: - await db.execute( - """ - INSERT INTO events.ticket (id, wallet, event, name, email, registered, paid) - VALUES (?, ?, ?, ?, ?, ?, ?) - """, - (payment_hash, wallet, event, name, email, False, True), - ) - - # UPDATE EVENT DATA ON SOLD TICKET - eventdata = await get_event(event) - assert eventdata, "Couldn't get event from ticket being paid" - sold = eventdata.sold + 1 - amount_tickets = eventdata.amount_tickets - 1 - await db.execute( - """ - UPDATE events.events - SET sold = ?, amount_tickets = ? - WHERE id = ? - """, - (sold, amount_tickets, event), - ) - - ticket = await get_ticket(payment_hash) - assert ticket, "Newly created ticket couldn't be retrieved" - return ticket - - -async def get_ticket(payment_hash: str) -> Optional[Tickets]: - row = await db.fetchone("SELECT * FROM events.ticket WHERE id = ?", (payment_hash,)) - return Tickets(**row) if row else None - - -async def get_tickets(wallet_ids: Union[str, List[str]]) -> List[Tickets]: - if isinstance(wallet_ids, str): - wallet_ids = [wallet_ids] - - q = ",".join(["?"] * len(wallet_ids)) - rows = await db.fetchall( - f"SELECT * FROM events.ticket WHERE wallet IN ({q})", (*wallet_ids,) - ) - return [Tickets(**row) for row in rows] - - -async def delete_ticket(payment_hash: str) -> None: - await db.execute("DELETE FROM events.ticket WHERE id = ?", (payment_hash,)) - - -async def delete_event_tickets(event_id: str) -> None: - await db.execute("DELETE FROM events.ticket WHERE event = ?", (event_id,)) - - -# EVENTS - - -async def create_event(data: CreateEvent) -> Events: - event_id = urlsafe_short_hash() - await db.execute( - """ - INSERT INTO events.events (id, wallet, name, info, closing_date, event_start_date, event_end_date, amount_tickets, price_per_ticket, sold) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - """, - ( - event_id, - data.wallet, - data.name, - data.info, - data.closing_date, - data.event_start_date, - data.event_end_date, - data.amount_tickets, - data.price_per_ticket, - 0, - ), - ) - - event = await get_event(event_id) - assert event, "Newly created event couldn't be retrieved" - return event - - -async def update_event(event_id: str, **kwargs) -> Events: - q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()]) - await db.execute( - f"UPDATE events.events SET {q} WHERE id = ?", (*kwargs.values(), event_id) - ) - event = await get_event(event_id) - assert event, "Newly updated event couldn't be retrieved" - return event - - -async def get_event(event_id: str) -> Optional[Events]: - row = await db.fetchone("SELECT * FROM events.events WHERE id = ?", (event_id,)) - return Events(**row) if row else None - - -async def get_events(wallet_ids: Union[str, List[str]]) -> List[Events]: - if isinstance(wallet_ids, str): - wallet_ids = [wallet_ids] - - q = ",".join(["?"] * len(wallet_ids)) - rows = await db.fetchall( - f"SELECT * FROM events.events WHERE wallet IN ({q})", (*wallet_ids,) - ) - - return [Events(**row) for row in rows] - - -async def delete_event(event_id: str) -> None: - await db.execute("DELETE FROM events.events WHERE id = ?", (event_id,)) - - -# EVENTTICKETS - - -async def get_event_tickets(event_id: str, wallet_id: str) -> List[Tickets]: - rows = await db.fetchall( - "SELECT * FROM events.ticket WHERE wallet = ? AND event = ?", - (wallet_id, event_id), - ) - return [Tickets(**row) for row in rows] - - -async def reg_ticket(ticket_id: str) -> List[Tickets]: - await db.execute( - "UPDATE events.ticket SET registered = ? WHERE id = ?", (True, ticket_id) - ) - ticket = await db.fetchone("SELECT * FROM events.ticket WHERE id = ?", (ticket_id,)) - rows = await db.fetchall( - "SELECT * FROM events.ticket WHERE event = ?", (ticket[1],) - ) - return [Tickets(**row) for row in rows] diff --git a/lnbits/extensions/events/migrations.py b/lnbits/extensions/events/migrations.py deleted file mode 100644 index 5b9d53b05..000000000 --- a/lnbits/extensions/events/migrations.py +++ /dev/null @@ -1,83 +0,0 @@ -async def m001_initial(db): - - await db.execute( - """ - CREATE TABLE events.events ( - id TEXT PRIMARY KEY, - wallet TEXT NOT NULL, - name TEXT NOT NULL, - info TEXT NOT NULL, - closing_date TEXT NOT NULL, - event_start_date TEXT NOT NULL, - event_end_date TEXT NOT NULL, - amount_tickets INTEGER NOT NULL, - price_per_ticket INTEGER NOT NULL, - sold INTEGER NOT NULL, - time TIMESTAMP NOT NULL DEFAULT """ - + db.timestamp_now - + """ - ); - """ - ) - - await db.execute( - """ - CREATE TABLE events.tickets ( - id TEXT PRIMARY KEY, - wallet TEXT NOT NULL, - event TEXT NOT NULL, - name TEXT NOT NULL, - email TEXT NOT NULL, - registered BOOLEAN NOT NULL, - time TIMESTAMP NOT NULL DEFAULT """ - + db.timestamp_now - + """ - ); - """ - ) - - -async def m002_changed(db): - - await db.execute( - """ - CREATE TABLE events.ticket ( - id TEXT PRIMARY KEY, - wallet TEXT NOT NULL, - event TEXT NOT NULL, - name TEXT NOT NULL, - email TEXT NOT NULL, - registered BOOLEAN NOT NULL, - paid BOOLEAN NOT NULL, - time TIMESTAMP NOT NULL DEFAULT """ - + db.timestamp_now - + """ - ); - """ - ) - - for row in [list(row) for row in await db.fetchall("SELECT * FROM events.tickets")]: - usescsv = "" - - for i in range(row[5]): - if row[7]: - usescsv += "," + str(i + 1) - else: - usescsv += "," + str(1) - usescsv = usescsv[1:] - await db.execute( - """ - INSERT INTO events.ticket ( - id, - wallet, - event, - name, - email, - registered, - paid - ) - VALUES (?, ?, ?, ?, ?, ?, ?) - """, - (row[0], row[1], row[2], row[3], row[4], row[5], True), - ) - await db.execute("DROP TABLE events.tickets") diff --git a/lnbits/extensions/events/models.py b/lnbits/extensions/events/models.py deleted file mode 100644 index dd38e973a..000000000 --- a/lnbits/extensions/events/models.py +++ /dev/null @@ -1,43 +0,0 @@ -from fastapi.param_functions import Query -from pydantic import BaseModel - - -class CreateEvent(BaseModel): - wallet: str - name: str - info: str - closing_date: str - event_start_date: str - event_end_date: str - amount_tickets: int = Query(..., ge=0) - price_per_ticket: int = Query(..., ge=0) - - -class CreateTicket(BaseModel): - name: str - email: str - - -class Events(BaseModel): - id: str - wallet: str - name: str - info: str - closing_date: str - event_start_date: str - event_end_date: str - amount_tickets: int - price_per_ticket: int - sold: int - time: int - - -class Tickets(BaseModel): - id: str - wallet: str - event: str - name: str - email: str - registered: bool - paid: bool - time: int diff --git a/lnbits/extensions/events/static/image/events.png b/lnbits/extensions/events/static/image/events.png deleted file mode 100644 index 65c1bddb5..000000000 Binary files a/lnbits/extensions/events/static/image/events.png and /dev/null differ diff --git a/lnbits/extensions/events/tasks.py b/lnbits/extensions/events/tasks.py deleted file mode 100644 index 945e2d281..000000000 --- a/lnbits/extensions/events/tasks.py +++ /dev/null @@ -1,36 +0,0 @@ -import asyncio - -from lnbits.core.models import Payment -from lnbits.helpers import get_current_extension_name -from lnbits.tasks import register_invoice_listener - -from .models import CreateTicket -from .views_api import api_ticket_send_ticket - - -async def wait_for_paid_invoices(): - invoice_queue = asyncio.Queue() - register_invoice_listener(invoice_queue, get_current_extension_name()) - - while True: - payment = await invoice_queue.get() - await on_invoice_paid(payment) - - -async def on_invoice_paid(payment: Payment) -> None: - # (avoid loops) - if ( - payment.extra - and "events" == payment.extra.get("tag") - and payment.extra.get("name") - and payment.extra.get("email") - ): - await api_ticket_send_ticket( - payment.memo, - payment.payment_hash, - CreateTicket( - name=str(payment.extra.get("name")), - email=str(payment.extra.get("email")), - ), - ) - return diff --git a/lnbits/extensions/events/templates/events/_api_docs.html b/lnbits/extensions/events/templates/events/_api_docs.html deleted file mode 100644 index 9a24d7079..000000000 --- a/lnbits/extensions/events/templates/events/_api_docs.html +++ /dev/null @@ -1,25 +0,0 @@ - - - -
- Events: Sell and register ticket waves for an event -
-

- Events alows you to make a wave of tickets for an event, each ticket is - in the form of a unqiue QRcode, which the user presents at registration. - Events comes with a shareable ticket scanner, which can be used to - register attendees.
- - Created by, - Ben Arc - -

-
-
- -
diff --git a/lnbits/extensions/events/templates/events/display.html b/lnbits/extensions/events/templates/events/display.html deleted file mode 100644 index 45c2aca26..000000000 --- a/lnbits/extensions/events/templates/events/display.html +++ /dev/null @@ -1,216 +0,0 @@ -{% extends "public.html" %} {% block page %} -
-
- - -

{{ event_name }}

-
-
{{ event_info }}
-
- - - - -
- Submit - Cancel -
-
-
-
- - -
- Link to your ticket! -

-

You'll be redirected in a few moments...

-
-
-
- - - - - - -
- Copy invoice - Close -
-
-
-
- -{% endblock %} {% block scripts %} - -{% endblock %} diff --git a/lnbits/extensions/events/templates/events/error.html b/lnbits/extensions/events/templates/events/error.html deleted file mode 100644 index f231177b4..000000000 --- a/lnbits/extensions/events/templates/events/error.html +++ /dev/null @@ -1,35 +0,0 @@ -{% extends "public.html" %} {% block page %} -
-
- - -
-

{{ event_name }} error

-
- - -
{{ event_error }}
-
-
-
-
-
- - {% endblock %} {% block scripts %} - - - - {% endblock %} -
diff --git a/lnbits/extensions/events/templates/events/index.html b/lnbits/extensions/events/templates/events/index.html deleted file mode 100644 index 212589301..000000000 --- a/lnbits/extensions/events/templates/events/index.html +++ /dev/null @@ -1,538 +0,0 @@ -{% extends "base.html" %} {% from "macros.jinja" import window_vars with context -%} {% block page %} -
-
- - - New Event - - - - - -
-
-
Events
-
-
- Export to CSV -
-
- - {% raw %} - - - {% endraw %} - -
-
- - - -
-
-
Tickets
-
-
- Export to CSV -
-
- - {% raw %} - - - {% endraw %} - -
-
-
-
- - -
- {{SITE_TITLE}} Events extension -
-
- - - {% include "events/_api_docs.html" %} - -
-
- - - - -
-
- -
-
- - -
-
- - -
-
Ticket closing date
-
- -
-
- -
-
Event begins
-
- -
-
- -
-
Event ends
-
- -
-
- -
-
- -
-
- -
-
- -
- Update Event - Create Event - Cancel -
-
-
-
-
-{% endblock %} {% block scripts %} {{ window_vars(user) }} - -{% endblock %} diff --git a/lnbits/extensions/events/templates/events/register.html b/lnbits/extensions/events/templates/events/register.html deleted file mode 100644 index 43d43070b..000000000 --- a/lnbits/extensions/events/templates/events/register.html +++ /dev/null @@ -1,176 +0,0 @@ -{% extends "public.html" %} {% block page %} - -
-
- - -
-

{{ event_name }} Registration

-
- -
- - Scan ticket -
-
-
- - - - - {% raw %} - - - {% endraw %} - - - -
- - - -
- -
-
- Cancel -
-
-
-
-{% endblock %} {% block scripts %} - -{% endblock %} diff --git a/lnbits/extensions/events/templates/events/ticket.html b/lnbits/extensions/events/templates/events/ticket.html deleted file mode 100644 index 21b7cfa82..000000000 --- a/lnbits/extensions/events/templates/events/ticket.html +++ /dev/null @@ -1,44 +0,0 @@ -{% extends "public.html" %} {% block page %} -
-
- - -
-

{{ ticket_name }} Ticket

-
-
- Bookmark, print or screenshot this page,
- and present it for registration! -
-
- - -
- - Print -
-
-
-
-
-{% endblock %} {% block scripts %} - -{% endblock %} diff --git a/lnbits/extensions/events/views.py b/lnbits/extensions/events/views.py deleted file mode 100644 index 4ed567956..000000000 --- a/lnbits/extensions/events/views.py +++ /dev/null @@ -1,106 +0,0 @@ -from datetime import date, datetime -from http import HTTPStatus - -from fastapi import Depends, Request -from fastapi.templating import Jinja2Templates -from starlette.exceptions import HTTPException -from starlette.responses import HTMLResponse - -from lnbits.core.models import User -from lnbits.decorators import check_user_exists - -from . import events_ext, events_renderer -from .crud import get_event, get_ticket - -templates = Jinja2Templates(directory="templates") - - -@events_ext.get("/", response_class=HTMLResponse) -async def index(request: Request, user: User = Depends(check_user_exists)): - return events_renderer().TemplateResponse( - "events/index.html", {"request": request, "user": user.dict()} - ) - - -@events_ext.get("/{event_id}", response_class=HTMLResponse) -async def display(request: Request, event_id): - event = await get_event(event_id) - if not event: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="Event does not exist." - ) - - if event.amount_tickets < 1: - return events_renderer().TemplateResponse( - "events/error.html", - { - "request": request, - "event_name": event.name, - "event_error": "Sorry, tickets are sold out :(", - }, - ) - datetime_object = datetime.strptime(event.closing_date, "%Y-%m-%d").date() - if date.today() > datetime_object: - return events_renderer().TemplateResponse( - "events/error.html", - { - "request": request, - "event_name": event.name, - "event_error": "Sorry, ticket closing date has passed :(", - }, - ) - - return events_renderer().TemplateResponse( - "events/display.html", - { - "request": request, - "event_id": event_id, - "event_name": event.name, - "event_info": event.info, - "event_price": event.price_per_ticket, - }, - ) - - -@events_ext.get("/ticket/{ticket_id}", response_class=HTMLResponse) -async def ticket(request: Request, ticket_id): - ticket = await get_ticket(ticket_id) - if not ticket: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="Ticket does not exist." - ) - - event = await get_event(ticket.event) - if not event: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="Event does not exist." - ) - - return events_renderer().TemplateResponse( - "events/ticket.html", - { - "request": request, - "ticket_id": ticket_id, - "ticket_name": event.name, - "ticket_info": event.info, - }, - ) - - -@events_ext.get("/register/{event_id}", response_class=HTMLResponse) -async def register(request: Request, event_id): - event = await get_event(event_id) - if not event: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="Event does not exist." - ) - - return events_renderer().TemplateResponse( - "events/register.html", - { - "request": request, - "event_id": event_id, - "event_name": event.name, - "wallet_id": event.wallet, - }, - ) diff --git a/lnbits/extensions/events/views_api.py b/lnbits/extensions/events/views_api.py deleted file mode 100644 index f27485d87..000000000 --- a/lnbits/extensions/events/views_api.py +++ /dev/null @@ -1,194 +0,0 @@ -from http import HTTPStatus - -from fastapi import Depends, Query -from starlette.exceptions import HTTPException - -from lnbits.core.crud import get_user -from lnbits.core.services import create_invoice -from lnbits.core.views.api import api_payment -from lnbits.decorators import WalletTypeInfo, get_key_type - -from . import events_ext -from .crud import ( - create_event, - create_ticket, - delete_event, - delete_event_tickets, - delete_ticket, - get_event, - get_event_tickets, - get_events, - get_ticket, - get_tickets, - reg_ticket, - update_event, -) -from .models import CreateEvent, CreateTicket - -# Events - - -@events_ext.get("/api/v1/events") -async def api_events( - all_wallets: bool = Query(False), wallet: WalletTypeInfo = Depends(get_key_type) -): - wallet_ids = [wallet.wallet.id] - - if all_wallets: - user = await get_user(wallet.wallet.user) - wallet_ids = user.wallet_ids if user else [] - - return [event.dict() for event in await get_events(wallet_ids)] - - -@events_ext.post("/api/v1/events") -@events_ext.put("/api/v1/events/{event_id}") -async def api_event_create( - data: CreateEvent, event_id=None, wallet: WalletTypeInfo = Depends(get_key_type) -): - if event_id: - event = await get_event(event_id) - if not event: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="Event does not exist." - ) - - if event.wallet != wallet.wallet.id: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, detail="Not your event." - ) - event = await update_event(event_id, **data.dict()) - else: - event = await create_event(data=data) - - return event.dict() - - -@events_ext.delete("/api/v1/events/{event_id}") -async def api_form_delete(event_id, wallet: WalletTypeInfo = Depends(get_key_type)): - event = await get_event(event_id) - if not event: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="Event does not exist." - ) - - if event.wallet != wallet.wallet.id: - raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="Not your event.") - - await delete_event(event_id) - await delete_event_tickets(event_id) - return "", HTTPStatus.NO_CONTENT - - -#########Tickets########## - - -@events_ext.get("/api/v1/tickets") -async def api_tickets( - all_wallets: bool = Query(False), wallet: WalletTypeInfo = Depends(get_key_type) -): - wallet_ids = [wallet.wallet.id] - - if all_wallets: - user = await get_user(wallet.wallet.user) - wallet_ids = user.wallet_ids if user else [] - - return [ticket.dict() for ticket in await get_tickets(wallet_ids)] - - -@events_ext.get("/api/v1/tickets/{event_id}/{name}/{email}") -async def api_ticket_make_ticket(event_id, name, email): - event = await get_event(event_id) - if not event: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="Event does not exist." - ) - try: - payment_hash, payment_request = await create_invoice( - wallet_id=event.wallet, - amount=event.price_per_ticket, - memo=f"{event_id}", - extra={"tag": "events", "name": name, "email": email}, - ) - except Exception as e: - raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(e)) - return {"payment_hash": payment_hash, "payment_request": payment_request} - - -@events_ext.post("/api/v1/tickets/{event_id}/{payment_hash}") -async def api_ticket_send_ticket(event_id, payment_hash, data: CreateTicket): - event = await get_event(event_id) - if not event: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Event could not be fetched.", - ) - - status = await api_payment(payment_hash) - if status["paid"]: - - exists = await get_ticket(payment_hash) - if exists: - return {"paid": True, "ticket_id": exists.id} - - ticket = await create_ticket( - payment_hash=payment_hash, - wallet=event.wallet, - event=event_id, - name=data.name, - email=data.email, - ) - if not ticket: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Event could not be fetched.", - ) - return {"paid": True, "ticket_id": ticket.id} - return {"paid": False} - - -@events_ext.delete("/api/v1/tickets/{ticket_id}") -async def api_ticket_delete(ticket_id, wallet: WalletTypeInfo = Depends(get_key_type)): - ticket = await get_ticket(ticket_id) - if not ticket: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="Ticket does not exist." - ) - - if ticket.wallet != wallet.wallet.id: - raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="Not your ticket.") - - await delete_ticket(ticket_id) - return "", HTTPStatus.NO_CONTENT - - -# Event Tickets - - -@events_ext.get("/api/v1/eventtickets/{wallet_id}/{event_id}") -async def api_event_tickets(wallet_id, event_id): - return [ - ticket.dict() - for ticket in await get_event_tickets(wallet_id=wallet_id, event_id=event_id) - ] - - -@events_ext.get("/api/v1/register/ticket/{ticket_id}") -async def api_event_register_ticket(ticket_id): - ticket = await get_ticket(ticket_id) - if not ticket: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="Ticket does not exist." - ) - - if not ticket.paid: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, detail="Ticket not paid for." - ) - - if ticket.registered is True: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, detail="Ticket already registered" - ) - - return [ticket.dict() for ticket in await reg_ticket(ticket_id)] diff --git a/tests/data/mock_data.zip b/tests/data/mock_data.zip index 7bc50d096..811176a77 100644 Binary files a/tests/data/mock_data.zip and b/tests/data/mock_data.zip differ