back
This commit is contained in:
@@ -13,10 +13,12 @@ lnurlpayout_ext: APIRouter = APIRouter(prefix="/lnurlpayout", tags=["lnurlpayout
|
||||
def lnurlpayout_renderer():
|
||||
return template_renderer(["lnbits/extensions/lnurlpayout/templates"])
|
||||
|
||||
|
||||
from .tasks import wait_for_paid_invoices
|
||||
from .views import * # noqa
|
||||
from .views_api import * # noqa
|
||||
|
||||
|
||||
def lnurlpayout_start():
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.create_task(catch_everything_and_restart(wait_for_paid_invoices))
|
||||
|
||||
@@ -6,14 +6,23 @@ from . import db
|
||||
from .models import lnurlpayout, CreateLnurlPayoutData
|
||||
|
||||
|
||||
async def create_lnurlpayout(wallet_id: str, admin_key: str, data: CreateLnurlPayoutData) -> lnurlpayout:
|
||||
async def create_lnurlpayout(
|
||||
wallet_id: str, admin_key: str, data: CreateLnurlPayoutData
|
||||
) -> lnurlpayout:
|
||||
lnurlpayout_id = urlsafe_short_hash()
|
||||
await db.execute(
|
||||
"""
|
||||
INSERT INTO lnurlpayout.lnurlpayouts (id, title, wallet, admin_key, lnurlpay, threshold)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(lnurlpayout_id, data.title, wallet_id, admin_key, data.lnurlpay, data.threshold),
|
||||
(
|
||||
lnurlpayout_id,
|
||||
data.title,
|
||||
wallet_id,
|
||||
admin_key,
|
||||
data.lnurlpay,
|
||||
data.threshold,
|
||||
),
|
||||
)
|
||||
|
||||
lnurlpayout = await get_lnurlpayout(lnurlpayout_id)
|
||||
@@ -22,13 +31,19 @@ async def create_lnurlpayout(wallet_id: str, admin_key: str, data: CreateLnurlPa
|
||||
|
||||
|
||||
async def get_lnurlpayout(lnurlpayout_id: str) -> Optional[lnurlpayout]:
|
||||
row = await db.fetchone("SELECT * FROM lnurlpayout.lnurlpayouts WHERE id = ?", (lnurlpayout_id,))
|
||||
row = await db.fetchone(
|
||||
"SELECT * FROM lnurlpayout.lnurlpayouts WHERE id = ?", (lnurlpayout_id,)
|
||||
)
|
||||
return lnurlpayout(**row) if row else None
|
||||
|
||||
|
||||
async def get_lnurlpayout_from_wallet(wallet_id: str) -> Optional[lnurlpayout]:
|
||||
row = await db.fetchone("SELECT * FROM lnurlpayout.lnurlpayouts WHERE wallet = ?", (wallet_id,))
|
||||
row = await db.fetchone(
|
||||
"SELECT * FROM lnurlpayout.lnurlpayouts WHERE wallet = ?", (wallet_id,)
|
||||
)
|
||||
return lnurlpayout(**row) if row else None
|
||||
|
||||
|
||||
async def get_lnurlpayouts(wallet_ids: Union[str, List[str]]) -> List[lnurlpayout]:
|
||||
if isinstance(wallet_ids, str):
|
||||
wallet_ids = [wallet_ids]
|
||||
@@ -42,4 +57,6 @@ async def get_lnurlpayouts(wallet_ids: Union[str, List[str]]) -> List[lnurlpayou
|
||||
|
||||
|
||||
async def delete_lnurlpayout(lnurlpayout_id: str) -> None:
|
||||
await db.execute("DELETE FROM lnurlpayout.lnurlpayouts WHERE id = ?", (lnurlpayout_id,))
|
||||
await db.execute(
|
||||
"DELETE FROM lnurlpayout.lnurlpayouts WHERE id = ?", (lnurlpayout_id,)
|
||||
)
|
||||
|
||||
@@ -2,11 +2,13 @@ from sqlite3 import Row
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class CreateLnurlPayoutData(BaseModel):
|
||||
title: str
|
||||
lnurlpay: str
|
||||
threshold: int
|
||||
|
||||
|
||||
class lnurlpayout(BaseModel):
|
||||
id: str
|
||||
title: str
|
||||
|
||||
@@ -26,28 +26,33 @@ async def on_invoice_paid(payment: Payment) -> None:
|
||||
# Check its got a payout associated with it
|
||||
lnurlpayout_link = await get_lnurlpayout_from_wallet(payment.wallet_id)
|
||||
if lnurlpayout_link:
|
||||
|
||||
|
||||
# Check the wallet balance is more than the threshold
|
||||
|
||||
|
||||
wallet = await get_wallet(lnurlpayout_link.wallet)
|
||||
if wallet.balance < lnurlpayout_link.threshold + (lnurlpayout_link.threshold*0.02):
|
||||
if wallet.balance < lnurlpayout_link.threshold + (
|
||||
lnurlpayout_link.threshold * 0.02
|
||||
):
|
||||
return
|
||||
|
||||
|
||||
# Get the invoice from the LNURL to pay
|
||||
async with httpx.AsyncClient() as client:
|
||||
try:
|
||||
url = await api_payments_decode({"data": lnurlpayout_link.lnurlpay})
|
||||
if str(url["domain"])[0:4] != "http":
|
||||
raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="LNURL broken")
|
||||
try:
|
||||
r = await client.get(
|
||||
str(url["domain"]),
|
||||
timeout=40,
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.FORBIDDEN, detail="LNURL broken"
|
||||
)
|
||||
try:
|
||||
r = await client.get(str(url["domain"]), timeout=40)
|
||||
res = r.json()
|
||||
try:
|
||||
r = await client.get(
|
||||
res["callback"] + "?amount=" + str(int((wallet.balance - wallet.balance*0.02) * 1000)),
|
||||
res["callback"]
|
||||
+ "?amount="
|
||||
+ str(
|
||||
int((wallet.balance - wallet.balance * 0.02) * 1000)
|
||||
),
|
||||
timeout=40,
|
||||
)
|
||||
res = r.json()
|
||||
@@ -65,6 +70,9 @@ async def on_invoice_paid(payment: Payment) -> None:
|
||||
except (httpx.ConnectError, httpx.RequestError):
|
||||
return
|
||||
except Exception:
|
||||
raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="Failed to save LNURLPayout")
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.FORBIDDEN,
|
||||
detail="Failed to save LNURLPayout",
|
||||
)
|
||||
except:
|
||||
return
|
||||
return
|
||||
|
||||
@@ -10,10 +10,17 @@ from lnbits.core.views.api import api_payment, api_payments_decode
|
||||
from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key
|
||||
|
||||
from . import lnurlpayout_ext
|
||||
from .crud import create_lnurlpayout, delete_lnurlpayout, get_lnurlpayout, get_lnurlpayouts, get_lnurlpayout_from_wallet
|
||||
from .crud import (
|
||||
create_lnurlpayout,
|
||||
delete_lnurlpayout,
|
||||
get_lnurlpayout,
|
||||
get_lnurlpayouts,
|
||||
get_lnurlpayout_from_wallet,
|
||||
)
|
||||
from .models import lnurlpayout, CreateLnurlPayoutData
|
||||
from .tasks import on_invoice_paid
|
||||
|
||||
|
||||
@lnurlpayout_ext.get("/api/v1/lnurlpayouts", status_code=HTTPStatus.OK)
|
||||
async def api_lnurlpayouts(
|
||||
all_wallets: bool = Query(None), wallet: WalletTypeInfo = Depends(get_key_type)
|
||||
@@ -28,23 +35,33 @@ async def api_lnurlpayouts(
|
||||
@lnurlpayout_ext.post("/api/v1/lnurlpayouts", status_code=HTTPStatus.CREATED)
|
||||
async def api_lnurlpayout_create(
|
||||
data: CreateLnurlPayoutData, wallet: WalletTypeInfo = Depends(get_key_type)
|
||||
):
|
||||
):
|
||||
if await get_lnurlpayout_from_wallet(wallet.wallet.id):
|
||||
raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="Wallet already has lnurlpayout set")
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.FORBIDDEN,
|
||||
detail="Wallet already has lnurlpayout set",
|
||||
)
|
||||
return
|
||||
url = await api_payments_decode({"data": data.lnurlpay})
|
||||
if "domain" not in url:
|
||||
raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="LNURL could not be decoded")
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.FORBIDDEN, detail="LNURL could not be decoded"
|
||||
)
|
||||
return
|
||||
if str(url["domain"])[0:4] != "http":
|
||||
raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="Not valid LNURL")
|
||||
return
|
||||
lnurlpayout = await create_lnurlpayout(wallet_id=wallet.wallet.id, admin_key=wallet.wallet.adminkey, data=data)
|
||||
lnurlpayout = await create_lnurlpayout(
|
||||
wallet_id=wallet.wallet.id, admin_key=wallet.wallet.adminkey, data=data
|
||||
)
|
||||
if not lnurlpayout:
|
||||
raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="Failed to save LNURLPayout")
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.FORBIDDEN, detail="Failed to save LNURLPayout"
|
||||
)
|
||||
return
|
||||
return lnurlpayout.dict()
|
||||
|
||||
|
||||
@lnurlpayout_ext.delete("/api/v1/lnurlpayouts/{lnurlpayout_id}")
|
||||
async def api_lnurlpayout_delete(
|
||||
lnurlpayout_id: str, wallet: WalletTypeInfo = Depends(require_admin_key)
|
||||
@@ -57,26 +74,34 @@ async def api_lnurlpayout_delete(
|
||||
)
|
||||
|
||||
if lnurlpayout.wallet != wallet.wallet.id:
|
||||
raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="Not your lnurlpayout.")
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.FORBIDDEN, detail="Not your lnurlpayout."
|
||||
)
|
||||
|
||||
await delete_lnurlpayout(lnurlpayout_id)
|
||||
raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
|
||||
|
||||
|
||||
@lnurlpayout_ext.get("/api/v1/lnurlpayouts/{lnurlpayout_id}", status_code=HTTPStatus.OK)
|
||||
async def api_lnurlpayout_check(
|
||||
lnurlpayout_id: str, wallet: WalletTypeInfo = Depends(get_key_type)
|
||||
):
|
||||
):
|
||||
lnurlpayout = await get_lnurlpayout(lnurlpayout_id)
|
||||
payments = await get_payments(
|
||||
wallet_id=lnurlpayout.wallet, complete=True, pending=False, outgoing=True, incoming=True
|
||||
wallet_id=lnurlpayout.wallet,
|
||||
complete=True,
|
||||
pending=False,
|
||||
outgoing=True,
|
||||
incoming=True,
|
||||
)
|
||||
result = await on_invoice_paid(payments[0])
|
||||
return
|
||||
|
||||
# get payouts func
|
||||
# lnurlpayouts = await get_lnurlpayouts(wallet_ids)
|
||||
# for lnurlpayout in lnurlpayouts:
|
||||
# payments = await get_payments(
|
||||
# wallet_id=lnurlpayout.wallet, complete=True, pending=False, outgoing=True, incoming=True
|
||||
# )
|
||||
# await on_invoice_paid(payments[0])
|
||||
|
||||
# get payouts func
|
||||
# lnurlpayouts = await get_lnurlpayouts(wallet_ids)
|
||||
# for lnurlpayout in lnurlpayouts:
|
||||
# payments = await get_payments(
|
||||
# wallet_id=lnurlpayout.wallet, complete=True, pending=False, outgoing=True, incoming=True
|
||||
# )
|
||||
# await on_invoice_paid(payments[0])
|
||||
|
||||
Reference in New Issue
Block a user