remove exception to black line-length and reformat.
This commit is contained in:
@@ -4,7 +4,11 @@ from lnbits.db import Database
|
||||
db = Database("database")
|
||||
|
||||
core_app: Blueprint = Blueprint(
|
||||
"core", __name__, template_folder="templates", static_folder="static", static_url_path="/core/static"
|
||||
"core",
|
||||
__name__,
|
||||
template_folder="templates",
|
||||
static_folder="static",
|
||||
static_url_path="/core/static",
|
||||
)
|
||||
|
||||
|
||||
|
||||
+25
-5
@@ -25,7 +25,9 @@ async def create_account() -> User:
|
||||
|
||||
|
||||
async def get_account(user_id: str) -> Optional[User]:
|
||||
row = await db.fetchone("SELECT id, email, pass as password FROM accounts WHERE id = ?", (user_id,))
|
||||
row = await db.fetchone(
|
||||
"SELECT id, email, pass as password FROM accounts WHERE id = ?", (user_id,)
|
||||
)
|
||||
|
||||
return User(**row) if row else None
|
||||
|
||||
@@ -34,7 +36,9 @@ async def get_user(user_id: str) -> Optional[User]:
|
||||
user = await db.fetchone("SELECT id, email FROM accounts WHERE id = ?", (user_id,))
|
||||
|
||||
if user:
|
||||
extensions = await db.fetchall("SELECT extension FROM extensions WHERE user = ? AND active = 1", (user_id,))
|
||||
extensions = await db.fetchall(
|
||||
"SELECT extension FROM extensions WHERE user = ? AND active = 1", (user_id,)
|
||||
)
|
||||
wallets = await db.fetchall(
|
||||
"""
|
||||
SELECT *, COALESCE((SELECT balance FROM balances WHERE wallet = wallets.id), 0) AS balance_msat
|
||||
@@ -45,7 +49,15 @@ async def get_user(user_id: str) -> Optional[User]:
|
||||
)
|
||||
|
||||
return (
|
||||
User(**{**user, **{"extensions": [e[0] for e in extensions], "wallets": [Wallet(**w) for w in wallets]}})
|
||||
User(
|
||||
**{
|
||||
**user,
|
||||
**{
|
||||
"extensions": [e[0] for e in extensions],
|
||||
"wallets": [Wallet(**w) for w in wallets],
|
||||
},
|
||||
}
|
||||
)
|
||||
if user
|
||||
else None
|
||||
)
|
||||
@@ -72,7 +84,13 @@ async def create_wallet(*, user_id: str, wallet_name: Optional[str] = None) -> W
|
||||
INSERT INTO wallets (id, name, user, adminkey, inkey)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
""",
|
||||
(wallet_id, wallet_name or DEFAULT_WALLET_NAME, user_id, uuid4().hex, uuid4().hex),
|
||||
(
|
||||
wallet_id,
|
||||
wallet_name or DEFAULT_WALLET_NAME,
|
||||
user_id,
|
||||
uuid4().hex,
|
||||
uuid4().hex,
|
||||
),
|
||||
)
|
||||
|
||||
new_wallet = await get_wallet(wallet_id=wallet_id)
|
||||
@@ -280,7 +298,9 @@ async def create_payment(
|
||||
int(pending),
|
||||
memo,
|
||||
fee,
|
||||
json.dumps(extra) if extra and extra != {} and type(extra) is dict else None,
|
||||
json.dumps(extra)
|
||||
if extra and extra != {} and type(extra) is dict
|
||||
else None,
|
||||
webhook,
|
||||
),
|
||||
)
|
||||
|
||||
@@ -111,7 +111,12 @@ async def m002_add_fields_to_apipayments(db):
|
||||
UPDATE apipayments SET extra = ?, memo = ?
|
||||
WHERE checking_id = ? AND memo = ?
|
||||
""",
|
||||
(json.dumps({"tag": ext}), new, row["checking_id"], row["memo"]),
|
||||
(
|
||||
json.dumps({"tag": ext}),
|
||||
new,
|
||||
row["checking_id"],
|
||||
row["memo"],
|
||||
),
|
||||
)
|
||||
break
|
||||
except OperationalError:
|
||||
|
||||
@@ -127,7 +127,9 @@ class Payment(NamedTuple):
|
||||
|
||||
@property
|
||||
def is_uncheckable(self) -> bool:
|
||||
return self.checking_id.startswith("temp_") or self.checking_id.startswith("internal_")
|
||||
return self.checking_id.startswith("temp_") or self.checking_id.startswith(
|
||||
"internal_"
|
||||
)
|
||||
|
||||
async def set_pending(self, pending: bool) -> None:
|
||||
from .crud import update_payment_status
|
||||
|
||||
+21
-5
@@ -18,7 +18,14 @@ from lnbits.settings import WALLET
|
||||
from lnbits.wallets.base import PaymentStatus, PaymentResponse
|
||||
|
||||
from . import db
|
||||
from .crud import get_wallet, create_payment, delete_payment, check_internal, update_payment_status, get_wallet_payment
|
||||
from .crud import (
|
||||
get_wallet,
|
||||
create_payment,
|
||||
delete_payment,
|
||||
check_internal,
|
||||
update_payment_status,
|
||||
get_wallet_payment,
|
||||
)
|
||||
|
||||
|
||||
async def create_invoice(
|
||||
@@ -101,7 +108,9 @@ async def pay_invoice(
|
||||
internal_checking_id = await check_internal(invoice.payment_hash)
|
||||
if internal_checking_id:
|
||||
# create a new payment from this wallet
|
||||
await create_payment(checking_id=internal_id, fee=0, pending=False, **payment_kwargs)
|
||||
await create_payment(
|
||||
checking_id=internal_id, fee=0, pending=False, **payment_kwargs
|
||||
)
|
||||
else:
|
||||
# create a temporary payment here so we can check if
|
||||
# the balance is enough in the next step
|
||||
@@ -143,12 +152,16 @@ async def pay_invoice(
|
||||
else:
|
||||
await delete_payment(temp_id)
|
||||
await db.commit()
|
||||
raise Exception(payment.error_message or "Failed to pay_invoice on backend.")
|
||||
raise Exception(
|
||||
payment.error_message or "Failed to pay_invoice on backend."
|
||||
)
|
||||
|
||||
return invoice.payment_hash
|
||||
|
||||
|
||||
async def redeem_lnurl_withdraw(wallet_id: str, res: LnurlWithdrawResponse, memo: Optional[str] = None) -> None:
|
||||
async def redeem_lnurl_withdraw(
|
||||
wallet_id: str, res: LnurlWithdrawResponse, memo: Optional[str] = None
|
||||
) -> None:
|
||||
_, payment_request = await create_invoice(
|
||||
wallet_id=wallet_id,
|
||||
amount=res.max_sats,
|
||||
@@ -159,7 +172,10 @@ async def redeem_lnurl_withdraw(wallet_id: str, res: LnurlWithdrawResponse, memo
|
||||
async with httpx.AsyncClient() as client:
|
||||
await client.get(
|
||||
res.callback.base,
|
||||
params={**res.callback.query_params, **{"k1": res.k1, "pr": payment_request}},
|
||||
params={
|
||||
**res.callback.query_params,
|
||||
**{"k1": res.k1, "pr": payment_request},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
|
||||
+50
-10
@@ -41,8 +41,18 @@ async def api_payments():
|
||||
@api_validate_post_request(
|
||||
schema={
|
||||
"amount": {"type": "integer", "min": 1, "required": True},
|
||||
"memo": {"type": "string", "empty": False, "required": True, "excludes": "description_hash"},
|
||||
"description_hash": {"type": "string", "empty": False, "required": True, "excludes": "memo"},
|
||||
"memo": {
|
||||
"type": "string",
|
||||
"empty": False,
|
||||
"required": True,
|
||||
"excludes": "description_hash",
|
||||
},
|
||||
"description_hash": {
|
||||
"type": "string",
|
||||
"empty": False,
|
||||
"required": True,
|
||||
"excludes": "memo",
|
||||
},
|
||||
"lnurl_callback": {"type": "string", "nullable": True, "required": False},
|
||||
"extra": {"type": "dict", "nullable": True, "required": False},
|
||||
"webhook": {"type": "string", "empty": False, "required": False},
|
||||
@@ -108,10 +118,14 @@ async def api_payments_create_invoice():
|
||||
|
||||
|
||||
@api_check_wallet_key("admin")
|
||||
@api_validate_post_request(schema={"bolt11": {"type": "string", "empty": False, "required": True}})
|
||||
@api_validate_post_request(
|
||||
schema={"bolt11": {"type": "string", "empty": False, "required": True}}
|
||||
)
|
||||
async def api_payments_pay_invoice():
|
||||
try:
|
||||
payment_hash = await pay_invoice(wallet_id=g.wallet.id, payment_request=g.data["bolt11"])
|
||||
payment_hash = await pay_invoice(
|
||||
wallet_id=g.wallet.id, payment_request=g.data["bolt11"]
|
||||
)
|
||||
except ValueError as e:
|
||||
return jsonify({"message": str(e)}), HTTPStatus.BAD_REQUEST
|
||||
except PermissionError as e:
|
||||
@@ -147,8 +161,18 @@ async def api_payments_create():
|
||||
"description_hash": {"type": "string", "empty": False, "required": True},
|
||||
"callback": {"type": "string", "empty": False, "required": True},
|
||||
"amount": {"type": "number", "empty": False, "required": True},
|
||||
"comment": {"type": "string", "nullable": True, "empty": True, "required": False},
|
||||
"description": {"type": "string", "nullable": True, "empty": True, "required": False},
|
||||
"comment": {
|
||||
"type": "string",
|
||||
"nullable": True,
|
||||
"empty": True,
|
||||
"required": False,
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"nullable": True,
|
||||
"empty": True,
|
||||
"required": False,
|
||||
},
|
||||
}
|
||||
)
|
||||
async def api_payments_pay_lnurl():
|
||||
@@ -168,7 +192,10 @@ async def api_payments_pay_lnurl():
|
||||
|
||||
params = json.loads(r.text)
|
||||
if params.get("status") == "ERROR":
|
||||
return jsonify({"message": f"{domain} said: '{params.get('reason', '')}'"}), HTTPStatus.BAD_REQUEST
|
||||
return (
|
||||
jsonify({"message": f"{domain} said: '{params.get('reason', '')}'"}),
|
||||
HTTPStatus.BAD_REQUEST,
|
||||
)
|
||||
|
||||
invoice = bolt11.decode(params["pr"])
|
||||
if invoice.amount_msat != g.data["amount"]:
|
||||
@@ -236,7 +263,10 @@ async def api_payment(payment_hash):
|
||||
except Exception:
|
||||
return jsonify({"paid": False}), HTTPStatus.OK
|
||||
|
||||
return jsonify({"paid": not payment.pending, "preimage": payment.preimage}), HTTPStatus.OK
|
||||
return (
|
||||
jsonify({"paid": not payment.pending, "preimage": payment.preimage}),
|
||||
HTTPStatus.OK,
|
||||
)
|
||||
|
||||
|
||||
@core_app.route("/api/v1/payments/sse", methods=["GET"])
|
||||
@@ -325,12 +355,22 @@ async def api_lnurlscan(code: str):
|
||||
data: lnurl.LnurlResponseModel = lnurl.LnurlResponse.from_dict(jdata)
|
||||
except (json.decoder.JSONDecodeError, lnurl.exceptions.LnurlResponseException):
|
||||
return (
|
||||
jsonify({"domain": domain, "message": f"got invalid response '{r.text[:200]}'"}),
|
||||
jsonify(
|
||||
{
|
||||
"domain": domain,
|
||||
"message": f"got invalid response '{r.text[:200]}'",
|
||||
}
|
||||
),
|
||||
HTTPStatus.SERVICE_UNAVAILABLE,
|
||||
)
|
||||
|
||||
if type(data) is lnurl.LnurlChannelResponse:
|
||||
return jsonify({"domain": domain, "kind": "channel", "message": "unsupported"}), HTTPStatus.BAD_REQUEST
|
||||
return (
|
||||
jsonify(
|
||||
{"domain": domain, "kind": "channel", "message": "unsupported"}
|
||||
),
|
||||
HTTPStatus.BAD_REQUEST,
|
||||
)
|
||||
|
||||
params.update(**data.dict())
|
||||
|
||||
|
||||
@@ -2,7 +2,15 @@ import trio # type: ignore
|
||||
import httpx
|
||||
from os import path
|
||||
from http import HTTPStatus
|
||||
from quart import g, abort, redirect, request, render_template, send_from_directory, url_for
|
||||
from quart import (
|
||||
g,
|
||||
abort,
|
||||
redirect,
|
||||
request,
|
||||
render_template,
|
||||
send_from_directory,
|
||||
url_for,
|
||||
)
|
||||
from lnurl import LnurlResponse, LnurlWithdrawResponse, decode as decode_lnurl # type: ignore
|
||||
|
||||
from lnbits.core import core_app
|
||||
@@ -22,12 +30,16 @@ from ..services import redeem_lnurl_withdraw
|
||||
|
||||
@core_app.route("/favicon.ico")
|
||||
async def favicon():
|
||||
return await send_from_directory(path.join(core_app.root_path, "static"), "favicon.ico")
|
||||
return await send_from_directory(
|
||||
path.join(core_app.root_path, "static"), "favicon.ico"
|
||||
)
|
||||
|
||||
|
||||
@core_app.route("/")
|
||||
async def home():
|
||||
return await render_template("core/index.html", lnurl=request.args.get("lightning", None))
|
||||
return await render_template(
|
||||
"core/index.html", lnurl=request.args.get("lightning", None)
|
||||
)
|
||||
|
||||
|
||||
@core_app.route("/extensions")
|
||||
@@ -38,12 +50,18 @@ async def extensions():
|
||||
extension_to_disable = request.args.get("disable", type=str)
|
||||
|
||||
if extension_to_enable and extension_to_disable:
|
||||
abort(HTTPStatus.BAD_REQUEST, "You can either `enable` or `disable` an extension.")
|
||||
abort(
|
||||
HTTPStatus.BAD_REQUEST, "You can either `enable` or `disable` an extension."
|
||||
)
|
||||
|
||||
if extension_to_enable:
|
||||
await update_user_extension(user_id=g.user.id, extension=extension_to_enable, active=1)
|
||||
await update_user_extension(
|
||||
user_id=g.user.id, extension=extension_to_enable, active=1
|
||||
)
|
||||
elif extension_to_disable:
|
||||
await update_user_extension(user_id=g.user.id, extension=extension_to_disable, active=0)
|
||||
await update_user_extension(
|
||||
user_id=g.user.id, extension=extension_to_disable, active=0
|
||||
)
|
||||
|
||||
return await render_template("core/extensions.html", user=await get_user(g.user.id))
|
||||
|
||||
@@ -85,7 +103,9 @@ async def wallet():
|
||||
if not wallet:
|
||||
abort(HTTPStatus.FORBIDDEN, "Not your wallet.")
|
||||
|
||||
return await render_template("core/wallet.html", user=user, wallet=wallet, service_fee=service_fee)
|
||||
return await render_template(
|
||||
"core/wallet.html", user=user, wallet=wallet, service_fee=service_fee
|
||||
)
|
||||
|
||||
|
||||
@core_app.route("/deletewallet")
|
||||
@@ -116,19 +136,33 @@ async def lnurlwallet():
|
||||
withdraw_res = LnurlResponse.from_dict(r.json())
|
||||
|
||||
if not withdraw_res.ok:
|
||||
return f"Could not process lnurl-withdraw: {withdraw_res.error_msg}", HTTPStatus.BAD_REQUEST
|
||||
return (
|
||||
f"Could not process lnurl-withdraw: {withdraw_res.error_msg}",
|
||||
HTTPStatus.BAD_REQUEST,
|
||||
)
|
||||
|
||||
if not isinstance(withdraw_res, LnurlWithdrawResponse):
|
||||
return f"Expected an lnurl-withdraw code, got {withdraw_res.tag}", HTTPStatus.BAD_REQUEST
|
||||
return (
|
||||
f"Expected an lnurl-withdraw code, got {withdraw_res.tag}",
|
||||
HTTPStatus.BAD_REQUEST,
|
||||
)
|
||||
except Exception as exc:
|
||||
return f"Could not process lnurl-withdraw: {exc}", HTTPStatus.INTERNAL_SERVER_ERROR
|
||||
return (
|
||||
f"Could not process lnurl-withdraw: {exc}",
|
||||
HTTPStatus.INTERNAL_SERVER_ERROR,
|
||||
)
|
||||
|
||||
account = await create_account()
|
||||
user = await get_user(account.id)
|
||||
wallet = await create_wallet(user_id=user.id)
|
||||
await db.commit()
|
||||
|
||||
g.nursery.start_soon(redeem_lnurl_withdraw, wallet.id, withdraw_res, "LNbits initial funding: voucher redeem.")
|
||||
g.nursery.start_soon(
|
||||
redeem_lnurl_withdraw,
|
||||
wallet.id,
|
||||
withdraw_res,
|
||||
"LNbits initial funding: voucher redeem.",
|
||||
)
|
||||
await trio.sleep(3)
|
||||
|
||||
return redirect(url_for("core.wallet", usr=user.id, wal=wallet.id))
|
||||
|
||||
Reference in New Issue
Block a user