mirror of
https://github.com/lnbits/lnbits.git
synced 2025-09-21 06:06:11 +02:00
Merge branch 'lnbits:main' into main
This commit is contained in:
@@ -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://<user>:<myPassword>@<host>/<lnbits> - alter line bellow with your user, password and db name
|
||||
LNBITS_DATABASE_URL="postgres://postgres:postgres@localhost/lnbits"
|
||||
# postgres://<user>:<myPassword>@<host>:<port>/<lnbits> - alter line bellow with your user, password and db name
|
||||
LNBITS_DATABASE_URL="postgres://postgres:postgres@localhost:5432/lnbits"
|
||||
# save and exit
|
||||
```
|
||||
|
||||
|
@@ -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))
|
||||
|
39
lnbits/extensions/events/tasks.py
Normal file
39
lnbits/extensions/events/tasks.py
Normal file
@@ -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
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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,
|
||||
|
@@ -797,7 +797,7 @@
|
||||
LNbits.utils.notifyApiError(error)
|
||||
})
|
||||
},
|
||||
clearFormDialoglnurldevice () {
|
||||
clearFormDialoglnurldevice() {
|
||||
this.formDialoglnurldevice.data = {
|
||||
lnurl_toggle: false,
|
||||
show_message: false,
|
||||
|
@@ -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,))
|
||||
|
@@ -44,7 +44,7 @@
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
||||
<code
|
||||
>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 }}"
|
||||
</code>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
@@ -57,13 +57,14 @@
|
||||
/usermanager/api/v1/users/<user_id></code
|
||||
>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Body (application/json)</h5>
|
||||
|
||||
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">
|
||||
Returns 200 OK (application/json)
|
||||
</h5>
|
||||
<code
|
||||
>{"id": <string>, "name": <string>, "admin":
|
||||
<string>, "email": <string>, "password": <string>}</code
|
||||
<string>, "email": <string>, "password":
|
||||
<string>}</code
|
||||
>
|
||||
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
||||
@@ -80,7 +81,7 @@
|
||||
<q-card-section>
|
||||
<code
|
||||
><span class="text-light-blue">GET</span>
|
||||
/usermanager/api/v1/wallets/<user_id></code
|
||||
/usermanager/api/v1/wallets</code
|
||||
>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
|
||||
<code>{"X-Api-Key": <string>}</code>
|
||||
@@ -91,9 +92,8 @@
|
||||
<code>JSON wallet data</code>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
||||
<code
|
||||
>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 }}"
|
||||
</code>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
@@ -220,7 +220,7 @@
|
||||
<code
|
||||
>curl -X DELETE {{ request.base_url
|
||||
}}usermanager/api/v1/users/<user_id> -H "X-Api-Key: {{
|
||||
user.wallets[0].inkey }}"
|
||||
user.wallets[0].adminkey }}"
|
||||
</code>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
@@ -238,7 +238,7 @@
|
||||
<code
|
||||
>curl -X DELETE {{ request.base_url
|
||||
}}usermanager/api/v1/wallets/<wallet_id> -H "X-Api-Key: {{
|
||||
user.wallets[0].inkey }}"
|
||||
user.wallets[0].adminkey }}"
|
||||
</code>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
@@ -259,15 +259,15 @@
|
||||
<code>{"X-Api-Key": <string>}</code>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
||||
<code
|
||||
>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"
|
||||
</code>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">
|
||||
Returns 200 OK (application/json)
|
||||
</h5>
|
||||
<code
|
||||
>{"extension": "updated"}</code
|
||||
>
|
||||
<code>{"extension": "updated"}</code>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</q-expansion-item>
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user