From ea3418c21d4f2f82858b954fc66d99cd933a231a Mon Sep 17 00:00:00 2001 From: fiatjaf Date: Fri, 9 Oct 2020 16:17:16 -0300 Subject: [PATCH] lnurlp: support success_text and success_url. --- lnbits/extensions/lnurlp/crud.py | 24 +++++++--- lnbits/extensions/lnurlp/lnurl.py | 8 +++- lnbits/extensions/lnurlp/models.py | 18 +++++++- .../lnurlp/templates/lnurlp/display.html | 2 +- .../lnurlp/templates/lnurlp/index.html | 45 ++++++++++++++++++- lnbits/extensions/lnurlp/views_api.py | 2 + 6 files changed, 88 insertions(+), 11 deletions(-) diff --git a/lnbits/extensions/lnurlp/crud.py b/lnbits/extensions/lnurlp/crud.py index 755925ec..eb151f91 100644 --- a/lnbits/extensions/lnurlp/crud.py +++ b/lnbits/extensions/lnurlp/crud.py @@ -7,7 +7,13 @@ from .models import PayLink def create_pay_link( - *, wallet_id: str, description: str, amount: int, webhook_url: Optional[str] = None + *, + wallet_id: str, + description: str, + amount: int, + webhook_url: Optional[str] = None, + success_text: Optional[str] = None, + success_url: Optional[str] = None, ) -> Optional[PayLink]: with open_ext_db("lnurlp") as db: db.execute( @@ -18,11 +24,13 @@ def create_pay_link( amount, served_meta, served_pr, - webhook_url + webhook_url, + success_text, + success_url ) - VALUES (?, ?, ?, 0, 0, ?) + VALUES (?, ?, ?, 0, 0, ?, ?, ?) """, - (wallet_id, description, amount, webhook_url), + (wallet_id, description, amount, webhook_url, success_text, success_url), ) link_id = db.cursor.lastrowid return get_pay_link(link_id) @@ -57,7 +65,13 @@ def get_pay_links(wallet_ids: Union[str, List[str]]) -> List[PayLink]: with open_ext_db("lnurlp") as db: q = ",".join(["?"] * len(wallet_ids)) - rows = db.fetchall(f"SELECT * FROM pay_links WHERE wallet IN ({q})", (*wallet_ids,)) + rows = db.fetchall( + f""" + SELECT * FROM pay_links WHERE wallet IN ({q}) + ORDER BY Id + """, + (*wallet_ids,), + ) return [PayLink.from_row(row) for row in rows] diff --git a/lnbits/extensions/lnurlp/lnurl.py b/lnbits/extensions/lnurlp/lnurl.py index 5275927f..e77d02df 100644 --- a/lnbits/extensions/lnurlp/lnurl.py +++ b/lnbits/extensions/lnurlp/lnurl.py @@ -33,7 +33,7 @@ async def api_lnurl_callback(link_id): if not link: return jsonify({"status": "ERROR", "reason": "LNURL-pay not found."}), HTTPStatus.OK - _, payment_request = create_invoice( + payment_hash, payment_request = create_invoice( wallet_id=link.wallet, amount=link.amount, memo=link.description, @@ -43,6 +43,10 @@ async def api_lnurl_callback(link_id): save_link_invoice(link_id, payment_request) - resp = LnurlPayActionResponse(pr=payment_request, success_action=None, routes=[]) + resp = LnurlPayActionResponse( + pr=payment_request, + success_action=link.success_action(payment_hash), + routes=[], + ) return jsonify(resp.dict()), HTTPStatus.OK diff --git a/lnbits/extensions/lnurlp/models.py b/lnbits/extensions/lnurlp/models.py index e376cf75..c15235f9 100644 --- a/lnbits/extensions/lnurlp/models.py +++ b/lnbits/extensions/lnurlp/models.py @@ -1,9 +1,11 @@ import json +from urllib.parse import urlparse, urlunparse, parse_qs, urlencode, ParseResult from quart import url_for +from typing import NamedTuple, Optional, Dict +from sqlite3 import Row from lnurl import Lnurl, encode as lnurl_encode from lnurl.types import LnurlPayMetadata -from sqlite3 import Row -from typing import NamedTuple +from lnurl.models import LnurlPaySuccessAction, MessageAction, UrlAction class PayLink(NamedTuple): @@ -31,6 +33,18 @@ class PayLink(NamedTuple): def lnurlpay_metadata(self) -> LnurlPayMetadata: return LnurlPayMetadata(json.dumps([["text/plain", self.description]])) + def success_action(self, payment_hash: str) -> Optional[LnurlPaySuccessAction]: + if self.success_url: + url: ParseResult = urlparse(self.success_url) + qs: Dict = parse_qs(url.query) + qs["payment_hash"] = payment_hash + url = url._replace(query=urlencode(qs)) + return UrlAction(url=urlunparse(url), description=self.success_text) + elif self.success_text: + return MessageAction(message=self.success_text) + else: + return None + class Invoice(NamedTuple): payment_hash: str diff --git a/lnbits/extensions/lnurlp/templates/lnurlp/display.html b/lnbits/extensions/lnurlp/templates/lnurlp/display.html index 6122a895..fd9b3dee 100644 --- a/lnbits/extensions/lnurlp/templates/lnurlp/display.html +++ b/lnbits/extensions/lnurlp/templates/lnurlp/display.html @@ -27,7 +27,7 @@
LNbits LNURL-pay link

- Use a LNURL compatible bitcoin wallet to claim the sats. + Use an LNURL compatible bitcoin wallet to pay.

diff --git a/lnbits/extensions/lnurlp/templates/lnurlp/index.html b/lnbits/extensions/lnurlp/templates/lnurlp/index.html index 324df67b..f7bb76a2 100644 --- a/lnbits/extensions/lnurlp/templates/lnurlp/index.html +++ b/lnbits/extensions/lnurlp/templates/lnurlp/index.html @@ -137,6 +137,23 @@ v-model="formDialog.data.webhook_url" type="text" label="Webhook URL (optional)" + hint="An URL to be called whenever this link receives a payment." + > + +
ID: {{ qrCodeDialog.data.id }}
Amount: {{ qrCodeDialog.data.amount }} sat
Webhook: {{ qrCodeDialog.data.webhook_url }}
+ Success Message: {{ qrCodeDialog.data.success_text + }}
+ Success URL: {{ qrCodeDialog.data.success_url }}

{% endraw %}
@@ -263,6 +283,13 @@ align: 'left', label: 'Webhook URL', field: 'webhook_url' + }, + { + name: 'success_action', + align: 'center', + label: '', + format: (_, row) => + row.success_text || row.success_url ? '💬' : '' } ], pagination: { @@ -341,12 +368,28 @@ updatePayLink: function (wallet, data) { var self = this + let values = _.omit( + _.pick( + data, + 'description', + 'amount', + 'webhook_url', + 'success_text', + 'success_url' + ), + (value, key) => + (key === 'webhook_url' || + key === 'success_text' || + key === 'success_url') && + (value === null || value === '') + ) + LNbits.api .request( 'PUT', '/lnurlp/api/v1/links/' + data.id, wallet.adminkey, - _.pick(data, 'description', 'amount', 'webhook_url') + values ) .then(function (response) { self.payLinks = _.reject(self.payLinks, function (obj) { diff --git a/lnbits/extensions/lnurlp/views_api.py b/lnbits/extensions/lnurlp/views_api.py index e5485475..9dac7b39 100644 --- a/lnbits/extensions/lnurlp/views_api.py +++ b/lnbits/extensions/lnurlp/views_api.py @@ -57,6 +57,8 @@ async def api_link_retrieve(link_id): "description": {"type": "string", "empty": False, "required": True}, "amount": {"type": "integer", "min": 1, "required": True}, "webhook_url": {"type": "string", "required": False}, + "success_text": {"type": "string", "required": False}, + "success_url": {"type": "string", "required": False}, } ) async def api_link_create_or_update(link_id=None):