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 ..watchonly.crud import get_watch_wallet, get_derive_address, get_mempool
import time
###############CHARGES##########################
@ -45,13 +44,12 @@ async def create_charge(user: str, description: Optional[str] = None, onchainwal
webhook,
time,
amount,
balance,
paid
balance
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
(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)
@ -79,21 +77,24 @@ async def delete_charge(charge_id: str) -> None:
async def check_address_balance(charge_id: str) -> List[Charges]:
charge = await get_charge(charge_id)
if charge.onchainaddress:
mempool = await get_mempool(charge.user)
try:
async with httpx.AsyncClient() as client:
r = await client.get(mempool.endpoint + "/api/address/" + charge.onchainaddress)
respAmount = r.json()['chain_stats']['funded_txo_sum']
if (charge.balance + respAmount) >= charge.balance:
return await update_charge(charge_id=charge_id, balance=(charge.balance + respAmount), paid=True)
else:
return await update_charge(charge_id=charge_id, balance=(charge.balance + respAmount), paid=False)
except Exception:
pass
if charge.lnbitswallet:
invoice_status = await check_invoice_status(charge.lnbitswallet, charge.payment_hash)
if invoice_status.paid:
return await update_charge(charge_id=charge_id, balance=charge.balance, paid=True)
print(charge.balance)
if not charge.paid:
if charge.onchainaddress:
mempool = await get_mempool(charge.user)
try:
async with httpx.AsyncClient() as client:
r = await client.get(mempool.endpoint + "/api/address/" + charge.onchainaddress)
respAmount = r.json()['chain_stats']['funded_txo_sum']
print(respAmount)
if respAmount >= charge.balance:
await update_charge(charge_id=charge_id, balance=respAmount)
except Exception:
pass
if charge.lnbitswallet:
invoice_status = await check_invoice_status(charge.lnbitswallet, charge.payment_hash)
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,))
return Charges.from_row(row) if row else None

View File

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

View File

@ -1,5 +1,6 @@
from sqlite3 import Row
from typing import NamedTuple
import time
class Charges(NamedTuple):
@ -12,12 +13,25 @@ class Charges(NamedTuple):
payment_request: str
payment_hash: str
webhook: str
time: str
time: int
amount: int
balance: int
paid: bool
timestamp: int
@classmethod
def from_row(cls, row: Row) -> "Charges":
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>
</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
group="api"
dense
@ -202,7 +128,7 @@
<q-card-section>
<code
><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>
<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>
<code
>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 }}"
</code>
</q-card-section>
</q-card>
</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-card>

View File

@ -1,74 +1,241 @@
{% extends "public.html" %} {% block page %}
<div class="q-pa-md">
<div class="q-pa-sm theCard">
<q-card class="my-card">
<q-card-section>
<div class="text-h6">Our Changing Planet</div>
<div class="text-subtitle2">by John Doe</div>
</q-card-section>
<div class="column">
<center> <div class="col theHeading">{{ charge.description }}</div></center>
<q-tabs v-model="tab" class="text-teal">
<q-tab label="Tab one" name="one" />
<q-tab label="Tab two" name="two" />
</q-tabs>
<div class="col">
<div class="col" color="white" style="background-color:grey; height: 30px; padding: 5px" v-if="charge_time_elapsed == 'True'">
<center>Time elapsed</center>
</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="text-center">
<a href="lightning:{{ charge.id }}">
<div class="col" style="margin: 2px 15px; max-height:100px" >
<center>
<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">
<qrcode
value="{{ charge.id }}"
:options="{width: 300}"
:value="'{{ charge.payment_request }}'"
:options="{width: 800}"
class="rounded-borders"
></qrcode>
</q-responsive>
</a>
</div>
<div class="row q-mt-lg">
<q-btn outline color="grey" @click="copyText('{{ charge.id }}')"
>Copy address</q-btn
<q-btn outline color="grey" @click="copyText('{{ charge.payment_request }}')"
>Copy invoice</q-btn
>
</div>
</q-tab-panel>
</div></div>
</q-card-section>
</q-card>
<q-tab-panel name="Onchain">
<div class="text-center">
<a href="lightning:{{ charge.id }}">
<q-card class="q-pa-lg" v-if="onbtc">
<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">
<qrcode
value="{{ charge.id }}"
:options="{width: 300}"
:value="'{{ charge.onchainaddress }}'"
:options="{width: 800}"
class="rounded-borders"
></qrcode>
</q-responsive>
</a>
</div>
<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
>
</div>
</q-tab-panel>
</q-tab-panels>
</div></div>
</q-card-section>
</q-card>
</q-card>
</div>
{% endblock %} {% block scripts %}
<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>
Vue.component(VueQrcode.name, VueQrcode)
new 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>
{% endblock %}

View File

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

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 lnbits.decorators import check_user_exists, validate_uuids
@ -16,6 +16,6 @@ async def index():
@satspay_ext.route("/<charge_id>")
async def display(charge_id):
charge = get_charge(charge_id) or abort(HTTPStatus.NOT_FOUND, "Charge link does not exist.")
return await render_template("satspay/display.html", charge=charge)
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)

View File

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