Added wallet, lnurl generation should work

This commit is contained in:
Ben Arc
2021-04-14 21:39:51 +01:00
parent af2e1b5d02
commit 0e67e6a0bb
5 changed files with 61 additions and 46 deletions

View File

@@ -9,19 +9,19 @@ from . import copilot_ext
from .crud import get_copilot from .crud import get_copilot
@copilot_ext.route("/lnurl/<copilot_id>", methods=["GET"]) @copilot_ext.route("/lnurl/<cp_id>", methods=["GET"])
async def lnurl_response(copilot_id): async def lnurl_response(cp_id):
copilot = await get_copilot(copilot_id) cp = await get_copilot(cp_id)
if not copilot: if not cp:
return jsonify({"status": "ERROR", "reason": "Copilot not found."}) return jsonify({"status": "ERROR", "reason": "Copilot not found."})
resp = LnurlPayResponse( resp = LnurlPayResponse(
callback=url_for( callback=url_for(
"copilot.lnurl_callback", _external=True "copilot.lnurl_callback", track_id=track.id, _external=True
), ),
min_sendable=copilot.amount, min_sendable=10,
max_sendable=copilot.amount, max_sendable=50000,
metadata=copilot.lnurl_title, metadata=await cp.lnurl_title,
) )
params = resp.dict() params = resp.dict()
@@ -30,24 +30,27 @@ async def lnurl_response(copilot_id):
return jsonify(params) return jsonify(params)
@copilot_ext.route("/lnurl/cb", methods=["GET"]) @copilot_ext.route("/lnurl/cb/<cp_id>", methods=["GET"])
async def lnurl_callback(): async def lnurl_callback(cp_id):
cp = await get_copilot(cp_id)
if not cp:
return jsonify({"status": "ERROR", "reason": "Copilot not found."})
amount_received = int(request.args.get("amount")) amount_received = int(request.args.get("amount"))
if amount_received < track.amount: if amount_received < 10:
return ( return (
jsonify( jsonify(
LnurlErrorResponse( LnurlErrorResponse(
reason=f"Amount {round(amount_received / 1000)} is smaller than minimum {math.floor(track.min_sendable)}." reason=f"Amount {round(amount_received / 1000)} is smaller than minimum 10 sats."
).dict() ).dict()
), ),
) )
elif track.max_sendable < amount_received: elif 50000 > amount_received/1000:
return ( return (
jsonify( jsonify(
LnurlErrorResponse( LnurlErrorResponse(
reason=f"Amount {round(amount_received / 1000)} is greater than maximum {math.floor(track.max_sendable)}." reason=f"Amount {round(amount_received / 1000)} is greater than maximum 50000."
).dict() ).dict()
), ),
) )
@@ -60,21 +63,19 @@ async def lnurl_callback():
).dict() ).dict()
) )
copilot = await get_copilot_by_track(track_id)
payment_hash, payment_request = await create_invoice( payment_hash, payment_request = await create_invoice(
wallet_id=copilot.wallet, wallet_id=cp.wallet,
amount=int(amount_received / 1000), amount=int(amount_received / 1000),
memo=await track.fullname(), memo=cp.lnurl_title,
description_hash=hashlib.sha256( description_hash=hashlib.sha256(
(await track.lnurlpay_metadata()).encode("utf-8") (cp.lnurl_title).encode("utf-8")
).digest(), ).digest(),
extra={"tag": "copilot", "track": track.id, "comment": comment}, extra={"tag": "copilot", "comment": comment},
) )
if amount_received < track.price_msat: if amount_received < track.price_msat:
success_action = None success_action = None
ecopilote: else:
success_action = track.success_action(payment_hash) success_action = track.success_action(payment_hash)
resp = LnurlPayActionResponse( resp = LnurlPayActionResponse(
@@ -82,5 +83,8 @@ async def lnurl_callback():
success_action=success_action, success_action=success_action,
routes=[], routes=[],
) )
socket_sendererer = app.socket_sendererer()
async with socket_sendererer.websocket('/ws') as the_websocket:
await the_websocket.send("pay{payment_hash}")
return jsonify(resp.dict()) return jsonify(resp.dict())

View File

@@ -9,6 +9,7 @@ async def m001_initial(db):
id TEXT NOT NULL PRIMARY KEY, id TEXT NOT NULL PRIMARY KEY,
user TEXT, user TEXT,
title TEXT, title TEXT,
wallet TEXT,
animation1 TEXT, animation1 TEXT,
animation2 TEXT, animation2 TEXT,
animation3 TEXT, animation3 TEXT,

View File

@@ -2,11 +2,15 @@ from sqlite3 import Row
from typing import NamedTuple from typing import NamedTuple
import time import time
from lnurl import Lnurl, encode as lnurl_encode # type: ignore
from lnurl.types import LnurlPayMetadata # type: ignore
from lnurl.models import LnurlPaySuccessAction, UrlAction # type: ignore
class Copilots(NamedTuple): class Copilots(NamedTuple):
id: str id: str
user: str user: str
title: str title: str
wallet: str
animation1: str animation1: str
animation2: str animation2: str
animation3: str animation3: str
@@ -28,3 +32,8 @@ class Copilots(NamedTuple):
@classmethod @classmethod
def from_row(cls, row: Row) -> "Copilots": def from_row(cls, row: Row) -> "Copilots":
return cls(**dict(row)) return cls(**dict(row))
@property
def lnurl(self) -> Lnurl:
url = url_for("copilots.lnurl_response", ls_id=self.id, _external=True)
return lnurl_encode(url)

View File

@@ -147,6 +147,14 @@
type="text" type="text"
label="Title" label="Title"
></q-input> ></q-input>
<q-select
filled
dense
emit-value
v-model="formDialogCopilot.data.wallet"
:options="g.user.walletOptions"
label="Wallet *"
></q-select>
<q-expansion-item <q-expansion-item
group="api" group="api"
@@ -182,7 +190,7 @@
filled filled
dense dense
v-model.trim="formDialogCopilot.data.animation1webhook" v-model.trim="formDialogCopilot.data.animation1webhook"
type="number" type="text"
label="Webhook" label="Webhook"
> >
</q-input> </q-input>
@@ -218,6 +226,7 @@
v-model.trim="formDialogCopilot.data.animation2threshold" v-model.trim="formDialogCopilot.data.animation2threshold"
type="number" type="number"
label="From *sats" label="From *sats"
:rules="[ val <= formDialogCopilot.data.animation1threshold || 'Must be higher than last']"
> >
</q-input> </q-input>
</div> </div>
@@ -226,7 +235,7 @@
filled filled
dense dense
v-model.trim="formDialogCopilot.data.animation2webhook" v-model.trim="formDialogCopilot.data.animation2webhook"
type="number" type="text"
label="Webhook" label="Webhook"
> >
</q-input> </q-input>
@@ -262,6 +271,7 @@
v-model.trim="formDialogCopilot.data.animation3threshold" v-model.trim="formDialogCopilot.data.animation3threshold"
type="number" type="number"
label="From *sats" label="From *sats"
:rules="[ val <= formDialogCopilot.data.animation2threshold || 'Must be higher than last']"
> >
</q-input> </q-input>
</div> </div>
@@ -270,7 +280,7 @@
filled filled
dense dense
v-model.trim="formDialogCopilot.data.animation3webhook" v-model.trim="formDialogCopilot.data.animation3webhook"
type="number" type="text"
label="Webhook" label="Webhook"
> >
</q-input> </q-input>
@@ -409,20 +419,14 @@
data: { data: {
show_message: false, show_message: false,
show_ack: true, show_ack: true,
title: '', title: ''
animation1threshold: 0,
animation2threshold: 0,
animation3threshold: 0,
animation1webhook: '',
animation2webhook: '',
animation3webhook: ''
} }
}, },
qrCodeDialog: { qrCodeDialog: {
show: false, show: false,
data: null data: null
}, },
options: ['moon_rocket', 'confetti', 'roller_coaster'] options: ['bitcoin', 'confetti', 'rocket', 'face', 'martijn', 'rick']
} }
}, },
methods: { methods: {
@@ -437,19 +441,15 @@
}, },
sendFormDataCopilot: function () { sendFormDataCopilot: function () {
var self = this var self = this
var wallet = this.g.user.wallets[0].adminkey console.log(self.formDialogCopilot.data.animation1threshold)
var data = this.formDialogCopilot.data this.createCopilot(
console.log(data) self.g.user.wallets[0].adminkey,
data.animation1threshold = parseInt(data.animation1threshold) self.formDialogCopilot.data
data.animation1threshold = parseInt(data.animation2threshold) )
data.animation1threshold = parseInt(data.animation3threshold)
this.createCopilot(wallet, data)
}, },
createCopilot: function (wallet, data) { createCopilot: function (wallet, data) {
var self = this var self = this
LNbits.api LNbits.api
.request('POST', '/copilot/api/v1/copilot', wallet, data) .request('POST', '/copilot/api/v1/copilot', wallet, data)
.then(function (response) { .then(function (response) {

View File

@@ -24,12 +24,13 @@ from .crud import (
@api_validate_post_request( @api_validate_post_request(
schema={ schema={
"title": {"type": "string", "empty": False, "required": True}, "title": {"type": "string", "empty": False, "required": True},
"wallet": {"type": "string", "empty": False, "required": True},
"animation1": {"type": "string", "required": False}, "animation1": {"type": "string", "required": False},
"animation2": {"type": "string", "required": False}, "animation2": {"type": "string", "required": False},
"animation3": {"type": "string", "required": False}, "animation3": {"type": "string", "required": False},
"animation1threshold": {"type": "integer", "required": False}, "animation1threshold": {"type": "string", "required": False},
"animation2threshold": {"type": "integer", "required": False}, "animation2threshold": {"type": "string", "required": False},
"animation3threshold": {"type": "integer", "required": False}, "animation3threshold": {"type": "string", "required": False},
"animation1webhook": {"type": "string", "required": False}, "animation1webhook": {"type": "string", "required": False},
"animation2webhook": {"type": "string", "required": False}, "animation2webhook": {"type": "string", "required": False},
"animation3webhook": {"type": "string", "required": False}, "animation3webhook": {"type": "string", "required": False},