diff --git a/docs/guide/installation.md b/docs/guide/installation.md index bf40418d9..072c4d91c 100644 --- a/docs/guide/installation.md +++ b/docs/guide/installation.md @@ -220,8 +220,8 @@ You need to edit the `.env` file. ```sh # add the database connection string to .env 'nano .env' LNBITS_DATABASE_URL= -# postgres://:@/ - alter line bellow with your user, password and db name -LNBITS_DATABASE_URL="postgres://postgres:postgres@localhost/lnbits" +# postgres://:@:/ - alter line bellow with your user, password and db name +LNBITS_DATABASE_URL="postgres://postgres:postgres@localhost:5432/lnbits" # save and exit ``` diff --git a/lnbits/extensions/events/__init__.py b/lnbits/extensions/events/__init__.py index d0aa27bca..c64a866ba 100644 --- a/lnbits/extensions/events/__init__.py +++ b/lnbits/extensions/events/__init__.py @@ -1,7 +1,11 @@ +import asyncio + from fastapi import APIRouter from lnbits.db import Database from lnbits.helpers import template_renderer +from lnbits.tasks import catch_everything_and_restart + db = Database("ext_events") @@ -13,5 +17,11 @@ def events_renderer(): return template_renderer(["lnbits/extensions/events/templates"]) +from .tasks import wait_for_paid_invoices from .views import * # noqa from .views_api import * # noqa + + +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/tasks.py b/lnbits/extensions/events/tasks.py new file mode 100644 index 000000000..2068b3fa4 --- /dev/null +++ b/lnbits/extensions/events/tasks.py @@ -0,0 +1,39 @@ +import asyncio +import json +from http import HTTPStatus +from urllib.parse import urlparse + +import httpx +from fastapi import HTTPException + +from lnbits import bolt11 +from lnbits.core.models import Payment +from lnbits.core.services import pay_invoice +from lnbits.helpers import get_current_extension_name +from lnbits.tasks import register_invoice_listener + +from .views_api import api_ticket_send_ticket +from loguru import logger +from lnbits.extensions.events.models import CreateTicket + + +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 ( + "events" == payment.extra.get("tag") + and payment.extra.get("name") + and payment.extra.get("email") + ): + CreateTicket.name = str(payment.extra.get("name")) + CreateTicket.email = str(payment.extra.get("email")) + await api_ticket_send_ticket(payment.memo, payment.payment_hash, CreateTicket) + return diff --git a/lnbits/extensions/events/templates/events/display.html b/lnbits/extensions/events/templates/events/display.html index 4589c5785..9dbb95bcd 100644 --- a/lnbits/extensions/events/templates/events/display.html +++ b/lnbits/extensions/events/templates/events/display.html @@ -135,7 +135,7 @@ var self = this axios - .get('/events/api/v1/tickets/' + '{{ event_id }}') + .get('/events/api/v1/tickets/' + '{{ event_id }}' + '/' + self.formDialog.data.name + '/' + self.formDialog.data.email) .then(function (response) { self.paymentReq = response.data.payment_request self.paymentCheck = response.data.payment_hash diff --git a/lnbits/extensions/events/views_api.py b/lnbits/extensions/events/views_api.py index 9cb18f042..08651f5d2 100644 --- a/lnbits/extensions/events/views_api.py +++ b/lnbits/extensions/events/views_api.py @@ -10,6 +10,7 @@ from lnbits.core.services import create_invoice from lnbits.core.views.api import api_payment from lnbits.decorators import WalletTypeInfo, get_key_type from lnbits.extensions.events.models import CreateEvent, CreateTicket +from loguru import logger from . import events_ext from .crud import ( @@ -96,8 +97,8 @@ async def api_tickets( return [ticket.dict() for ticket in await get_tickets(wallet_ids)] -@events_ext.get("/api/v1/tickets/{event_id}") -async def api_ticket_make_ticket(event_id): +@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( @@ -108,11 +109,10 @@ async def api_ticket_make_ticket(event_id): wallet_id=event.wallet, amount=event.price_per_ticket, memo=f"{event_id}", - extra={"tag": "events"}, + 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} @@ -156,7 +156,7 @@ async def api_ticket_delete(ticket_id, wallet: WalletTypeInfo = Depends(get_key_ ) await delete_ticket(ticket_id) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + return "", HTTPStatus.NO_CONTENT # Event Tickets diff --git a/lnbits/extensions/lnurldevice/lnurl.py b/lnbits/extensions/lnurldevice/lnurl.py index c8f9675e4..dd8dcb08e 100644 --- a/lnbits/extensions/lnurldevice/lnurl.py +++ b/lnbits/extensions/lnurldevice/lnurl.py @@ -105,9 +105,9 @@ async def lnurl_v1_params( paymentcheck = await get_lnurlpayload(p) if device.device == "atm": if paymentcheck: - return {"status": "ERROR", "reason": f"Payment already claimed"} + if paymentcheck.payhash != "payment_hash": + return {"status": "ERROR", "reason": f"Payment already claimed"} if device.device == "switch": - price_msat = ( await fiat_amount_as_satoshis(float(profit), device.currency) if device.currency != "sat" @@ -177,7 +177,7 @@ async def lnurl_v1_params( "callback": request.url_for( "lnurldevice.lnurl_callback", paymentid=lnurldevicepayment.id ), - "k1": lnurldevicepayment.id, + "k1": p, "minWithdrawable": price_msat * 1000, "maxWithdrawable": price_msat * 1000, "defaultDescription": device.title, @@ -227,14 +227,13 @@ async def lnurl_callback( status_code=HTTPStatus.FORBIDDEN, detail="No payment request" ) else: - if lnurldevicepayment.id != k1: + if lnurldevicepayment.payload != k1: return {"status": "ERROR", "reason": "Bad K1"} if lnurldevicepayment.payhash != "payment_hash": return {"status": "ERROR", "reason": f"Payment already claimed"} lnurldevicepayment = await update_lnurldevicepayment( lnurldevicepayment_id=paymentid, payhash=lnurldevicepayment.payload ) - await pay_invoice( wallet_id=device.wallet, payment_request=pr, diff --git a/lnbits/extensions/lnurldevice/templates/lnurldevice/index.html b/lnbits/extensions/lnurldevice/templates/lnurldevice/index.html index 83ff4571e..b0b223fff 100644 --- a/lnbits/extensions/lnurldevice/templates/lnurldevice/index.html +++ b/lnbits/extensions/lnurldevice/templates/lnurldevice/index.html @@ -797,7 +797,7 @@ LNbits.utils.notifyApiError(error) }) }, - clearFormDialoglnurldevice () { + clearFormDialoglnurldevice() { this.formDialoglnurldevice.data = { lnurl_toggle: false, show_message: false, diff --git a/lnbits/extensions/usermanager/crud.py b/lnbits/extensions/usermanager/crud.py index 1ce66d4fa..649888a83 100644 --- a/lnbits/extensions/usermanager/crud.py +++ b/lnbits/extensions/usermanager/crud.py @@ -63,10 +63,11 @@ async def get_usermanager_users(user_id: str) -> List[Users]: return [Users(**row) for row in rows] -async def delete_usermanager_user(user_id: str) -> None: - wallets = await get_usermanager_wallets(user_id) - for wallet in wallets: - await delete_wallet(user_id=user_id, wallet_id=wallet.id) +async def delete_usermanager_user(user_id: str, delete_core: bool = True) -> None: + if delete_core: + wallets = await get_usermanager_wallets(user_id) + for wallet in wallets: + await delete_wallet(user_id=user_id, wallet_id=wallet.id) await db.execute("DELETE FROM usermanager.users WHERE id = ?", (user_id,)) await db.execute("""DELETE FROM usermanager.wallets WHERE "user" = ?""", (user_id,)) diff --git a/lnbits/extensions/usermanager/templates/usermanager/_api_docs.html b/lnbits/extensions/usermanager/templates/usermanager/_api_docs.html index de477834b..ff3ba85a3 100644 --- a/lnbits/extensions/usermanager/templates/usermanager/_api_docs.html +++ b/lnbits/extensions/usermanager/templates/usermanager/_api_docs.html @@ -44,7 +44,7 @@
Curl example
curl -X GET {{ request.base_url }}usermanager/api/v1/users -H - "X-Api-Key: {{ user.wallets[0].inkey }}" + "X-Api-Key: {{ user.wallets[0].adminkey }}" @@ -57,13 +57,14 @@ /usermanager/api/v1/users/<user_id>
Body (application/json)
- +
Returns 200 OK (application/json)
{"id": <string>, "name": <string>, "admin": - <string>, "email": <string>, "password": <string>}
Curl example
@@ -80,7 +81,7 @@ GET - /usermanager/api/v1/wallets/<user_id>
Headers
{"X-Api-Key": <string>} @@ -91,9 +92,8 @@ JSON wallet data
Curl example
curl -X GET {{ request.base_url - }}usermanager/api/v1/wallets/<user_id> -H "X-Api-Key: {{ - user.wallets[0].inkey }}" + >curl -X GET {{ request.base_url }}usermanager/api/v1/wallets -H + "X-Api-Key: {{ user.wallets[0].adminkey }}"
@@ -220,7 +220,7 @@ curl -X DELETE {{ request.base_url }}usermanager/api/v1/users/<user_id> -H "X-Api-Key: {{ - user.wallets[0].inkey }}" + user.wallets[0].adminkey }}" @@ -238,7 +238,7 @@ curl -X DELETE {{ request.base_url }}usermanager/api/v1/wallets/<wallet_id> -H "X-Api-Key: {{ - user.wallets[0].inkey }}" + user.wallets[0].adminkey }}" @@ -259,15 +259,15 @@ {"X-Api-Key": <string>}
Curl example
curl -X POST {{ request.base_url }}usermanager/api/v1/extensions?extension=withdraw&userid=user_id&active=true -H "X-Api-Key: {{ user.wallets[0].inkey }}" -H - "Content-type: application/json" + >curl -X POST {{ request.base_url + }}usermanager/api/v1/extensions?extension=withdraw&userid=user_id&active=true + -H "X-Api-Key: {{ user.wallets[0].inkey }}" -H "Content-type: + application/json"
Returns 200 OK (application/json)
- {"extension": "updated"} + {"extension": "updated"} diff --git a/lnbits/extensions/usermanager/views_api.py b/lnbits/extensions/usermanager/views_api.py index 7e7b7653a..b1bf8ef89 100644 --- a/lnbits/extensions/usermanager/views_api.py +++ b/lnbits/extensions/usermanager/views_api.py @@ -52,15 +52,17 @@ async def api_usermanager_users_create( @usermanager_ext.delete("/api/v1/users/{user_id}") async def api_usermanager_users_delete( - user_id, wallet: WalletTypeInfo = Depends(require_admin_key) + user_id, + delete_core: bool = Query(True), + wallet: WalletTypeInfo = Depends(require_admin_key), ): user = await get_usermanager_user(user_id) if not user: raise HTTPException( status_code=HTTPStatus.NOT_FOUND, detail="User does not exist." ) - await delete_usermanager_user(user_id) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + await delete_usermanager_user(user_id, delete_core) + return "", HTTPStatus.NO_CONTENT # Activate Extension @@ -124,4 +126,4 @@ async def api_usermanager_wallets_delete( status_code=HTTPStatus.NOT_FOUND, detail="Wallet does not exist." ) await delete_usermanager_wallet(wallet_id, get_wallet.user) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + return "", HTTPStatus.NO_CONTENT