Should be working

Need to check lnurl logic, and debug
This commit is contained in:
Ben Arc 2021-04-15 09:39:27 +01:00
parent 34d659f9f3
commit 1af84b2b3d
8 changed files with 227 additions and 260 deletions

View file

@ -15,7 +15,8 @@ from quart import jsonify
async def create_copilot( async def create_copilot(
title: str, title: str,
user: str, user: str,
wallet: str, lnurl_toggle: str,
wallet: Optional[str] = None,
animation1: Optional[str] = None, animation1: Optional[str] = None,
animation2: Optional[str] = None, animation2: Optional[str] = None,
animation3: Optional[str] = None, animation3: Optional[str] = None,
@ -37,6 +38,7 @@ async def create_copilot(
INSERT INTO copilots ( INSERT INTO copilots (
id, id,
user, user,
lnurl_toggle,
wallet, wallet,
title, title,
animation1, animation1,
@ -54,11 +56,12 @@ async def create_copilot(
lnurl_title, lnurl_title,
amount_made amount_made
) )
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""", """,
( (
copilot_id, copilot_id,
user, user,
lnurl_toggle,
wallet, wallet,
title, title,
animation1, animation1,

View file

@ -67,6 +67,7 @@ async def lnurl_callback(cp_id):
wallet_id=cp.wallet, wallet_id=cp.wallet,
amount=int(amount_received / 1000), amount=int(amount_received / 1000),
memo=cp.lnurl_title, memo=cp.lnurl_title,
webhook="/copilot/api/v1/copilot/hook/" + cp_id,
description_hash=hashlib.sha256( description_hash=hashlib.sha256(
(cp.lnurl_title).encode("utf-8") (cp.lnurl_title).encode("utf-8")
).digest(), ).digest(),
@ -83,8 +84,5 @@ async def lnurl_callback(cp_id):
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,
lnurl_toggle INTEGER,
wallet TEXT, wallet TEXT,
animation1 TEXT, animation1 TEXT,
animation2 TEXT, animation2 TEXT,

View file

@ -10,6 +10,7 @@ class Copilots(NamedTuple):
id: str id: str
user: str user: str
title: str title: str
lnurl_toggle: str
wallet: str wallet: str
animation1: str animation1: str
animation2: str animation2: str

View file

@ -16,6 +16,7 @@
<img src="" style="width: 100%" id="animations" class="fixed-bottom-left" /> <img src="" style="width: 100%" id="animations" class="fixed-bottom-left" />
<qrcode <qrcode
v-if="'{{ lnurl_toggle }}' == 'True'"
style="width: 20%; z-index: 9999" style="width: 20%; z-index: 9999"
:value="'{{ lnurl }}'" :value="'{{ lnurl }}'"
:options="{width:222}" :options="{width:222}"
@ -79,80 +80,6 @@
self.connection.send('') self.connection.send('')
}, 1000) }, 1000)
}, 2000) }, 2000)
},
reconnect: function () {
this.connection.addEventListener('open', function (event) {
this.connection.send('')
})
this.connection.addEventListener('message', function (event) {
res = event.data.split('-')
console.log(res[1])
if (res[0] != this.oldRes) {
this.oldRes = res[0]
if (res[1] == 'rocket') {
document.getElementById('animations').style.width = '50%'
document.getElementById('animations').src =
'/copilot/static/rocket.gif'
setTimeout(function () {
document.getElementById('animations').src = ''
}, 5000)
}
if (res[1] == 'face') {
document.getElementById('animations').style.width = '50%'
document.getElementById('animations').src =
'/copilot/static/face.gif'
setTimeout(function () {
document.getElementById('animations').src = ''
}, 5000)
}
if (res[1] == 'bitcoin') {
document.getElementById('animations').style.width = '30%'
document.getElementById('animations').src =
'/copilot/static/bitcoin.gif'
setTimeout(function () {
document.getElementById('animations').src = ''
}, 5000)
}
if (res[1] == 'confetti') {
document.getElementById('animations').style.width = '100%'
document.getElementById('animations').src =
'/copilot/static/confetti.gif'
setTimeout(function () {
document.getElementById('animations').src = ''
}, 5000)
}
if (res[1] == 'martijn') {
document.getElementById('animations').style.width = '50%'
document.getElementById('animations').src =
'/copilot/static/martijn.gif'
setTimeout(function () {
document.getElementById('animations').src = ''
}, 5000)
}
if (res[1] == 'rick') {
document.getElementById('animations').style.width = '50%'
document.getElementById('animations').src =
'/copilot/static/rick.gif'
setTimeout(function () {
document.getElementById('animations').src = ''
}, 5000)
}
if (res[1] == 'true') {
document.getElementById('videoElement').style.width = '20%'
}
if (res[1] == 'false') {
document.getElementById('videoElement').style.width = '100%'
}
if (res[1].substring(0, 3) == 'htt') {
document.getElementById('iframe_main').src = res[1]
}
}
})
this.connection.addEventListener('close', function (event) {
console.log('The connection has been closed')
})
} }
}, },
mounted() { mounted() {

View file

@ -49,8 +49,9 @@
> >
<template v-slot:header="props"> <template v-slot:header="props">
<q-tr :props="props"> <q-tr :props="props">
<q-th auto-width></q-th> <q-th style="width: 5%"></q-th>
<q-th auto-width></q-th> <q-th style="width: 5%"></q-th>
<q-th style="width: 5%"></q-th>
<q-th <q-th
v-for="col in props.cols" v-for="col in props.cols"
@ -147,178 +148,183 @@
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
group="api"
dense
expand-separator
label="Payment threshold 1"
>
<q-card>
<q-card-section>
<div class="row">
<div class="col">
<q-select
filled
dense
v-model.trim="formDialogCopilot.data.animation1"
:options="options"
label="Animation"
/>
</div>
<div class="col q-pl-xs">
<q-input
filled
dense
v-model.trim="formDialogCopilot.data.animation1threshold"
type="number"
label="From *sats"
>
</q-input>
</div>
<div class="col q-pl-xs">
<q-input
filled
dense
v-model.trim="formDialogCopilot.data.animation1webhook"
type="text"
label="Webhook"
>
</q-input>
</div>
</div>
</q-card-section>
</q-card>
</q-expansion-item>
<q-expansion-item
group="api"
dense
expand-separator
label="Payment threshold 2"
>
<q-card>
<q-card-section>
<div class="row">
<div class="col">
<q-select
filled
dense
v-model.trim="formDialogCopilot.data.animation2"
:options="options"
label="Animation"
/>
</div>
<div class="col q-pl-xs">
<q-input
filled
dense
v-model.trim="formDialogCopilot.data.animation2threshold"
type="number"
label="From *sats"
:rules="[ val <= formDialogCopilot.data.animation1threshold || 'Must be higher than last']"
>
</q-input>
</div>
<div class="col q-pl-xs">
<q-input
filled
dense
v-model.trim="formDialogCopilot.data.animation2webhook"
type="text"
label="Webhook"
>
</q-input>
</div>
</div>
</q-card-section>
</q-card>
</q-expansion-item>
<q-expansion-item
group="api"
dense
expand-separator
label="Payment threshold 3"
>
<q-card>
<q-card-section>
<div class="row">
<div class="col">
<q-select
filled
dense
v-model.trim="formDialogCopilot.data.animation3"
:options="options"
label="Animation"
/>
</div>
<div class="col q-pl-xs">
<q-input
filled
dense
v-model.trim="formDialogCopilot.data.animation3threshold"
type="number"
label="From *sats"
:rules="[ val <= formDialogCopilot.data.animation2threshold || 'Must be higher than last']"
>
</q-input>
</div>
<div class="col q-pl-xs">
<q-input
filled
dense
v-model.trim="formDialogCopilot.data.animation3webhook"
type="text"
label="Webhook"
>
</q-input>
</div>
</div>
</q-card-section>
</q-card>
</q-expansion-item>
<q-input
filled
dense
v-model.trim="formDialogCopilot.data.lnurl_title"
type="text"
max="1440"
label="Lnurl title (message with QR code)"
>
</q-input>
<div class="row"> <div class="row">
<div class="col"> <q-checkbox
<div class="q-gutter-sm"> v-model="formDialogCopilot.data.lnurl_toggle"
<q-checkbox label="Include lnurl payment QR? (requires https)"
v-model="formDialogCopilot.data.show_message" left-label
left-label ></q-checkbox>
label="Show lnurl-pay messages?" </div>
/> <div v-if="formDialogCopilot.data.lnurl_toggle">
</div> <q-select
</div> filled
dense
emit-value
v-model="formDialogCopilot.data.wallet"
:options="g.user.walletOptions"
label="Wallet *"
></q-select>
<div class="col q-pl-xs"> <q-expansion-item
<div class="q-gutter-sm"> group="api"
<q-checkbox dense
v-model="formDialogCopilot.data.show_ack" expand-separator
left-label label="Payment threshold 1"
label="Show 'powered by LNbits'" >
/> <q-card>
</div> <q-card-section>
<div class="row">
<div class="col">
<q-select
filled
dense
v-model.trim="formDialogCopilot.data.animation1"
:options="options"
label="Animation"
/>
</div>
<div class="col q-pl-xs">
<q-input
filled
dense
v-model.trim="formDialogCopilot.data.animation1threshold"
type="number"
label="From *sats"
:min="10"
>
</q-input>
</div>
<div class="col q-pl-xs">
<q-input
filled
dense
v-model.trim="formDialogCopilot.data.animation1webhook"
type="text"
label="Webhook"
>
</q-input>
</div>
</div>
</q-card-section>
</q-card>
</q-expansion-item>
<q-expansion-item
group="api"
dense
expand-separator
label="Payment threshold 2 (Must be higher than last)"
>
<q-card>
<q-card-section>
<div class="row">
<div class="col">
<q-select
filled
dense
v-model.trim="formDialogCopilot.data.animation2"
:options="options"
label="Animation"
/>
</div>
<div class="col q-pl-xs">
<q-input
filled
dense
v-model="formDialogCopilot.data.animation2threshold"
type="number"
label="From *sats"
:min="formDialogCopilot.data.animation1threshold"
>
</q-input>
</div>
<div class="col q-pl-xs">
<q-input
filled
dense
v-model.trim="formDialogCopilot.data.animation2webhook"
type="text"
label="Webhook"
>
</q-input>
</div>
</div>
</q-card-section>
</q-card>
</q-expansion-item>
<q-expansion-item
group="api"
dense
expand-separator
label="Payment threshold 3 (Must be higher than last)"
>
<q-card>
<q-card-section>
<div class="row">
<div class="col">
<q-select
filled
dense
v-model.trim="formDialogCopilot.data.animation3"
:options="options"
label="Animation"
/>
</div>
<div class="col q-pl-xs">
<q-input
filled
dense
v-model="formDialogCopilot.data.animation3threshold"
type="number"
label="From *sats"
:min="formDialogCopilot.data.animation2threshold"
>
</q-input>
</div>
<div class="col q-pl-xs">
<q-input
filled
dense
v-model.trim="formDialogCopilot.data.animation3webhook"
type="text"
label="Webhook"
>
</q-input>
</div>
</div>
</q-card-section>
</q-card>
</q-expansion-item>
<q-input
filled
dense
v-model.trim="formDialogCopilot.data.lnurl_title"
type="text"
max="1440"
label="Lnurl title (message with QR code)"
>
</q-input>
<div class="q-gutter-sm">
<q-checkbox
v-model="formDialogCopilot.data.show_message"
left-label
label="Show lnurl-pay messages?"
></q-checkbox>
</div>
</div>
<div class="q-gutter-sm">
<div class="row">
<q-checkbox
v-model="formDialogCopilot.data.show_ack"
left-label
label="Show 'powered by LNbits'"
></q-checkbox>
</div> </div>
</div> </div>
@ -393,6 +399,12 @@
label: 'id', label: 'id',
field: 'id' field: 'id'
}, },
{
name: 'lnurl_toggle',
align: 'left',
label: 'Show lnurl pay link',
field: 'lnurl_toggle'
},
{ {
name: 'title', name: 'title',
align: 'left', align: 'left',
@ -417,6 +429,7 @@
formDialogCopilot: { formDialogCopilot: {
show: false, show: false,
data: { data: {
lnurl_toggle: false,
show_message: false, show_message: false,
show_ack: true, show_ack: true,
title: '' title: ''

View file

@ -40,7 +40,9 @@ async def compose(copilot_id):
copilot = await get_copilot(copilot_id) or abort( copilot = await get_copilot(copilot_id) or abort(
HTTPStatus.NOT_FOUND, "Copilot link does not exist." HTTPStatus.NOT_FOUND, "Copilot link does not exist."
) )
return await render_template("copilot/compose.html", copilot=copilot, lnurl=copilot.lnurl) if copilot.lnurl_toggle:
return await render_template("copilot/compose.html", copilot=copilot, lnurl=copilot.lnurl, lnurl_toggle=copilot.lnurl_toggle)
return await render_template("copilot/compose.html", copilot=copilot, lnurl_toggle=copilot.lnurl_toggle)
@copilot_ext.route("/<copilot_id>") @copilot_ext.route("/<copilot_id>")
async def panel(copilot_id): async def panel(copilot_id):

View file

@ -1,5 +1,5 @@
import hashlib import hashlib
from quart import g, jsonify, url_for from quart import g, jsonify, url_for, websocket
from http import HTTPStatus from http import HTTPStatus
import httpx import httpx
@ -26,18 +26,19 @@ 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}, "lnurl_toggle": {"type": "integer", "empty": False, "required": True},
"wallet": {"type": "string", "empty": False, "required": False},
"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": "string", "required": False}, "animation1threshold": {"type": "integer", "required": False},
"animation2threshold": {"type": "string", "required": False}, "animation2threshold": {"type": "integer", "required": False},
"animation3threshold": {"type": "string", "required": False}, "animation3threshold": {"type": "integer", "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},
"lnurl_title": {"type": "string", "empty": False, "required": True}, "lnurl_title": {"type": "string", "empty": False, "required": False},
"show_message": {"type": "integer", "empty": False, "required": True}, "show_message": {"type": "integer", "empty": False, "required": False},
"show_ack": {"type": "integer", "empty": False, "required": True}, "show_ack": {"type": "integer", "empty": False, "required": True},
} }
) )
@ -96,4 +97,25 @@ async def api_copilot_delete(copilot_id):
await delete_copilot(copilot_id) await delete_copilot(copilot_id)
return "", HTTPStatus.NO_CONTENT return "", HTTPStatus.NO_CONTENT
#############################PAYMENTHOOK##########################
@copilot_ext.route("/api/v1/copilot/hook/<copilot_id>", methods=["POST"])
async def api_copilot_delete(copilot_id, trigger):
copilot = await get_copilot(copilot_id)
if not copilot:
return jsonify({"message": "Copilot link link does not exist."}), HTTPStatus.NOT_FOUND
socket_sendererer = app.socket_sendererer()
if copilot.animation1threshold and g.data['amount'] > copilot.animation1threshold:
data = copilot.animation1
if copilot.animation2threshold and g.data['amount'] > copilot.animation2threshold:
data = copilot.animation2
if copilot.animation3threshold and g.data['amount'] > copilot.animation3threshold:
data = copilot.animation3
async with socket_sendererer.websocket('/ws/compose/' + copilot_id) as the_websocket:
await the_websocket.send(data)
return "", HTTPStatus.OK