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 bd071450..00000000 --- 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 3c52fd2a..00000000 --- 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 e8e55f2f..00000000 --- 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 3254ad43..00000000 --- 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 44c2e0f1..00000000 --- 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 a7a3cf8c..00000000 --- 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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 VR=HnLUJSH?(9_k=Wt~$(69DwxlxP3| diff --git a/lnbits/extensions/lnticket/tasks.py b/lnbits/extensions/lnticket/tasks.py deleted file mode 100644 index 746ebea9..00000000 --- a/lnbits/extensions/lnticket/tasks.py +++ /dev/null @@ -1,32 +0,0 @@ -import asyncio - -from loguru import logger - -from lnbits.core.models import Payment -from lnbits.helpers import get_current_extension_name -from lnbits.tasks import register_invoice_listener - -from .crud import get_ticket, set_ticket_paid - - -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: - 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 97a0fe6b..00000000 --- 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 7d6694b9..00000000 --- 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 9329be7b..00000000 --- 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 9bb1d9b3..00000000 --- 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 4462688b..00000000 --- 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) z8ta}5 z*D^3n7F@43*yw!FwoP`}5XU6kIeEc`80ITo43jtZT7Wet&d%Jptl_WgF#K3}-ViOjcZ| h2)Bu2lN^)9yvZ7yJo&U3v>3t!7#KdzV_;xl0085#i@5** delta 1078 zcmcb6kLmvtrVX>>1+;8}+Vhwg7#Io|7(^Hp7$$FvSDehWPPqQ}C@Hro*C*}|O8X|t^4 zRi|nz`E?yV*<<(m<>hbuU$14Kezi+;a`mlUwN?h_b|ijX9(uu0Qr^IjMQe&_{nwdM zi+{gz{I_Jq#UCkhuOpw=+MV0AZ&P4U|JJXPop%cSRtE(2Z>?Er>(%+)sekPC{>JT>;q!javz@=-@s`z}FJ3ag$nAFf-xg_$ z+Vm*ttJP-=maEQ)*}o&weAZ3D++%Mgdw=!RcN*Va8`71v@6YyIf0O6?*9lGQxS0Q1 z{F`*JPu#3GbE4nca&K10sYT* zF*_!P3SPR~?;^qg0W+4jiJY1$*K*iV^FifIn@3-peV)5+uZ!?aukM<)@w?DRAMKew z7d}S8%`C5j_I@J!78y09V zY1K{MwKK;Q4GavE->+7iTrgW0Y|5e4a?JkC43pP1xPtlNjUv2=fZ%Om zn4HyU36`0)Mvm!p+vHtql9*~cC(EskW4_$YFxjBfaPo$=TFg^=876=1vH+`8TqnoG uH(|2lx