Satspay mostly working

This commit is contained in:
Ben Arc
2021-04-07 01:50:38 +01:00
parent f5d06653a6
commit 90319bfd8c
8 changed files with 342 additions and 237 deletions

View File

@@ -11,7 +11,6 @@ import httpx
from lnbits.core.services import create_invoice, check_invoice_status from lnbits.core.services import create_invoice, check_invoice_status
from ..watchonly.crud import get_watch_wallet, get_derive_address, get_mempool from ..watchonly.crud import get_watch_wallet, get_derive_address, get_mempool
import time
###############CHARGES########################## ###############CHARGES##########################
@@ -45,13 +44,12 @@ async def create_charge(user: str, description: Optional[str] = None, onchainwal
webhook, webhook,
time, time,
amount, amount,
balance, balance
paid
) )
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""", """,
(charge_id, user, description, onchainwallet, onchainaddress, lnbitswallet, (charge_id, user, description, onchainwallet, onchainaddress, lnbitswallet,
payment_request, payment_hash, webhook, time, amount, 0, False), payment_request, payment_hash, webhook, time, amount, 0),
) )
return await get_charge(charge_id) return await get_charge(charge_id)
@@ -79,21 +77,24 @@ async def delete_charge(charge_id: str) -> None:
async def check_address_balance(charge_id: str) -> List[Charges]: async def check_address_balance(charge_id: str) -> List[Charges]:
charge = await get_charge(charge_id) charge = await get_charge(charge_id)
if charge.onchainaddress: print(charge.balance)
mempool = await get_mempool(charge.user) if not charge.paid:
try: if charge.onchainaddress:
async with httpx.AsyncClient() as client: mempool = await get_mempool(charge.user)
r = await client.get(mempool.endpoint + "/api/address/" + charge.onchainaddress) try:
respAmount = r.json()['chain_stats']['funded_txo_sum'] async with httpx.AsyncClient() as client:
if (charge.balance + respAmount) >= charge.balance: r = await client.get(mempool.endpoint + "/api/address/" + charge.onchainaddress)
return await update_charge(charge_id=charge_id, balance=(charge.balance + respAmount), paid=True) respAmount = r.json()['chain_stats']['funded_txo_sum']
else: print(respAmount)
return await update_charge(charge_id=charge_id, balance=(charge.balance + respAmount), paid=False) if respAmount >= charge.balance:
except Exception: await update_charge(charge_id=charge_id, balance=respAmount)
pass except Exception:
if charge.lnbitswallet: pass
invoice_status = await check_invoice_status(charge.lnbitswallet, charge.payment_hash) if charge.lnbitswallet:
if invoice_status.paid: invoice_status = await check_invoice_status(charge.lnbitswallet, charge.payment_hash)
return await update_charge(charge_id=charge_id, balance=charge.balance, paid=True) print(invoice_status)
if invoice_status.paid:
print("paid")
return await update_charge(charge_id=charge_id, balance=charge.amount)
row = await db.fetchone("SELECT * FROM charges WHERE id = ?", (charge_id,)) row = await db.fetchone("SELECT * FROM charges WHERE id = ?", (charge_id,))
return Charges.from_row(row) if row else None return Charges.from_row(row) if row else None

View File

@@ -3,7 +3,6 @@ async def m001_initial(db):
Initial wallet table. Initial wallet table.
""" """
await db.execute( await db.execute(
""" """
CREATE TABLE IF NOT EXISTS charges ( CREATE TABLE IF NOT EXISTS charges (
@@ -19,7 +18,6 @@ async def m001_initial(db):
time INTEGER, time INTEGER,
amount INTEGER, amount INTEGER,
balance INTEGER DEFAULT 0, balance INTEGER DEFAULT 0,
paid BOOLEAN,
timestamp TIMESTAMP NOT NULL DEFAULT (strftime('%s', 'now')) timestamp TIMESTAMP NOT NULL DEFAULT (strftime('%s', 'now'))
); );
""" """

View File

@@ -1,5 +1,6 @@
from sqlite3 import Row from sqlite3 import Row
from typing import NamedTuple from typing import NamedTuple
import time
class Charges(NamedTuple): class Charges(NamedTuple):
@@ -12,12 +13,25 @@ class Charges(NamedTuple):
payment_request: str payment_request: str
payment_hash: str payment_hash: str
webhook: str webhook: str
time: str time: int
amount: int amount: int
balance: int balance: int
paid: bool
timestamp: int timestamp: int
@classmethod @classmethod
def from_row(cls, row: Row) -> "Charges": def from_row(cls, row: Row) -> "Charges":
return cls(**dict(row)) return cls(**dict(row))
@property
def time_elapsed(self):
if (self.timestamp + (self.time * 60)) >= time.time():
return False
else:
return True
@property
def paid(self):
if self.balance >= self.amount:
return True
else:
return False

View File

@@ -117,80 +117,6 @@
</q-card-section> </q-card-section>
</q-card> </q-card>
</q-expansion-item> </q-expansion-item>
<q-expansion-item
group="api"
dense
expand-separator
label="Create a charge link"
>
<q-card>
<q-card-section>
<code><span class="text-green">POST</span> /pay/api/v1/links</code>
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
<code>{"X-Api-Key": &lt;invoice_key&gt;}</code><br />
<h5 class="text-caption q-mt-sm q-mb-none">
Body (application/json)
</h5>
<code>{"description": &lt;string&gt; "amount": &lt;integer&gt;}</code>
<h5 class="text-caption q-mt-sm q-mb-none">
Returns 201 CREATED (application/json)
</h5>
<code>
{ "deliveryId": &lt;string&gt;, "description": &lt;string&gt;,
"webhookId": &lt;string&gt;, "originalDeliveryId": &lt;string&gt;,
"isRedelivery": &lt;boolean&gt;, "type": &lt;string&gt;,
"timestamp": &lt;int&gt;, "paytime": &lt;int&gt;, "storeId":
&lt;string&gt;, "invoiceId": &lt;string&gt;, "manuallyMarked":
&lt;boolean&gt;, "overPaid": &lt;boolean&gt;, "afterExpiration":
&lt;boolean&gt;, "partiallyPaid": &lt;boolean&gt; }<br /><small
>"type" can be InvoiceReceivedPayment, InvoicePaidInFull,
InvoiceExpired, InvoiceConfirmed, and InvoiceInvalid</small
>
</code>
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
<code
>curl -X POST {{ request.url_root }}pay/api/v1/links -d
'{"description": &lt;string&gt;, "amount": &lt;integer&gt;}' -H
"Content-type: application/json" -H "X-Api-Key: {{
g.user.wallets[0].adminkey }}"
</code>
</q-card-section>
</q-card>
</q-expansion-item>
<q-expansion-item
group="api"
dense
expand-separator
label="Update a pay link"
>
<q-card>
<q-card-section>
<code
><span class="text-green">PUT</span>
/pay/api/v1/links/&lt;pay_id&gt;</code
>
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
<code>{"X-Api-Key": &lt;admin_key&gt;}</code><br />
<h5 class="text-caption q-mt-sm q-mb-none">
Body (application/json)
</h5>
<code
>{"description": &lt;string&gt;, "amount": &lt;integer&gt;}</code
>
<h5 class="text-caption q-mt-sm q-mb-none">
Returns 200 OK (application/json)
</h5>
<code>{"lnurl": &lt;string&gt;}</code>
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
<code
>curl -X PUT {{ request.url_root }}pay/api/v1/links/&lt;pay_id&gt;
-d '{"description": &lt;string&gt;, "amount": &lt;integer&gt;}' -H
"Content-type: application/json" -H "X-Api-Key: {{
g.user.wallets[0].adminkey }}"
</code>
</q-card-section>
</q-card>
</q-expansion-item>
<q-expansion-item <q-expansion-item
group="api" group="api"
dense dense
@@ -202,7 +128,7 @@
<q-card-section> <q-card-section>
<code <code
><span class="text-pink">DELETE</span> ><span class="text-pink">DELETE</span>
/pay/api/v1/links/&lt;pay_id&gt;</code /satspay/api/v1/charge/&lt;charge_id&gt;</code
> >
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5> <h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
<code>{"X-Api-Key": &lt;admin_key&gt;}</code><br /> <code>{"X-Api-Key": &lt;admin_key&gt;}</code><br />
@@ -211,11 +137,36 @@
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5> <h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
<code <code
>curl -X DELETE {{ request.url_root >curl -X DELETE {{ request.url_root
}}pay/api/v1/links/&lt;pay_id&gt; -H "X-Api-Key: {{ }}api/v1/charge/&lt;charge_id&gt; -H "X-Api-Key: {{
g.user.wallets[0].adminkey }}" g.user.wallets[0].adminkey }}"
</code> </code>
</q-card-section> </q-card-section>
</q-card> </q-card>
</q-expansion-item> </q-expansion-item>
<q-expansion-item group="api" dense expand-separator label="Get balances">
<q-card>
<q-card-section>
<code
><span class="text-blue">GET</span>
/satspay/api/v1/charges/balance/&lt;charge_id&gt;</code
>
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
<code>{"X-Api-Key": &lt;admin_key&gt;}</code><br />
<h5 class="text-caption q-mt-sm q-mb-none">
Body (application/json)
</h5>
<h5 class="text-caption q-mt-sm q-mb-none">
Returns 200 OK (application/json)
</h5>
<code>[&lt;charge_object&gt;, ...]</code>
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
<code
>curl -X GET {{ request.url_root
}}api/v1/charges/balance/&lt;charge_id&gt; -H "X-Api-Key: {{
g.user.wallets[0].inkey }}"
</code>
</q-card-section>
</q-card>
</q-expansion-item>
</q-expansion-item> </q-expansion-item>
</q-card> </q-card>

View File

@@ -1,74 +1,241 @@
{% extends "public.html" %} {% block page %} {% extends "public.html" %} {% block page %}
<div class="q-pa-sm theCard">
<div class="q-pa-md">
<q-card class="my-card"> <q-card class="my-card">
<q-card-section> <div class="column">
<div class="text-h6">Our Changing Planet</div> <center> <div class="col theHeading">{{ charge.description }}</div></center>
<div class="text-subtitle2">by John Doe</div>
</q-card-section>
<q-tabs v-model="tab" class="text-teal"> <div class="col">
<q-tab label="Tab one" name="one" /> <div class="col" color="white" style="background-color:grey; height: 30px; padding: 5px" v-if="charge_time_elapsed == 'True'">
<q-tab label="Tab two" name="two" /> <center>Time elapsed</center>
</q-tabs> </div>
<div class="col" color="white" style="background-color:grey; height: 30px; padding: 5px" v-else-if="charge_paid == 'True'">
<center>Charge paid</center>
</div>
<div v-else>
<q-linear-progress size="30px" :value="newProgress" color="grey" >
<q-separator /> <q-item-section>
<q-item style="padding: 3px">
<q-spinner color="white" size="0.8em" ></q-spinner
><span style="font-size: 15px; color:white"><span class="q-pr-xl q-pl-md"> Awaiting payment...</span>
<span class="q-pl-xl" style="color:white"> {% raw %} {{ newTimeLeft }} {% endraw %}</span></span>
</q-item-section>
</q-item>
</q-linear-progress>
</div>
</div>
<q-tab-panels v-model="tab" animated>
<q-tab-panel name="Lightning"> <div class="col" style="margin: 2px 15px; max-height:100px" >
<div class="text-center"> <center>
<a href="lightning:{{ charge.id }}"> <q-btn flat dense outline @click="copyText('{{ charge.id }}')"
>Charge ID: {{ charge.id }}</q-btn
>
</center>
<span><small>{% raw %}
Total to pay: {{ charge_amount }}sats<br/>
Amount paid: {{ charge_balance }}</small><br/>
Amount due: {{ charge_amount - charge_balance }}sats
{% endraw %}
</span>
</div>
<q-separator></q-separator>
<div class="col">
<div class="row">
<div class="col">
<q-btn flat disable v-if="'{{ charge.lnbitswallet }}' == 'None' || charge_time_elapsed == 'True'" style="color: primary; width: 100%" label="lightning⚡" >
<q-tooltip>
bitcoin onchain payment method not available
</q-tooltip>
</q-btn>
<q-btn flat v-else @click="payLN" style="color: primary; width: 100%" label="lightning⚡" >
<q-tooltip>
pay with lightning
</q-tooltip>
</q-btn>
</div>
<div class="col">
<q-btn flat disable v-if="'{{ charge.onchainwallet }}' == 'None' || charge_time_elapsed == 'True'" style="color: primary; width: 100%" label="onchain⛓" >
<q-tooltip>
bitcoin lightning payment method not available
</q-tooltip>
</q-btn>
<q-btn flat v-else @click="payON" style="color: primary; width: 100%" label="onchain⛓" >
<q-tooltip>
pay onchain
</q-tooltip>
</q-btn>
</div>
</div>
<q-separator></q-separator>
</div>
</div>
<q-card class="q-pa-lg" v-if="lnbtc">
<q-card-section class="q-pa-none">
<div class="text-center q-pt-md">
<div v-if="charge_time_elapsed == 'True' && charge_paid == 'False'">
<q-icon name="block" style="color: #ccc; font-size: 21.4em;" ></q-icon>
</div>
<div v-else-if="charge_paid == 'True'">
<q-icon name="check" style="color:green; font-size: 21.4em;" ></q-icon>
</div>
<div v-else>
<center>
<span class="text-subtitle2">Pay this <br/> lightning-network invoice</span>
</center>
<a href="lightning://{{ charge.payment_request }}">
<q-responsive :ratio="1" class="q-mx-md"> <q-responsive :ratio="1" class="q-mx-md">
<qrcode <qrcode
value="{{ charge.id }}" :value="'{{ charge.payment_request }}'"
:options="{width: 300}" :options="{width: 800}"
class="rounded-borders" class="rounded-borders"
></qrcode> ></qrcode>
</q-responsive> </q-responsive>
</a> </a>
</div>
<div class="row q-mt-lg"> <div class="row q-mt-lg">
<q-btn outline color="grey" @click="copyText('{{ charge.id }}')" <q-btn outline color="grey" @click="copyText('{{ charge.payment_request }}')"
>Copy address</q-btn >Copy invoice</q-btn
> >
</div> </div>
</q-tab-panel> </div></div>
</q-card-section>
</q-card>
<q-tab-panel name="Onchain">
<div class="text-center"> <q-card class="q-pa-lg" v-if="onbtc">
<a href="lightning:{{ charge.id }}"> <q-card-section class="q-pa-none">
<div class="text-center q-pt-md">
<div v-if="charge_time_elapsed == 'True' && charge_paid == 'False'">
<q-icon name="block" style="color: #ccc; font-size: 21.4em;" ></q-icon>
</div>
<div v-else-if="charge_paid == 'True'">
<q-icon name="check" style="color:green; font-size: 21.4em;" ></q-icon>
</div>
<div v-else>
<center>
<span class="text-subtitle2">Send {{ charge.amount }}sats<br/> to this onchain address</span>
</center>
<a href="bitcoin://{{ charge.onchainaddress }}">
<q-responsive :ratio="1" class="q-mx-md"> <q-responsive :ratio="1" class="q-mx-md">
<qrcode <qrcode
value="{{ charge.id }}" :value="'{{ charge.onchainaddress }}'"
:options="{width: 300}" :options="{width: 800}"
class="rounded-borders" class="rounded-borders"
></qrcode> ></qrcode>
</q-responsive> </q-responsive>
</a> </a>
</div>
<div class="row q-mt-lg"> <div class="row q-mt-lg">
<q-btn outline color="grey" @click="copyText('{{ charge.id }}')" <q-btn outline color="grey" @click="copyText('{{ charge.onchainaddress }}')"
>Copy address</q-btn >Copy address</q-btn
> >
</div> </div>
</q-tab-panel> </div></div>
</q-tab-panels> </q-card-section>
</q-card>
</q-card> </q-card>
</div> </div>
{% endblock %} {% block scripts %} {% endblock %} {% block scripts %}
<script src="{{ url_for('static', filename='vendor/vue-qrcode@1.0.2/vue-qrcode.min.js') }}"></script> <script src="{{ url_for('static', filename='vendor/vue-qrcode@1.0.2/vue-qrcode.min.js') }}"></script>
<style>
.theCard {
width: 360px;
margin: 10px auto;
}
.theHeading {
margin: 15px;
font-size: 25px;
}
</style>
<script> <script>
Vue.component(VueQrcode.name, VueQrcode) Vue.component(VueQrcode.name, VueQrcode)
new Vue({ new Vue({
el: '#vue', el: '#vue',
mixins: [windowMixin] mixins: [windowMixin],
data() {
return {
newProgress: 0.4,
counter: 1,
newTimeLeft: '',
lnbtc: true,
onbtc: false,
charge_time_elapsed: '{{charge.time_elapsed}}',
charge_amount: '{{charge.amount}}',
charge_balance: '{{charge.balance}}',
charge_paid: '{{charge.paid}}'
}
},
methods: {
checkBalance: function () {
var self = this
LNbits.api
.request(
'GET',
'/satspay/api/v1/charges/balance/{{ charge.id }}',
"filla"
)
.then(function (response) {
console.log(response.data)
self.charge_time_elapsed = response.data.time_elapsed
self.charge_amount = response.data.amount
self.charge_balance = response.data.balance
if (self.charge_balance >= self.charge_amount ){
self.charge_paid = "True"
}
console.log(self.charge_paid)
})
.catch(function (error) {
LNbits.utils.notifyApiError(error)
})
},
payLN: function(){
this.lnbtc = true
this.onbtc = false
},
payON: function(){
this.lnbtc = false
this.onbtc = true
},
getTheTime: function () {
var timeToComplete = (parseInt('{{ charge.time }}') * 60) - (Date.now()/1000 - parseInt('{{ charge.timestamp }}') )
var timeLeft = Quasar.utils.date.formatDate(
new Date((timeToComplete - 3600)*1000),
'HH:mm:ss'
)
this.newTimeLeft = timeLeft
},
getThePercentage: function () {
var timeToComplete = (parseInt('{{ charge.time }}') * 60) - (Date.now()/1000 - parseInt('{{ charge.timestamp }}') )
this.newProgress = 1 - (timeToComplete / (parseInt('{{ charge.time }}') * 60))
},
timerCount: function () {
self = this
setInterval(function () {
self.getTheTime()
self.getThePercentage()
self.counter++
if (self.counter% 10 === 0){
self.checkBalance()
}
}, 1000)
}
},
created: function () {
this.getTheTime()
this.getThePercentage()
var timerCount = this.timerCount
console.log('{{ charge.paid }}')
if('{{ charge.paid }}' == 'False'){
timerCount()
}
}
}) })
</script> </script>
{% endblock %} {% endblock %}

View File

@@ -64,33 +64,53 @@
type="a" type="a"
:href="props.row.displayUrl" :href="props.row.displayUrl"
target="_blank" target="_blank"
></q-btn> >
<q-tooltip>
Payment link
</q-tooltip>
</q-btn>
</q-td> </q-td>
<q-td auto-width> <q-td auto-width>
<q-icon v-if="props.row.timeleft < 1 && props.row.amount_paid < props.row.amount" <q-btn v-if="props.row.time_elapsed && props.row.balance < props.row.amount"
#unelevated unelevated
flat
dense dense
size="xs" size="xs"
name="error" icon="error"
:color="($q.dark.isActive) ? 'red' : 'red'" :color="($q.dark.isActive) ? 'red' : 'red'"
></q-icon> >
<q-tooltip>
Time elapsed
</q-tooltip>
</q-btn>
<q-icon v-else-if="props.row.balance > props.row.amount" <q-btn v-else-if="props.row.balance >= props.row.amount"
#unelevated unelevated
flat
dense dense
size="xs" size="xs"
name="check" icon="check"
:color="($q.dark.isActive) ? 'green' : 'green'" :color="($q.dark.isActive) ? 'green' : 'green'"
></q-icon> >
<q-tooltip>
PAID!
</q-tooltip>
</q-btn>
<q-icon v-else="props.row.amount_paid < props.row.amount && props.row.timeleft > 1" <q-btn v-else
#unelevated unelevated
dense dense
size="xs" size="xs"
name="cached" icon="cached"
flat
@click="getBalance(props.row.id)"
:color="($q.dark.isActive) ? 'blue' : 'blue'" :color="($q.dark.isActive) ? 'blue' : 'blue'"
></q-icon> >
<q-tooltip>
Check balance
</q-tooltip>
</q-btn>
<q-btn <q-btn
flat flat
dense dense
@@ -175,7 +195,8 @@
dense dense
v-model.trim="formDialogCharge.data.time" v-model.trim="formDialogCharge.data.time"
type="number" type="number"
label="Time (secs)" max="1440"
label="Mins valid for (max 1440)"
> </q-input> > </q-input>
<q-input <q-input
@@ -281,26 +302,27 @@
) )
return obj return obj
} }
var mapCharge = function (obj) {
obj._data = _.clone(obj) var mapCharge = obj => {
obj.theDate = ( obj.time + obj.timestamp - ((Date.now()/1000))) obj._data = _.clone(obj)
console.log(obj.theDate) obj.theTime = (obj.time * 60) - (Date.now()/1000 - obj.timestamp)
if(obj.theDate < 0){ console.log(obj.theTime)
obj.time = obj.time + "mins"
if(obj.time_elapsed){
obj.date = "Time elapsed" obj.date = "Time elapsed"
} }
else{ else{
obj.date = Quasar.utils.date.formatDate( obj.date = Quasar.utils.date.formatDate(
new Date((obj.theTime - 3600)*1000),
new Date(obj.theDate * 1000),
'HH:mm:ss' 'HH:mm:ss'
) )}
}
obj.displayUrl = ['/satspay/', obj.id].join('') obj.displayUrl = ['/satspay/', obj.id].join('')
console.log(obj.date)
return obj return obj
} }
new Vue({ new Vue({
el: '#vue', el: '#vue',
mixins: [windowMixin], mixins: [windowMixin],
@@ -326,8 +348,8 @@
ChargesTable: { ChargesTable: {
columns: [ columns: [
{ {
name: 'id', name: 'theId',
align: 'left', align: 'left',
label: 'ID', label: 'ID',
field: 'id' field: 'id'
@@ -344,6 +366,12 @@
label: 'Time left', label: 'Time left',
field: 'date' field: 'date'
}, },
{
name: 'time to pay',
align: 'left',
label: 'Time to Pay',
field: 'time'
},
{ {
name: 'amount', name: 'amount',
align: 'left', align: 'left',
@@ -356,12 +384,6 @@
label: 'Balance', label: 'Balance',
field: 'balance' field: 'balance'
}, },
{
name: 'time to pay',
align: 'left',
label: 'Time to Pay',
field: 'time'
},
{ {
name: 'onchain address', name: 'onchain address',
align: 'left', align: 'left',
@@ -394,11 +416,6 @@
} }
}, },
methods: { methods: {
updateCountdowns: function () {
setInterval(function(){
}, 1000)
},
getWalletLinks: function () { getWalletLinks: function () {
var self = this var self = this
@@ -410,13 +427,9 @@
this.g.user.wallets[0].inkey this.g.user.wallets[0].inkey
) )
.then(function (response) { .then(function (response) {
console.log(response.data)
for (i = 0; i < response.data.length; i++) { for (i = 0; i < response.data.length; i++) {
self.walletLinks.push(response.data[i].id) self.walletLinks.push(response.data[i].id)
} }
console.log(self.walletLinks)
return return
}) })
.catch(function (error) { .catch(function (error) {
@@ -463,25 +476,8 @@
this.g.user.wallets[0].inkey this.g.user.wallets[0].inkey
) )
.then(function (response) { .then(function (response) {
console.log(response.data) console.log(response.data[0].time_elapsed)
var i self.ChargeLinks = response.data.map(mapCharge)
var now = parseInt(new Date() / 1000)
for (i = 0; i < response.data.length; i++) {
timeleft = response.data[i].time_to_pay - (now - response.data[i].time)
if (timeleft < 1) {
response.data[i].timeleft = 0
}
else{
response.data[i].timeleft = timeleft
}
}
self.ChargeLinks = response.data.map(function (obj) {
return mapCharge(obj)
})
}) })
.catch(function (error) { .catch(function (error) {
LNbits.utils.notifyApiError(error) LNbits.utils.notifyApiError(error)
@@ -491,7 +487,6 @@
var self = this var self = this
var wallet = self.g.user.wallets[0].adminkey var wallet = self.g.user.wallets[0].adminkey
var data = self.formDialogCharge.data var data = self.formDialogCharge.data
console.log(data)
data.amount = parseInt(data.amount) data.amount = parseInt(data.amount)
data.time = parseInt(data.time) data.time = parseInt(data.time)
if (data.id) { if (data.id) {
@@ -509,7 +504,7 @@
LNbits.api LNbits.api
.request( .request(
'PUT', 'PUT',
'/satspay/api/v1/Charge/' + data.id, '/satspay/api/v1/charge/' + data.id,
wallet.adminkey, data) wallet.adminkey, data)
.then(function (response) { .then(function (response) {
self.Charge = _.reject(self.Charge, function (obj) { self.Charge = _.reject(self.Charge, function (obj) {
@@ -531,7 +526,7 @@
this.g.user.wallets[0].inkey this.g.user.wallets[0].inkey
) )
.then(function (response) { .then(function (response) {
console.log(response.data) this.ChargeLinks = response.data.map(mapCharge)
}) })
.catch(function (error) { .catch(function (error) {
LNbits.utils.notifyApiError(error) LNbits.utils.notifyApiError(error)
@@ -556,14 +551,13 @@
deleteCharge: function (linkId) { deleteCharge: function (linkId) {
var self = this var self = this
var link = _.findWhere(this.Charge, {id: linkId}) var link = _.findWhere(this.Charge, {id: linkId})
console.log(self.g.user.wallets[0].adminkey)
LNbits.utils LNbits.utils
.confirmDialog('Are you sure you want to delete this pay link?') .confirmDialog('Are you sure you want to delete this pay link?')
.onOk(function () { .onOk(function () {
LNbits.api LNbits.api
.request( .request(
'DELETE', 'DELETE',
'/satspay/api/v1/Charge/' + linkId, '/satspay/api/v1/charge/' + linkId,
self.g.user.wallets[0].inkey self.g.user.wallets[0].inkey
) )
.then(function (response) { .then(function (response) {
@@ -603,7 +597,6 @@
.then(function (response) { .then(function (response) {
self.walletLinks.push(mapWalletLink(response.data)) self.walletLinks.push(mapWalletLink(response.data))
self.formDialog.show = false self.formDialog.show = false
console.log(response.data[1][1])
}) })
.catch(function (error) { .catch(function (error) {
LNbits.utils.notifyApiError(error) LNbits.utils.notifyApiError(error)
@@ -612,7 +605,6 @@
deleteWalletLink: function (linkId) { deleteWalletLink: function (linkId) {
var self = this var self = this
var link = _.findWhere(this.walletLinks, {id: linkId}) var link = _.findWhere(this.walletLinks, {id: linkId})
console.log(self.g.user.wallets[0].adminkey)
LNbits.utils LNbits.utils
.confirmDialog('Are you sure you want to delete this pay link?') .confirmDialog('Are you sure you want to delete this pay link?')
.onOk(function () { .onOk(function () {
@@ -642,15 +634,6 @@
getCharges() getCharges()
var getWalletLinks = this.getWalletLinks var getWalletLinks = this.getWalletLinks
getWalletLinks() getWalletLinks()
var getBalance = this.getBalance
setTimeout(function(){
for (i = 0; i < self.ChargeLinks.length; i++) {
getBalance(self.ChargeLinks[i].id)
}
}, 5000);
getCharges()
var updateCountdowns = this.updateCountdowns
updateCountdowns()
} }
}) })
</script> </script>

View File

@@ -1,4 +1,4 @@
from quart import g, abort, render_template from quart import g, abort, render_template, jsonify
from http import HTTPStatus from http import HTTPStatus
from lnbits.decorators import check_user_exists, validate_uuids from lnbits.decorators import check_user_exists, validate_uuids
@@ -16,6 +16,6 @@ async def index():
@satspay_ext.route("/<charge_id>") @satspay_ext.route("/<charge_id>")
async def display(charge_id): async def display(charge_id):
charge = get_charge(charge_id) or abort(HTTPStatus.NOT_FOUND, "Charge link does not exist.") charge = await get_charge(charge_id) or abort(
HTTPStatus.NOT_FOUND, "Charge link does not exist.")
return await render_template("satspay/display.html", charge=charge) return await render_template("satspay/display.html", charge=charge)

View File

@@ -46,38 +46,32 @@ async def api_charge_create_or_update(charge_id=None):
@satspay_ext.route("/api/v1/charges", methods=["GET"]) @satspay_ext.route("/api/v1/charges", methods=["GET"])
@api_check_wallet_key("invoice") @api_check_wallet_key("invoice")
async def api_charges_retrieve(): async def api_charges_retrieve():
try:
charges = await get_charges(g.wallet.user) return jsonify([{**charge._asdict(), **{"time_elapsed": charge.time_elapsed}, **{"paid": charge.paid}}for charge in await get_charges(g.wallet.user)]), HTTPStatus.OK
if not charges: except:
return ( return ""
jsonify(""),
HTTPStatus.OK
)
else:
return jsonify([charge._asdict() for charge in charges]), HTTPStatus.OK
@satspay_ext.route("/api/v1/charge/<charge_id>", methods=["GET"]) @satspay_ext.route("/api/v1/charge/<charge_id>", methods=["GET"])
@api_check_wallet_key("invoice") @api_check_wallet_key("invoice")
async def api_charge_retrieve(charge_id): async def api_charge_retrieve(charge_id):
charge = await get_charge(charge_id) charge = await get_charge(charge_id)
print(charge)
if not charge: if not charge:
return jsonify({"message": "charge does not exist"}), HTTPStatus.NOT_FOUND return jsonify({"message": "charge does not exist"}), HTTPStatus.NOT_FOUND
return jsonify(charge._asdict()), HTTPStatus.OK return jsonify({**charge._asdict(), **{"time_elapsed": charge.time_elapsed}, **{"paid": charge.paid}}), HTTPStatus.OK
@satspay_ext.route("/api/v1/charge/<charge_id>", methods=["DELETE"]) @satspay_ext.route("/api/v1/charge/<charge_id>", methods=["DELETE"])
@api_check_wallet_key("invoice") @api_check_wallet_key("invoice")
async def api_charge_delete(charge_id): async def api_charge_delete(charge_id):
charge = await get_watch_wallet(charge_id) charge = await get_charge(charge_id)
if not charge: if not charge:
return jsonify({"message": "Wallet link does not exist."}), HTTPStatus.NOT_FOUND return jsonify({"message": "Wallet link does not exist."}), HTTPStatus.NOT_FOUND
await delete_watch_wallet(charge_id) await delete_charge(charge_id)
return "", HTTPStatus.NO_CONTENT return "", HTTPStatus.NO_CONTENT
@@ -85,15 +79,12 @@ async def api_charge_delete(charge_id):
#############################BALANCE########################## #############################BALANCE##########################
@satspay_ext.route("/api/v1/charges/balance/<charge_id>", methods=["GET"]) @satspay_ext.route("/api/v1/charges/balance/<charge_id>", methods=["GET"])
@api_check_wallet_key("invoice")
async def api_charges_balance(charge_id): async def api_charges_balance(charge_id):
charge = await check_address_balance(charge_id) charge = await check_address_balance(charge_id)
if not charge: if not charge:
return ( return jsonify({"message": "charge does not exist"}), HTTPStatus.NOT_FOUND
jsonify(""),
HTTPStatus.OK
)
else: else:
return jsonify(charge._asdict()), HTTPStatus.OK return jsonify(charge._asdict()), HTTPStatus.OK