mirror of
https://github.com/lnbits/lnbits.git
synced 2025-09-21 14:10:30 +02:00
Removed satspay ext
This commit is contained in:
@@ -1,4 +0,0 @@
|
|||||||
# SatsPay Server
|
|
||||||
|
|
||||||
Create onchain and LN charges. Includes webhooks!
|
|
||||||
|
|
@@ -1,11 +0,0 @@
|
|||||||
from quart import Blueprint
|
|
||||||
from lnbits.db import Database
|
|
||||||
|
|
||||||
db = Database("ext_satspay")
|
|
||||||
|
|
||||||
|
|
||||||
satspay_ext: Blueprint = Blueprint("satspay", __name__, static_folder="static", template_folder="templates")
|
|
||||||
|
|
||||||
|
|
||||||
from .views_api import * # noqa
|
|
||||||
from .views import * # noqa
|
|
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "SatsPay Server",
|
|
||||||
"short_description": "Create onchain and LN charges",
|
|
||||||
"icon": "payment",
|
|
||||||
"contributors": [
|
|
||||||
"arcbtc"
|
|
||||||
]
|
|
||||||
}
|
|
@@ -1,96 +0,0 @@
|
|||||||
from typing import List, Optional, Union
|
|
||||||
|
|
||||||
#from lnbits.db import open_ext_db
|
|
||||||
from . import db
|
|
||||||
from .models import Charges
|
|
||||||
|
|
||||||
from lnbits.helpers import urlsafe_short_hash
|
|
||||||
|
|
||||||
from quart import jsonify
|
|
||||||
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##########################
|
|
||||||
|
|
||||||
|
|
||||||
async def create_charge(user: str, description: Optional[str] = None, onchainwallet: Optional[str] = None, lnbitswallet: Optional[str] = None, webhook: Optional[str] = None, time: Optional[int] = None, amount: Optional[int] = None) -> Charges:
|
|
||||||
charge_id = urlsafe_short_hash()
|
|
||||||
if onchainwallet:
|
|
||||||
wallet = await get_watch_wallet(onchainwallet)
|
|
||||||
onchainaddress = await get_derive_address(onchainwallet, wallet[4] + 1)
|
|
||||||
else:
|
|
||||||
onchainaddress = None
|
|
||||||
if lnbitswallet:
|
|
||||||
payment_hash, payment_request = await create_invoice(
|
|
||||||
wallet_id=lnbitswallet,
|
|
||||||
amount=amount,
|
|
||||||
memo=charge_id)
|
|
||||||
else:
|
|
||||||
payment_hash = None
|
|
||||||
payment_request = None
|
|
||||||
await db.execute(
|
|
||||||
"""
|
|
||||||
INSERT INTO charges (
|
|
||||||
id,
|
|
||||||
user,
|
|
||||||
description,
|
|
||||||
onchainwallet,
|
|
||||||
onchainaddress,
|
|
||||||
lnbitswallet,
|
|
||||||
payment_request,
|
|
||||||
payment_hash,
|
|
||||||
webhook,
|
|
||||||
time,
|
|
||||||
amount,
|
|
||||||
balance,
|
|
||||||
paid
|
|
||||||
)
|
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
||||||
""",
|
|
||||||
(charge_id, user, description, onchainwallet, onchainaddress, lnbitswallet, payment_request, payment_hash, webhook, time, amount, 0, False),
|
|
||||||
)
|
|
||||||
return await get_charge(charge_id)
|
|
||||||
|
|
||||||
async def update_charge(charge_id: str, **kwargs) -> Optional[Charges]:
|
|
||||||
q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()])
|
|
||||||
await db.execute(f"UPDATE charges SET {q} WHERE id = ?", (*kwargs.values(), wallet_id))
|
|
||||||
row = await db.fetchone("SELECT * FROM charges WHERE id = ?", (wallet_id,))
|
|
||||||
return Charges.from_row(row) if row else None
|
|
||||||
|
|
||||||
|
|
||||||
async def get_charge(charge_id: str) -> Charges:
|
|
||||||
row = await db.fetchone("SELECT * FROM charges WHERE id = ?", (charge_id,))
|
|
||||||
return Charges.from_row(row) if row else None
|
|
||||||
|
|
||||||
|
|
||||||
async def get_charges(user: str) -> List[Charges]:
|
|
||||||
rows = await db.fetchall("SELECT * FROM charges WHERE user = ?", (user,))
|
|
||||||
return [Charges.from_row(row) for row in rows]
|
|
||||||
|
|
||||||
|
|
||||||
async def delete_charge(charge_id: str) -> None:
|
|
||||||
await db.execute("DELETE FROM charges WHERE id = ?", (charge_id,))
|
|
||||||
|
|
||||||
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)
|
|
||||||
row = await db.fetchone("SELECT * FROM charges WHERE id = ?", (charge_id,))
|
|
||||||
return Charges.from_row(row) if row else None
|
|
@@ -1,26 +0,0 @@
|
|||||||
async def m001_initial(db):
|
|
||||||
"""
|
|
||||||
Initial wallet table.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
await db.execute(
|
|
||||||
"""
|
|
||||||
CREATE TABLE IF NOT EXISTS charges (
|
|
||||||
id TEXT NOT NULL PRIMARY KEY,
|
|
||||||
user TEXT,
|
|
||||||
description TEXT,
|
|
||||||
onchainwallet TEXT,
|
|
||||||
onchainaddress TEXT,
|
|
||||||
lnbitswallet TEXT,
|
|
||||||
payment_request TEXT,
|
|
||||||
payment_hash TEXT,
|
|
||||||
webhook TEXT,
|
|
||||||
time INTEGER,
|
|
||||||
amount INTEGER,
|
|
||||||
balance INTEGER DEFAULT 0,
|
|
||||||
paid BOOLEAN,
|
|
||||||
timestamp TIMESTAMP NOT NULL DEFAULT (strftime('%s', 'now'))
|
|
||||||
);
|
|
||||||
"""
|
|
||||||
)
|
|
@@ -1,22 +0,0 @@
|
|||||||
from sqlite3 import Row
|
|
||||||
from typing import NamedTuple
|
|
||||||
|
|
||||||
class Charges(NamedTuple):
|
|
||||||
id: str
|
|
||||||
user: str
|
|
||||||
description: str
|
|
||||||
onchainwallet: str
|
|
||||||
onchainaddress: str
|
|
||||||
lnbitswallet: str
|
|
||||||
payment_request: str
|
|
||||||
payment_hash: str
|
|
||||||
webhook: str
|
|
||||||
time: str
|
|
||||||
amount: int
|
|
||||||
balance: int
|
|
||||||
paid: bool
|
|
||||||
timestamp: int
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_row(cls, row: Row) -> "Payments":
|
|
||||||
return cls(**dict(row))
|
|
@@ -1,156 +0,0 @@
|
|||||||
<q-card>
|
|
||||||
<q-card-section>
|
|
||||||
<p>SatsPay: Create Onchain/LN charges. Includes webhooks!<br />
|
|
||||||
<small>
|
|
||||||
Created by, <a href="https://github.com/benarc">Ben Arc</a></small
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
</q-card-section>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<q-expansion-item
|
|
||||||
group="extras"
|
|
||||||
icon="swap_vertical_circle"
|
|
||||||
label="API info"
|
|
||||||
:content-inset-level="0.5"
|
|
||||||
>
|
|
||||||
<q-expansion-item group="api" dense expand-separator label="List pay links">
|
|
||||||
<q-card>
|
|
||||||
<q-card-section>
|
|
||||||
<code><span class="text-blue">GET</span> /pay/api/v1/links</code>
|
|
||||||
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
|
|
||||||
<code>{"X-Api-Key": <invoice_key>}</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>[<pay_link_object>, ...]</code>
|
|
||||||
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
|
||||||
<code
|
|
||||||
>curl -X GET {{ request.url_root }}pay/api/v1/links -H "X-Api-Key: {{
|
|
||||||
g.user.wallets[0].inkey }}"
|
|
||||||
</code>
|
|
||||||
</q-card-section>
|
|
||||||
</q-card>
|
|
||||||
</q-expansion-item>
|
|
||||||
<q-expansion-item group="api" dense expand-separator label="Get a pay link">
|
|
||||||
<q-card>
|
|
||||||
<q-card-section>
|
|
||||||
<code
|
|
||||||
><span class="text-blue">GET</span>
|
|
||||||
/pay/api/v1/links/<pay_id></code
|
|
||||||
>
|
|
||||||
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
|
|
||||||
<code>{"X-Api-Key": <invoice_key>}</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 201 CREATED (application/json)
|
|
||||||
</h5>
|
|
||||||
<code>{"lnurl": <string>}</code>
|
|
||||||
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
|
||||||
<code
|
|
||||||
>curl -X GET {{ request.url_root }}pay/api/v1/links/<pay_id> -H
|
|
||||||
"X-Api-Key: {{ g.user.wallets[0].inkey }}"
|
|
||||||
</code>
|
|
||||||
</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": <invoice_key>}</code><br />
|
|
||||||
<h5 class="text-caption q-mt-sm q-mb-none">Body (application/json)</h5>
|
|
||||||
<code>{"description": <string> "amount": <integer>}</code>
|
|
||||||
<h5 class="text-caption q-mt-sm q-mb-none">
|
|
||||||
Returns 201 CREATED (application/json)
|
|
||||||
</h5>
|
|
||||||
<code> {
|
|
||||||
"deliveryId": <string>,
|
|
||||||
"description": <string>,
|
|
||||||
"webhookId": <string>,
|
|
||||||
"originalDeliveryId": <string>,
|
|
||||||
"isRedelivery": <boolean>,
|
|
||||||
"type": <string>,
|
|
||||||
"timestamp": <int>,
|
|
||||||
"paytime": <int>,
|
|
||||||
"storeId": <string>,
|
|
||||||
"invoiceId": <string>,
|
|
||||||
"manuallyMarked": <boolean>,
|
|
||||||
"overPaid": <boolean>,
|
|
||||||
"afterExpiration": <boolean>,
|
|
||||||
"partiallyPaid": <boolean>
|
|
||||||
}<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": <string>, "amount": <integer>}' -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/<pay_id></code
|
|
||||||
>
|
|
||||||
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
|
|
||||||
<code>{"X-Api-Key": <admin_key>}</code><br />
|
|
||||||
<h5 class="text-caption q-mt-sm q-mb-none">Body (application/json)</h5>
|
|
||||||
<code>{"description": <string>, "amount": <integer>}</code>
|
|
||||||
<h5 class="text-caption q-mt-sm q-mb-none">
|
|
||||||
Returns 200 OK (application/json)
|
|
||||||
</h5>
|
|
||||||
<code>{"lnurl": <string>}</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/<pay_id> -d
|
|
||||||
'{"description": <string>, "amount": <integer>}' -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="Delete a pay link"
|
|
||||||
class="q-pb-md"
|
|
||||||
>
|
|
||||||
<q-card>
|
|
||||||
<q-card-section>
|
|
||||||
<code
|
|
||||||
><span class="text-pink">DELETE</span>
|
|
||||||
/pay/api/v1/links/<pay_id></code
|
|
||||||
>
|
|
||||||
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
|
|
||||||
<code>{"X-Api-Key": <admin_key>}</code><br />
|
|
||||||
<h5 class="text-caption q-mt-sm q-mb-none">Returns 204 NO CONTENT</h5>
|
|
||||||
<code></code>
|
|
||||||
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
|
||||||
<code
|
|
||||||
>curl -X DELETE {{ request.url_root }}pay/api/v1/links/<pay_id>
|
|
||||||
-H "X-Api-Key: {{ g.user.wallets[0].adminkey }}"
|
|
||||||
</code>
|
|
||||||
</q-card-section>
|
|
||||||
</q-card>
|
|
||||||
</q-expansion-item>
|
|
||||||
</q-expansion-item>
|
|
@@ -1,74 +0,0 @@
|
|||||||
{% extends "public.html" %} {% block page %}
|
|
||||||
|
|
||||||
<div class="q-pa-md">
|
|
||||||
<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>
|
|
||||||
|
|
||||||
<q-tabs v-model="tab" class="text-teal">
|
|
||||||
<q-tab label="Tab one" name="one" />
|
|
||||||
<q-tab label="Tab two" name="two" />
|
|
||||||
</q-tabs>
|
|
||||||
|
|
||||||
<q-separator />
|
|
||||||
|
|
||||||
<q-tab-panels v-model="tab" animated>
|
|
||||||
<q-tab-panel name="Lightning">
|
|
||||||
<div class="text-center">
|
|
||||||
<a href="lightning:{{ charge.id }}">
|
|
||||||
<q-responsive :ratio="1" class="q-mx-md">
|
|
||||||
<qrcode
|
|
||||||
value="{{ charge.id }}"
|
|
||||||
:options="{width: 300}"
|
|
||||||
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
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</q-tab-panel>
|
|
||||||
|
|
||||||
<q-tab-panel name="Onchain">
|
|
||||||
<div class="text-center">
|
|
||||||
<a href="lightning:{{ charge.id }}">
|
|
||||||
<q-responsive :ratio="1" class="q-mx-md">
|
|
||||||
<qrcode
|
|
||||||
value="{{ charge.id }}"
|
|
||||||
:options="{width: 300}"
|
|
||||||
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
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</q-tab-panel>
|
|
||||||
</q-tab-panels>
|
|
||||||
</q-card>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% endblock %} {% block scripts %}
|
|
||||||
<script src="{{ url_for('static', filename='vendor/vue-qrcode@1.0.2/vue-qrcode.min.js') }}"></script>
|
|
||||||
<script>
|
|
||||||
Vue.component(VueQrcode.name, VueQrcode)
|
|
||||||
|
|
||||||
new Vue({
|
|
||||||
el: '#vue',
|
|
||||||
mixins: [windowMixin]
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
@@ -1,643 +0,0 @@
|
|||||||
{% extends "base.html" %} {% from "macros.jinja" import window_vars with context
|
|
||||||
%} {% block page %}
|
|
||||||
<div class="row q-col-gutter-md">
|
|
||||||
<div class="col-12 col-md-7 q-gutter-y-md">
|
|
||||||
<q-card>
|
|
||||||
<q-card-section>
|
|
||||||
{% raw %}
|
|
||||||
<q-btn unelevated color="deep-purple" @click="formDialogCharge.show = true"
|
|
||||||
>New charge </q-btn
|
|
||||||
>
|
|
||||||
</q-card-section>
|
|
||||||
</q-card>
|
|
||||||
|
|
||||||
<q-card>
|
|
||||||
<q-card-section>
|
|
||||||
<div class="row items-center no-wrap q-mb-md">
|
|
||||||
<div class="col">
|
|
||||||
<h5 class="text-subtitle1 q-my-none">Charges</h5>
|
|
||||||
</div>
|
|
||||||
<div class="col-auto">
|
|
||||||
<q-input borderless dense debounce="300" v-model="filter" placeholder="Search">
|
|
||||||
<template v-slot:append>
|
|
||||||
<q-icon name="search"></q-icon>
|
|
||||||
</template>
|
|
||||||
</q-input>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<q-table
|
|
||||||
flat
|
|
||||||
dense
|
|
||||||
:data="ChargeLinks"
|
|
||||||
row-key="id"
|
|
||||||
:columns="ChargesTable.columns"
|
|
||||||
:pagination.sync="ChargesTable.pagination"
|
|
||||||
:filter="filter"
|
|
||||||
>
|
|
||||||
|
|
||||||
<template v-slot:header="props">
|
|
||||||
<q-tr :props="props">
|
|
||||||
<q-th auto-width></q-th>
|
|
||||||
<q-th auto-width></q-th>
|
|
||||||
|
|
||||||
<q-th v-for="col in props.cols" :key="col.name" :props="props" auto-width>
|
|
||||||
<div v-if="col.name == 'id'"></div>
|
|
||||||
<div v-else>
|
|
||||||
{{ col.label }}
|
|
||||||
</div>
|
|
||||||
</q-th>
|
|
||||||
<q-th auto-width></q-th>
|
|
||||||
</q-tr>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-slot:body="props">
|
|
||||||
<q-tr :props="props">
|
|
||||||
|
|
||||||
<q-td auto-width>
|
|
||||||
<q-btn
|
|
||||||
unelevated
|
|
||||||
dense
|
|
||||||
size="xs"
|
|
||||||
icon="link"
|
|
||||||
:color="($q.dark.isActive) ? 'grey-7' : 'grey-5'"
|
|
||||||
type="a"
|
|
||||||
:href="props.row.displayUrl"
|
|
||||||
target="_blank"
|
|
||||||
></q-btn>
|
|
||||||
</q-td>
|
|
||||||
<q-td auto-width>
|
|
||||||
|
|
||||||
<q-icon v-if="props.row.timeleft < 1 && props.row.amount_paid < props.row.amount"
|
|
||||||
#unelevated
|
|
||||||
dense
|
|
||||||
size="xs"
|
|
||||||
name="error"
|
|
||||||
:color="($q.dark.isActive) ? 'red' : 'red'"
|
|
||||||
></q-icon>
|
|
||||||
|
|
||||||
<q-icon v-else-if="props.row.balance > props.row.amount"
|
|
||||||
#unelevated
|
|
||||||
dense
|
|
||||||
size="xs"
|
|
||||||
name="check"
|
|
||||||
:color="($q.dark.isActive) ? 'green' : 'green'"
|
|
||||||
></q-icon>
|
|
||||||
|
|
||||||
<q-icon v-else="props.row.amount_paid < props.row.amount && props.row.timeleft > 1"
|
|
||||||
#unelevated
|
|
||||||
dense
|
|
||||||
size="xs"
|
|
||||||
name="cached"
|
|
||||||
:color="($q.dark.isActive) ? 'blue' : 'blue'"
|
|
||||||
></q-icon>
|
|
||||||
<q-btn
|
|
||||||
flat
|
|
||||||
dense
|
|
||||||
size="xs"
|
|
||||||
@click="openUpdateDialog(props.row.id)"
|
|
||||||
icon="edit"
|
|
||||||
color="light-blue"
|
|
||||||
></q-btn>
|
|
||||||
<q-btn
|
|
||||||
flat
|
|
||||||
dense
|
|
||||||
size="xs"
|
|
||||||
@click="deleteWalletLink(props.row.id)"
|
|
||||||
icon="cancel"
|
|
||||||
color="pink"
|
|
||||||
></q-btn>
|
|
||||||
|
|
||||||
|
|
||||||
</q-td>
|
|
||||||
<q-td v-for="col in props.cols" :key="col.name" :props="props" auto-width>
|
|
||||||
<div v-if="col.name == 'id'"></div>
|
|
||||||
<div v-else>
|
|
||||||
{{ col.value }}
|
|
||||||
</div>
|
|
||||||
</q-td>
|
|
||||||
|
|
||||||
</q-tr>
|
|
||||||
</template>
|
|
||||||
{% endraw %}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</q-table>
|
|
||||||
</q-card-section>
|
|
||||||
</q-card>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="col-12 col-md-5 q-gutter-y-md">
|
|
||||||
<q-card>
|
|
||||||
<q-card-section>
|
|
||||||
<h6 class="text-subtitle1 q-my-none">
|
|
||||||
LNbits satspay Extension
|
|
||||||
</h6>
|
|
||||||
</q-card-section>
|
|
||||||
<q-card-section class="q-pa-none">
|
|
||||||
<q-separator></q-separator>
|
|
||||||
<q-list>
|
|
||||||
{% include "satspay/_api_docs.html" %}
|
|
||||||
</q-list>
|
|
||||||
</q-card-section>
|
|
||||||
</q-card>
|
|
||||||
</div>
|
|
||||||
<q-dialog v-model="formDialogCharge.show" position="top" @hide="closeFormDialog">
|
|
||||||
<q-card class="q-pa-lg q-pt-xl lnbits__dialog-card">
|
|
||||||
<q-form @submit="sendFormDataCharge" class="q-gutter-md">
|
|
||||||
|
|
||||||
<q-input
|
|
||||||
filled
|
|
||||||
dense
|
|
||||||
v-model.trim="formDialogCharge.data.description"
|
|
||||||
type="text"
|
|
||||||
label="Description"
|
|
||||||
></q-input>
|
|
||||||
|
|
||||||
<q-input
|
|
||||||
filled
|
|
||||||
dense
|
|
||||||
v-model.trim="formDialogCharge.data.amount"
|
|
||||||
type="number"
|
|
||||||
label="Amount (sats)"
|
|
||||||
></q-input>
|
|
||||||
|
|
||||||
<q-input
|
|
||||||
filled
|
|
||||||
dense
|
|
||||||
v-model.trim="formDialogCharge.data.time"
|
|
||||||
type="number"
|
|
||||||
label="Time (secs)"
|
|
||||||
> </q-input>
|
|
||||||
|
|
||||||
<q-input
|
|
||||||
filled
|
|
||||||
dense
|
|
||||||
v-model.trim="formDialogCharge.data.webhook"
|
|
||||||
type="url"
|
|
||||||
label="Webhook"
|
|
||||||
> </q-input>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<div v-if="walletLinks.length > 0">
|
|
||||||
<q-checkbox v-model="formDialogCharge.data.onchain" label="Onchain" />
|
|
||||||
</div>
|
|
||||||
<div v-else>
|
|
||||||
<q-checkbox :value=false label="Onchain" disabled>
|
|
||||||
<q-tooltip>
|
|
||||||
Watch-Only extension MUST be activated and have a wallet
|
|
||||||
</q-tooltip>
|
|
||||||
</q-checkbox>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col">
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<q-checkbox v-model="formDialogCharge.data.lnbits" label="LNbits wallet" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div v-if="formDialogCharge.data.onchain">
|
|
||||||
|
|
||||||
<q-select filled dense emit-value v-model="formDialogCharge.data.onchainwallet" :options="walletLinks" label="Onchain Wallet" />
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div v-if="formDialogCharge.data.lnbits">
|
|
||||||
<q-select
|
|
||||||
filled
|
|
||||||
dense
|
|
||||||
emit-value
|
|
||||||
v-model="formDialogCharge.data.lnbitswallet"
|
|
||||||
:options="g.user.walletOptions"
|
|
||||||
label="Wallet *"
|
|
||||||
>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="row q-mt-lg">
|
|
||||||
<q-btn
|
|
||||||
v-if="formDialogCharge.data.id"
|
|
||||||
unelevated
|
|
||||||
color="deep-purple"
|
|
||||||
type="submit"
|
|
||||||
>Update Paylink</q-btn
|
|
||||||
>
|
|
||||||
<q-btn
|
|
||||||
v-else
|
|
||||||
unelevated
|
|
||||||
color="deep-purple"
|
|
||||||
:disable="
|
|
||||||
formDialogCharge.data.time == null ||
|
|
||||||
formDialogCharge.data.amount == null"
|
|
||||||
type="submit"
|
|
||||||
>Create Paylink</q-btn
|
|
||||||
>
|
|
||||||
<q-btn v-close-popup flat color="grey" class="q-ml-auto"
|
|
||||||
>Cancel</q-btn
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</q-form>
|
|
||||||
</q-card>
|
|
||||||
</q-dialog>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
{% endblock %} {% block scripts %} {{ window_vars(user) }}
|
|
||||||
<script src="{{ url_for('static', filename='vendor/vue-qrcode@1.0.2/vue-qrcode.min.js') }}"></script>
|
|
||||||
<style>
|
|
||||||
|
|
||||||
</style>
|
|
||||||
<script>
|
|
||||||
Vue.component(VueQrcode.name, VueQrcode)
|
|
||||||
|
|
||||||
Vue.filter('reverse', function(value) {
|
|
||||||
// slice to make a copy of array, then reverse the copy
|
|
||||||
return value.slice().reverse();
|
|
||||||
});
|
|
||||||
var locationPath = [
|
|
||||||
window.location.protocol,
|
|
||||||
'//',
|
|
||||||
window.location.hostname,
|
|
||||||
window.location.pathname
|
|
||||||
].join('')
|
|
||||||
|
|
||||||
var mapWalletLink = function (obj) {
|
|
||||||
obj._data = _.clone(obj)
|
|
||||||
obj.date = Quasar.utils.date.formatDate(
|
|
||||||
new Date(obj.time * 1000),
|
|
||||||
'YYYY-MM-DD HH:mm'
|
|
||||||
)
|
|
||||||
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){
|
|
||||||
obj.date = "Time elapsed"
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
obj.date = Quasar.utils.date.formatDate(
|
|
||||||
|
|
||||||
new Date(obj.theDate * 1000),
|
|
||||||
'HH:mm:ss'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.displayUrl = ['/satspay/', obj.id].join('')
|
|
||||||
return obj
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
new Vue({
|
|
||||||
el: '#vue',
|
|
||||||
mixins: [windowMixin],
|
|
||||||
data: function () {
|
|
||||||
return {
|
|
||||||
filter: '',
|
|
||||||
watchonlyactive: false,
|
|
||||||
balance: null,
|
|
||||||
checker: null,
|
|
||||||
walletLinks: [],
|
|
||||||
ChargeLinks: [],
|
|
||||||
onchainwallet: '',
|
|
||||||
currentaddress: "",
|
|
||||||
Addresses: {
|
|
||||||
show: false,
|
|
||||||
data: null
|
|
||||||
},
|
|
||||||
mempool:{
|
|
||||||
endpoint:""
|
|
||||||
},
|
|
||||||
|
|
||||||
ChargesTable: {
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
name: 'description',
|
|
||||||
align: 'left',
|
|
||||||
label: 'Title',
|
|
||||||
field: 'description'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'amount',
|
|
||||||
align: 'left',
|
|
||||||
label: 'Amount to pay',
|
|
||||||
field: 'amount'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'balance',
|
|
||||||
align: 'left',
|
|
||||||
label: 'Balance',
|
|
||||||
field: 'balance'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'onchain address',
|
|
||||||
align: 'left',
|
|
||||||
label: 'Onchain Address',
|
|
||||||
field: 'onchainaddress'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'LNbits wallet',
|
|
||||||
align: 'left',
|
|
||||||
label: 'LNbits wallet',
|
|
||||||
field: 'lnbitswallet'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'time to pay',
|
|
||||||
align: 'left',
|
|
||||||
label: 'Time to Pay',
|
|
||||||
field: 'time'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'timeleft',
|
|
||||||
align: 'left',
|
|
||||||
label: 'Time left',
|
|
||||||
field: 'date'
|
|
||||||
},
|
|
||||||
],
|
|
||||||
pagination: {
|
|
||||||
rowsPerPage: 10
|
|
||||||
}
|
|
||||||
},
|
|
||||||
formDialog: {
|
|
||||||
show: false,
|
|
||||||
data: {}
|
|
||||||
},
|
|
||||||
formDialogCharge: {
|
|
||||||
show: false,
|
|
||||||
data: {onchain: false,lnbits:false}
|
|
||||||
},
|
|
||||||
qrCodeDialog: {
|
|
||||||
show: false,
|
|
||||||
data: null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
|
|
||||||
getWalletLinks: function () {
|
|
||||||
var self = this
|
|
||||||
|
|
||||||
LNbits.api
|
|
||||||
.request(
|
|
||||||
'GET',
|
|
||||||
'/watchonly/api/v1/wallet',
|
|
||||||
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) {
|
|
||||||
LNbits.utils.notifyApiError(error)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
closeFormDialog: function () {
|
|
||||||
this.formDialog.data = {
|
|
||||||
is_unique: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
openQrCodeDialog: function (linkId) {
|
|
||||||
var self = this
|
|
||||||
var getAddresses = this.getAddresses
|
|
||||||
getAddresses(linkId)
|
|
||||||
self.current = linkId
|
|
||||||
self.Addresses.show = true
|
|
||||||
},
|
|
||||||
|
|
||||||
openUpdateDialog: function (linkId) {
|
|
||||||
var link = _.findWhere(this.walletLinks, {id: linkId})
|
|
||||||
this.formDialog.data = _.clone(link._data)
|
|
||||||
this.formDialog.show = true
|
|
||||||
},
|
|
||||||
sendFormData: function () {
|
|
||||||
var wallet = this.g.user.wallets[0]
|
|
||||||
var data = _.omit(this.formDialog.data, 'wallet')
|
|
||||||
|
|
||||||
if (data.id) {
|
|
||||||
this.updateWalletLink(wallet, data)
|
|
||||||
} else {
|
|
||||||
this.createWalletLink(wallet, data)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
getCharges: function () {
|
|
||||||
var self = this
|
|
||||||
var getAddressBalance = this.getAddressBalance
|
|
||||||
|
|
||||||
LNbits.api
|
|
||||||
.request(
|
|
||||||
'GET',
|
|
||||||
'/satspay/api/v1/charges',
|
|
||||||
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) {
|
|
||||||
console.log(obj.timestamp)
|
|
||||||
console.log(Date.now()/1000)
|
|
||||||
return mapCharge(obj)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.catch(function (error) {
|
|
||||||
LNbits.utils.notifyApiError(error)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
sendFormDataCharge: function () {
|
|
||||||
var self = this
|
|
||||||
var wallet = self.g.user.wallets[0].inkey
|
|
||||||
var data = self.formDialogCharge.data
|
|
||||||
console.log(data)
|
|
||||||
data.amount = parseInt(data.amount)
|
|
||||||
data.time = parseInt(data.time)
|
|
||||||
if (data.id) {
|
|
||||||
this.updateCharge(wallet, data)
|
|
||||||
} else {
|
|
||||||
this.createCharge(wallet, data)
|
|
||||||
}
|
|
||||||
this.getCharges()
|
|
||||||
this.formDialogCharge.show = false
|
|
||||||
this.formDialogCharge.data = null
|
|
||||||
},
|
|
||||||
updateCharge: function (wallet, data) {
|
|
||||||
var self = this
|
|
||||||
|
|
||||||
LNbits.api
|
|
||||||
.request(
|
|
||||||
'PUT',
|
|
||||||
'/satspay/api/v1/Charge/' + data.id,
|
|
||||||
wallet.inkey, data)
|
|
||||||
.then(function (response) {
|
|
||||||
self.Charge = _.reject(self.Charge, function (obj) {
|
|
||||||
return obj.id === data.id
|
|
||||||
})
|
|
||||||
self.Charge.push(mapCharge(response.data))
|
|
||||||
self.formDialogPayLink.show = false
|
|
||||||
})
|
|
||||||
.catch(function (error) {
|
|
||||||
LNbits.utils.notifyApiError(error)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
getBalance: function (walletId) {
|
|
||||||
var self = this
|
|
||||||
LNbits.api
|
|
||||||
.request(
|
|
||||||
'GET',
|
|
||||||
'/satspay/api/v1/charges/balance/' + walletId,
|
|
||||||
this.g.user.wallets[0].inkey
|
|
||||||
)
|
|
||||||
.then(function (response) {
|
|
||||||
console.log(response.data)
|
|
||||||
})
|
|
||||||
.catch(function (error) {
|
|
||||||
LNbits.utils.notifyApiError(error)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
createCharge: function (wallet, data) {
|
|
||||||
var self = this
|
|
||||||
|
|
||||||
LNbits.api
|
|
||||||
.request('POST', '/satspay/api/v1/charge', wallet, data)
|
|
||||||
.then(function (response) {
|
|
||||||
this.formDialogCharge.show = false
|
|
||||||
this.formDialogCharge.data = null
|
|
||||||
self.ChargeLinks.push(mapCharge(response.data))
|
|
||||||
|
|
||||||
})
|
|
||||||
.catch(function (error) {
|
|
||||||
LNbits.utils.notifyApiError(error)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
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,
|
|
||||||
self.g.user.wallets[0].inkey
|
|
||||||
)
|
|
||||||
.then(function (response) {
|
|
||||||
self.Charge = _.reject(self.Charge, function (obj) {
|
|
||||||
return obj.id === linkId
|
|
||||||
})})
|
|
||||||
.catch(function (error) {
|
|
||||||
LNbits.utils.notifyApiError(error)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
updateWalletLink: function (wallet, data) {
|
|
||||||
var self = this
|
|
||||||
|
|
||||||
LNbits.api
|
|
||||||
.request(
|
|
||||||
'PUT',
|
|
||||||
'/satspay/api/v1/wallet/' + data.id,
|
|
||||||
wallet.inkey, data)
|
|
||||||
.then(function (response) {
|
|
||||||
self.walletLinks = _.reject(self.walletLinks, function (obj) {
|
|
||||||
return obj.id === data.id
|
|
||||||
})
|
|
||||||
self.walletLinks.push(mapWalletLink(response.data))
|
|
||||||
self.formDialog.show = false
|
|
||||||
})
|
|
||||||
.catch(function (error) {
|
|
||||||
LNbits.utils.notifyApiError(error)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
createWalletLink: function (wallet, data) {
|
|
||||||
var self = this
|
|
||||||
|
|
||||||
LNbits.api
|
|
||||||
.request('POST', '/satspay/api/v1/wallet', wallet.inkey, data)
|
|
||||||
.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)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
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 () {
|
|
||||||
LNbits.api
|
|
||||||
.request(
|
|
||||||
'DELETE',
|
|
||||||
'/satspay/api/v1/wallet/' + linkId,
|
|
||||||
self.g.user.wallets[0].inkey
|
|
||||||
)
|
|
||||||
.then(function (response) {
|
|
||||||
self.walletLinks = _.reject(self.walletLinks, function (obj) {
|
|
||||||
return obj.id === linkId
|
|
||||||
})})
|
|
||||||
.catch(function (error) {
|
|
||||||
LNbits.utils.notifyApiError(error)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
},
|
|
||||||
exportCSV: function () {
|
|
||||||
LNbits.utils.exportCSV(this.paywallsTable.columns, this.paywalls)
|
|
||||||
},
|
|
||||||
|
|
||||||
},
|
|
||||||
created: function () {
|
|
||||||
var self = this
|
|
||||||
var getCharges = this.getCharges
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
@@ -1,21 +0,0 @@
|
|||||||
from quart import g, abort, render_template
|
|
||||||
from http import HTTPStatus
|
|
||||||
|
|
||||||
from lnbits.decorators import check_user_exists, validate_uuids
|
|
||||||
|
|
||||||
from . import satspay_ext
|
|
||||||
from .crud import get_charge
|
|
||||||
|
|
||||||
|
|
||||||
@satspay_ext.route("/")
|
|
||||||
@validate_uuids(["usr"], required=True)
|
|
||||||
@check_user_exists()
|
|
||||||
async def index():
|
|
||||||
return await render_template("satspay/index.html", user=g.user)
|
|
||||||
|
|
||||||
|
|
||||||
@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)
|
|
@@ -1,112 +0,0 @@
|
|||||||
import hashlib
|
|
||||||
from quart import g, jsonify, url_for
|
|
||||||
from http import HTTPStatus
|
|
||||||
import httpx
|
|
||||||
|
|
||||||
|
|
||||||
from lnbits.core.crud import get_user
|
|
||||||
from lnbits.decorators import api_check_wallet_key, api_validate_post_request
|
|
||||||
|
|
||||||
from lnbits.extensions.satspay import satspay_ext
|
|
||||||
from .crud import (
|
|
||||||
create_charge,
|
|
||||||
get_charge,
|
|
||||||
get_charges,
|
|
||||||
delete_charge,
|
|
||||||
check_address_balance,
|
|
||||||
)
|
|
||||||
|
|
||||||
#############################CHARGES##########################
|
|
||||||
@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
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
return jsonify(charge._asdict()), HTTPStatus.OK
|
|
||||||
|
|
||||||
@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
|
|
||||||
|
|
||||||
|
|
||||||
@satspay_ext.route("/api/v1/charge/<charge_id>", methods=["GET"])
|
|
||||||
@api_check_wallet_key("invoice")
|
|
||||||
async def api_charge_retrieve(charge_id):
|
|
||||||
charge = get_charge(charge_id)
|
|
||||||
|
|
||||||
if not charge:
|
|
||||||
return jsonify({"message": "charge does not exist"}), HTTPStatus.NOT_FOUND
|
|
||||||
|
|
||||||
return jsonify({charge}), HTTPStatus.OK
|
|
||||||
|
|
||||||
|
|
||||||
@satspay_ext.route("/api/v1/charge", methods=["POST"])
|
|
||||||
@satspay_ext.route("/api/v1/charge/<charge_id>", methods=["PUT"])
|
|
||||||
@api_check_wallet_key("invoice")
|
|
||||||
@api_validate_post_request(
|
|
||||||
schema={
|
|
||||||
"onchainwallet": {"type": "string"},
|
|
||||||
"lnbitswallet": {"type": "string"},
|
|
||||||
"description": {"type": "string", "empty": False, "required": True},
|
|
||||||
"webhook": {"type": "string", "empty": False, "required": True},
|
|
||||||
"time": {"type": "integer", "min": 1, "required": True},
|
|
||||||
"amount": {"type": "integer", "min": 1, "required": True},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
async def api_charge_create_or_update(charge_id=None):
|
|
||||||
|
|
||||||
if not charge_id:
|
|
||||||
charge = await create_charge(user = g.wallet.user, **g.data)
|
|
||||||
return jsonify(charge), HTTPStatus.CREATED
|
|
||||||
else:
|
|
||||||
charge = await update_charge(user = g.wallet.user, **g.data)
|
|
||||||
return jsonify(charge), 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)
|
|
||||||
|
|
||||||
if not charge:
|
|
||||||
return jsonify({"message": "Wallet link does not exist."}), HTTPStatus.NOT_FOUND
|
|
||||||
|
|
||||||
await delete_watch_wallet(charge_id)
|
|
||||||
|
|
||||||
return "", HTTPStatus.NO_CONTENT
|
|
||||||
|
|
||||||
#############################MEMPOOL##########################
|
|
||||||
|
|
||||||
@satspay_ext.route("/api/v1/mempool", methods=["PUT"])
|
|
||||||
@api_check_wallet_key("invoice")
|
|
||||||
@api_validate_post_request(
|
|
||||||
schema={
|
|
||||||
"endpoint": {"type": "string", "empty": False, "required": True},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
async def api_update_mempool():
|
|
||||||
mempool = await update_mempool(user=g.wallet.user, **g.data)
|
|
||||||
return jsonify(mempool._asdict()), HTTPStatus.OK
|
|
||||||
|
|
||||||
@satspay_ext.route("/api/v1/mempool", methods=["GET"])
|
|
||||||
@api_check_wallet_key("invoice")
|
|
||||||
async def api_get_mempool():
|
|
||||||
mempool = await get_mempool(g.wallet.user)
|
|
||||||
if not mempool:
|
|
||||||
mempool = await create_mempool(user=g.wallet.user)
|
|
||||||
return jsonify(mempool._asdict()), HTTPStatus.OK
|
|
Reference in New Issue
Block a user