From f22e5069df4e3ada079c9ad6659564aab027a788 Mon Sep 17 00:00:00 2001 From: ben Date: Fri, 27 Jan 2023 12:16:54 +0000 Subject: [PATCH] Removed lnticket --- lnbits/extensions/lnticket/README.md | 29 - lnbits/extensions/lnticket/__init__.py | 35 -- lnbits/extensions/lnticket/config.json | 6 - lnbits/extensions/lnticket/crud.py | 162 ------ lnbits/extensions/lnticket/migrations.py | 177 ------ lnbits/extensions/lnticket/models.py | 44 -- .../lnticket/static/image/lntickets.png | Bin 18543 -> 0 bytes lnbits/extensions/lnticket/tasks.py | 32 - .../templates/lnticket/_api_docs.html | 26 - .../lnticket/templates/lnticket/display.html | 202 ------- .../lnticket/templates/lnticket/index.html | 550 ------------------ lnbits/extensions/lnticket/views.py | 49 -- lnbits/extensions/lnticket/views_api.py | 164 ------ tests/data/mock_data.zip | Bin 45695 -> 44893 bytes 14 files changed, 1476 deletions(-) delete mode 100644 lnbits/extensions/lnticket/README.md delete mode 100644 lnbits/extensions/lnticket/__init__.py delete mode 100644 lnbits/extensions/lnticket/config.json delete mode 100644 lnbits/extensions/lnticket/crud.py delete mode 100644 lnbits/extensions/lnticket/migrations.py delete mode 100644 lnbits/extensions/lnticket/models.py delete mode 100644 lnbits/extensions/lnticket/static/image/lntickets.png delete mode 100644 lnbits/extensions/lnticket/tasks.py delete mode 100644 lnbits/extensions/lnticket/templates/lnticket/_api_docs.html delete mode 100644 lnbits/extensions/lnticket/templates/lnticket/display.html delete mode 100644 lnbits/extensions/lnticket/templates/lnticket/index.html delete mode 100644 lnbits/extensions/lnticket/views.py delete mode 100644 lnbits/extensions/lnticket/views_api.py diff --git a/lnbits/extensions/lnticket/README.md b/lnbits/extensions/lnticket/README.md deleted file mode 100644 index bd0714506..000000000 --- a/lnbits/extensions/lnticket/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# Support Tickets - -## Get paid sats to answer questions - -Charge a per word amount for people to contact you. - -Possible applications include, paid support ticketing, PAYG language services, contact spam protection. - -1. Click "NEW FORM" to create a new contact form\ - ![new contact form](https://i.imgur.com/kZqWGPe.png) -2. Fill out the contact form - - set the wallet to use - - give your form a name - - set an optional webhook that will get called when the form receives a payment - - give it a small description - - set the amount you want to charge, per **word**, for people to contact you\ - ![form settings](https://i.imgur.com/AsXeVet.png) -3. Your new contact form will appear on the _Forms_ section. Note that you can create various forms with different rates per word, for different purposes\ - ![forms section](https://i.imgur.com/gg71HhM.png) -4. When a user wants to reach out to you, they will get to the contact form. They can fill out some information: - - a name - - an optional email if they want you to reply - - and the actual message - - at the bottom, a value in satoshis, will display how much it will cost them to send this message\ - ![user view of form](https://i.imgur.com/DWGJWQz.png) - - after submiting the Lightning Network invoice will pop up and after payment the message will be sent to you\ - ![contact form payment](https://i.imgur.com/7heGsiO.png) -5. Back in "Support ticket" extension you'll get the messages your fans, users, haters, etc, sent you on the _Tickets_ section\ - ![tickets](https://i.imgur.com/dGhJ6Ok.png) diff --git a/lnbits/extensions/lnticket/__init__.py b/lnbits/extensions/lnticket/__init__.py deleted file mode 100644 index 3c52fd2a2..000000000 --- a/lnbits/extensions/lnticket/__init__.py +++ /dev/null @@ -1,35 +0,0 @@ -import asyncio -import json - -from fastapi import APIRouter -from starlette.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_lnticket") - -lnticket_ext: APIRouter = APIRouter(prefix="/lnticket", tags=["LNTicket"]) - -lnticket_static_files = [ - { - "path": "/lnticket/static", - "app": StaticFiles(directory="lnbits/extensions/lnticket/static"), - "name": "lnticket_static", - } -] - - -def lnticket_renderer(): - return template_renderer(["lnbits/extensions/lnticket/templates"]) - - -from .tasks import wait_for_paid_invoices -from .views import * # noqa -from .views_api import * # noqa - - -def lnticket_start(): - loop = asyncio.get_event_loop() - loop.create_task(catch_everything_and_restart(wait_for_paid_invoices)) diff --git a/lnbits/extensions/lnticket/config.json b/lnbits/extensions/lnticket/config.json deleted file mode 100644 index e8e55f2ff..000000000 --- a/lnbits/extensions/lnticket/config.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "Support Tickets", - "short_description": "LN support ticket system", - "tile": "/lnticket/static/image/lntickets.png", - "contributors": ["benarc"] -} diff --git a/lnbits/extensions/lnticket/crud.py b/lnbits/extensions/lnticket/crud.py deleted file mode 100644 index 3254ad438..000000000 --- a/lnbits/extensions/lnticket/crud.py +++ /dev/null @@ -1,162 +0,0 @@ -from typing import List, Optional, Union - -import httpx - -from lnbits.core.models import Wallet -from lnbits.helpers import urlsafe_short_hash - -from . import db -from .models import CreateFormData, CreateTicketData, Forms, Tickets - - -async def create_ticket( - payment_hash: str, wallet: str, data: CreateTicketData -) -> Tickets: - await db.execute( - """ - INSERT INTO lnticket.ticket (id, form, email, ltext, name, wallet, sats, paid) - VALUES (?, ?, ?, ?, ?, ?, ?, ?) - """, - ( - payment_hash, - data.form, - data.email, - data.ltext, - data.name, - wallet, - data.sats, - False, - ), - ) - - ticket = await get_ticket(payment_hash) - assert ticket, "Newly created ticket couldn't be retrieved" - return ticket - - -async def set_ticket_paid(payment_hash: str) -> Tickets: - row = await db.fetchone( - "SELECT * FROM lnticket.ticket WHERE id = ?", (payment_hash,) - ) - if row[7] == False: - await db.execute( - """ - UPDATE lnticket.ticket - SET paid = true - WHERE id = ? - """, - (payment_hash,), - ) - - formdata = await get_form(row[1]) - assert formdata, "Couldn't get form from paid ticket" - - amount = formdata.amountmade + row[7] - await db.execute( - """ - UPDATE lnticket.form2 - SET amountmade = ? - WHERE id = ? - """, - (amount, row[1]), - ) - - ticket = await get_ticket(payment_hash) - assert ticket, "Newly paid ticket could not be retrieved" - - if formdata.webhook: - async with httpx.AsyncClient() as client: - await client.post( - formdata.webhook, - json={ - "form": ticket.form, - "name": ticket.name, - "email": ticket.email, - "content": ticket.ltext, - }, - timeout=40, - ) - return ticket - - ticket = await get_ticket(payment_hash) - assert ticket, "Newly paid ticket could not be retrieved" - return ticket - - -async def get_ticket(ticket_id: str) -> Optional[Tickets]: - row = await db.fetchone("SELECT * FROM lnticket.ticket WHERE id = ?", (ticket_id,)) - 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 lnticket.ticket WHERE wallet IN ({q})", (*wallet_ids,) - ) - - return [Tickets(**row) for row in rows] - - -async def delete_ticket(ticket_id: str) -> None: - await db.execute("DELETE FROM lnticket.ticket WHERE id = ?", (ticket_id,)) - - -# FORMS - - -async def create_form(data: CreateFormData, wallet: Wallet) -> Forms: - form_id = urlsafe_short_hash() - await db.execute( - """ - INSERT INTO lnticket.form2 (id, wallet, name, webhook, description, flatrate, amount, amountmade) - VALUES (?, ?, ?, ?, ?, ?, ?, ?) - """, - ( - form_id, - wallet.id, - wallet.name, - data.webhook, - data.description, - data.flatrate, - data.amount, - 0, - ), - ) - - form = await get_form(form_id) - assert form, "Newly created forms couldn't be retrieved" - return form - - -async def update_form(form_id: str, **kwargs) -> Forms: - q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()]) - await db.execute( - f"UPDATE lnticket.form2 SET {q} WHERE id = ?", (*kwargs.values(), form_id) - ) - row = await db.fetchone("SELECT * FROM lnticket.form2 WHERE id = ?", (form_id,)) - assert row, "Newly updated form couldn't be retrieved" - return Forms(**row) - - -async def get_form(form_id: str) -> Optional[Forms]: - row = await db.fetchone("SELECT * FROM lnticket.form2 WHERE id = ?", (form_id,)) - return Forms(**row) if row else None - - -async def get_forms(wallet_ids: Union[str, List[str]]) -> List[Forms]: - if isinstance(wallet_ids, str): - wallet_ids = [wallet_ids] - - q = ",".join(["?"] * len(wallet_ids)) - rows = await db.fetchall( - f"SELECT * FROM lnticket.form2 WHERE wallet IN ({q})", (*wallet_ids,) - ) - - return [Forms(**row) for row in rows] - - -async def delete_form(form_id: str) -> None: - await db.execute("DELETE FROM lnticket.form2 WHERE id = ?", (form_id,)) diff --git a/lnbits/extensions/lnticket/migrations.py b/lnbits/extensions/lnticket/migrations.py deleted file mode 100644 index 44c2e0f10..000000000 --- a/lnbits/extensions/lnticket/migrations.py +++ /dev/null @@ -1,177 +0,0 @@ -async def m001_initial(db): - - await db.execute( - """ - CREATE TABLE lnticket.forms ( - id TEXT PRIMARY KEY, - wallet TEXT NOT NULL, - name TEXT NOT NULL, - description TEXT NOT NULL, - costpword INTEGER NOT NULL, - amountmade INTEGER NOT NULL, - time TIMESTAMP NOT NULL DEFAULT """ - + db.timestamp_now - + """ - ); - """ - ) - - await db.execute( - """ - CREATE TABLE lnticket.tickets ( - id TEXT PRIMARY KEY, - form TEXT NOT NULL, - email TEXT NOT NULL, - ltext TEXT NOT NULL, - name TEXT NOT NULL, - wallet TEXT NOT NULL, - sats INTEGER NOT NULL, - time TIMESTAMP NOT NULL DEFAULT """ - + db.timestamp_now - + """ - ); - """ - ) - - -async def m002_changed(db): - - await db.execute( - """ - CREATE TABLE lnticket.ticket ( - id TEXT PRIMARY KEY, - form TEXT NOT NULL, - email TEXT NOT NULL, - ltext TEXT NOT NULL, - name TEXT NOT NULL, - wallet TEXT NOT NULL, - sats INTEGER 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 lnticket.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 lnticket.ticket ( - id, - form, - email, - ltext, - name, - wallet, - sats, - paid - ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?) - """, - (row[0], row[1], row[2], row[3], row[4], row[5], row[6], True), - ) - await db.execute("DROP TABLE lnticket.tickets") - - -async def m003_changed(db): - - await db.execute( - """ - CREATE TABLE IF NOT EXISTS lnticket.form ( - id TEXT PRIMARY KEY, - wallet TEXT NOT NULL, - name TEXT NOT NULL, - webhook TEXT, - description TEXT NOT NULL, - costpword INTEGER NOT NULL, - amountmade INTEGER NOT NULL, - time TIMESTAMP NOT NULL DEFAULT """ - + db.timestamp_now - + """ - ); - """ - ) - - for row in [list(row) for row in await db.fetchall("SELECT * FROM lnticket.forms")]: - 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 lnticket.form ( - id, - wallet, - name, - webhook, - description, - costpword, - amountmade - ) - VALUES (?, ?, ?, ?, ?, ?, ?) - """, - (row[0], row[1], row[2], row[3], row[4], row[5], row[6]), - ) - await db.execute("DROP TABLE lnticket.forms") - - -async def m004_changed(db): - - await db.execute( - """ - CREATE TABLE lnticket.form2 ( - id TEXT PRIMARY KEY, - wallet TEXT NOT NULL, - name TEXT NOT NULL, - webhook TEXT, - description TEXT NOT NULL, - flatrate INTEGER DEFAULT 0, - amount INTEGER NOT NULL, - amountmade INTEGER NOT NULL, - time TIMESTAMP NOT NULL DEFAULT """ - + db.timestamp_now - + """ - ); - """ - ) - - for row in [list(row) for row in await db.fetchall("SELECT * FROM lnticket.form")]: - 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 lnticket.form2 ( - id, - wallet, - name, - webhook, - description, - amount, - amountmade - ) - VALUES (?, ?, ?, ?, ?, ?, ?) - """, - (row[0], row[1], row[2], row[3], row[4], row[5], row[6]), - ) - await db.execute("DROP TABLE lnticket.form") diff --git a/lnbits/extensions/lnticket/models.py b/lnbits/extensions/lnticket/models.py deleted file mode 100644 index a7a3cf8c3..000000000 --- a/lnbits/extensions/lnticket/models.py +++ /dev/null @@ -1,44 +0,0 @@ -from typing import Optional - -from fastapi.param_functions import Query -from pydantic import BaseModel - - -class CreateFormData(BaseModel): - name: str = Query(...) - webhook: str = Query(None) - description: str = Query(..., min_length=0) - amount: int = Query(..., ge=0) - flatrate: int = Query(...) - - -class CreateTicketData(BaseModel): - form: str = Query(...) - name: str = Query(...) - email: str = Query("") - ltext: str = Query(...) - sats: int = Query(..., ge=0) - - -class Forms(BaseModel): - id: str - wallet: str - name: str - webhook: Optional[str] - description: str - amount: int - flatrate: int - amountmade: int - time: int - - -class Tickets(BaseModel): - id: str - form: str - email: str - ltext: str - name: str - wallet: str - sats: int - paid: bool - time: int diff --git a/lnbits/extensions/lnticket/static/image/lntickets.png b/lnbits/extensions/lnticket/static/image/lntickets.png deleted file mode 100644 index 875b41547a2cf76cdbb4d9c00834c3e491776523..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18543 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 None: - if payment.extra.get("tag") != "lnticket": - # not a lnticket invoice - return - - ticket = await get_ticket(payment.checking_id) - if not ticket: - logger.error("this should never happen", payment) - return - - await payment.set_pending(False) - await set_ticket_paid(payment.payment_hash) diff --git a/lnbits/extensions/lnticket/templates/lnticket/_api_docs.html b/lnbits/extensions/lnticket/templates/lnticket/_api_docs.html deleted file mode 100644 index 97a0fe6b1..000000000 --- a/lnbits/extensions/lnticket/templates/lnticket/_api_docs.html +++ /dev/null @@ -1,26 +0,0 @@ - - - -
- Support Tickets: Get paid sats to answer questions -
-

- Charge people per word for contacting you. Possible applications incude, - paid support ticketing, PAYG language services, contact spam - protection.
- - Created by, - Ben Arc -

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

{{ form_name }}

-
-
{{ form_desc }}
-
- - - - - -

{% raw %}{{amountWords}}{% endraw %}

-
- Submit - Cancel -
-
-
-
-
- - - - - - -
- Copy invoice - Close -
-
-
-
- -{% endblock %} {% block scripts %} - -{% endblock %} diff --git a/lnbits/extensions/lnticket/templates/lnticket/index.html b/lnbits/extensions/lnticket/templates/lnticket/index.html deleted file mode 100644 index 9329be7b2..000000000 --- a/lnbits/extensions/lnticket/templates/lnticket/index.html +++ /dev/null @@ -1,550 +0,0 @@ -{% extends "base.html" %} {% from "macros.jinja" import window_vars with context -%} {% block page %} -
-
- - - New Form - - - - - -
-
-
Forms
-
-
- Export to CSV -
-
- - {% raw %} - - - {% endraw %} - -
-
- - - -
-
-
Tickets
-
- -
- Export to CSV -
-
- - {% raw %} - - - {% endraw %} - -
-
-
-
- - -
- {{SITE_TITLE}} Support Tickets extension -
-
- - - {% include "lnticket/_api_docs.html" %} - -
-
- - - - - - - - - -
-
- -
-
- -
-
- -
- Update Form - - Create Form - Cancel -
-
-
-
- - - - {% raw %} - -

- {{this.ticketDialog.data.name}} sent a ticket -

-
- {{this.ticketDialog.data.email}} -
- {{this.ticketDialog.data.date}} -
- - -

{{this.ticketDialog.data.content}}

-
- {% endraw %} - - - -
-
-
-{% endblock %} {% block scripts %} {{ window_vars(user) }} - -{% endblock %} diff --git a/lnbits/extensions/lnticket/views.py b/lnbits/extensions/lnticket/views.py deleted file mode 100644 index 9bb1d9b3a..000000000 --- a/lnbits/extensions/lnticket/views.py +++ /dev/null @@ -1,49 +0,0 @@ -from http import HTTPStatus - -from fastapi import Request -from fastapi.param_functions import Depends -from fastapi.params import Depends -from fastapi.templating import Jinja2Templates -from starlette.exceptions import HTTPException -from starlette.responses import HTMLResponse - -from lnbits.core.crud import get_wallet -from lnbits.core.models import User -from lnbits.decorators import check_user_exists - -from . import lnticket_ext, lnticket_renderer -from .crud import get_form - -templates = Jinja2Templates(directory="templates") - - -@lnticket_ext.get("/", response_class=HTMLResponse) -async def index(request: Request, user: User = Depends(check_user_exists)): - return lnticket_renderer().TemplateResponse( - "lnticket/index.html", {"request": request, "user": user.dict()} - ) - - -@lnticket_ext.get("/{form_id}") -async def display(request: Request, form_id): - form = await get_form(form_id) - if not form: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="LNTicket does not exist." - ) - - wallet = await get_wallet(form.wallet) - assert wallet - - return lnticket_renderer().TemplateResponse( - "lnticket/display.html", - { - "request": request, - "form_id": form.id, - "form_name": form.name, - "form_desc": form.description, - "form_amount": form.amount, - "form_flatrate": form.flatrate, - "form_wallet": wallet.inkey, - }, - ) diff --git a/lnbits/extensions/lnticket/views_api.py b/lnbits/extensions/lnticket/views_api.py deleted file mode 100644 index 4462688b6..000000000 --- a/lnbits/extensions/lnticket/views_api.py +++ /dev/null @@ -1,164 +0,0 @@ -import re -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 lnticket_ext -from .crud import ( - create_form, - create_ticket, - delete_form, - delete_ticket, - get_form, - get_forms, - get_ticket, - get_tickets, - set_ticket_paid, - update_form, -) -from .models import CreateFormData, CreateTicketData - -# FORMS - - -@lnticket_ext.get("/api/v1/forms") -async def api_forms_get( - 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 [form.dict() for form in await get_forms(wallet_ids)] - - -@lnticket_ext.post("/api/v1/forms", status_code=HTTPStatus.CREATED) -@lnticket_ext.put("/api/v1/forms/{form_id}") -async def api_form_create( - data: CreateFormData, form_id=None, wallet: WalletTypeInfo = Depends(get_key_type) -): - if form_id: - form = await get_form(form_id) - - if not form: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail=f"Form does not exist." - ) - - if form.wallet != wallet.wallet.id: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, detail=f"Not your form." - ) - - form = await update_form(form_id, **data.dict()) - else: - form = await create_form(data, wallet.wallet) - return form.dict() - - -@lnticket_ext.delete("/api/v1/forms/{form_id}") -async def api_form_delete(form_id, wallet: WalletTypeInfo = Depends(get_key_type)): - form = await get_form(form_id) - - if not form: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail=f"Form does not exist." - ) - - if form.wallet != wallet.wallet.id: - raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail=f"Not your form.") - - await delete_form(form_id) - - return "", HTTPStatus.NO_CONTENT - - -#########tickets########## - - -@lnticket_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 [form.dict() for form in await get_tickets(wallet_ids)] - - -@lnticket_ext.post("/api/v1/tickets/{form_id}", status_code=HTTPStatus.CREATED) -async def api_ticket_make_ticket(data: CreateTicketData, form_id): - form = await get_form(form_id) - if not form: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail=f"LNTicket does not exist." - ) - if data.sats < 1: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail=f"0 invoices not allowed." - ) - - nwords = len(re.split(r"\s+", data.ltext)) - - try: - payment_hash, payment_request = await create_invoice( - wallet_id=form.wallet, - amount=data.sats, - memo=f"ticket with {nwords} words on {form_id}", - extra={"tag": "lnticket"}, - ) - except Exception as e: - raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(e)) - - ticket = await create_ticket( - payment_hash=payment_hash, wallet=form.wallet, data=data - ) - - if not ticket: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="LNTicket could not be fetched." - ) - - return {"payment_hash": payment_hash, "payment_request": payment_request} - - -@lnticket_ext.get("/api/v1/tickets/{payment_hash}", status_code=HTTPStatus.OK) -async def api_ticket_send_ticket(payment_hash): - ticket = await get_ticket(payment_hash) - - try: - status = await api_payment(payment_hash) - if status["paid"]: - await set_ticket_paid(payment_hash=payment_hash) - return {"paid": True} - except Exception: - return {"paid": False} - - return {"paid": False} - - -@lnticket_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=f"LNTicket 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 diff --git a/tests/data/mock_data.zip b/tests/data/mock_data.zip index fb6e5122128d6c16c4ad3945196032e3902c1b7f..90c1393b24ba8b0816054e799d23e58b1c46ba16 100644 GIT binary patch delta 359 zcmezWgz4@*rVX>>H%BKuaGgANg%ne7{N$Z0vRT{`7#Jq+O;wrfv(lFNN)p55jj7I) z8301li$=jOm>1+;8}+Vhwg7#Io|7(^Hp7$$FvSDehWPPqQ_ZhttqDUUuQ-w z{{71F-;xydzN1nP22~yZvvAv_)-t zl=Ri=GX~35XTnsp^Zo0DrgdD*e=Yt^ zI@l*})|)xe?|wgf@yUFwRMu@2mtzvQK zSl9o5d|>B)|7*`{Yaqf5ANVcKf2vMPgDN}Vbm(tARLAY}mH*^F!+CF|1H748K(6Fq zShDuV=2`I%UFFbIC)8AiC5^rD46w8+Ke>FV9J6l{!{k-*4wDZo;+gzpsT>PiGEl+a zB$dfp%WRpaq%utYnB)wW+__ASIWUc3^15VWAfIJ2|5Ay`a~Jb5H)JwQzMEz~dBPg5 z$<@o{m@fhO`spAw0+a7Amtwx0$1vF-#|&(S-3mD-&cexYE0USt7c)%uDKr5Kv#gY3 zHYj75+*@o4=BEMqhbkE+%a=pskFS(t60e>7d}S8%`C5j_I@J!78y09VY1K{MwKK;Q4M2y#U#&K|V74&WltZiKnEjg>Ca-C51@prjMR*Yb!P~+xIjhkUEHi73 z9MkEx$-CAhG1YcXmRlRge7PIw=uX4Q8`f$uPw52)LYD