mirror of
https://github.com/lnbits/lnbits-legend.git
synced 2025-02-23 06:35:23 +01:00
generated fresh addresses nicely
This commit is contained in:
parent
48cf23346c
commit
c62678b3aa
7 changed files with 97 additions and 57 deletions
1
Pipfile
1
Pipfile
|
@ -24,6 +24,7 @@ quart-trio = "*"
|
||||||
trio = "==0.16.0"
|
trio = "==0.16.0"
|
||||||
hypercorn = {extras = ["trio"], version = "*"}
|
hypercorn = {extras = ["trio"], version = "*"}
|
||||||
sqlalchemy-aio = "*"
|
sqlalchemy-aio = "*"
|
||||||
|
embit = "*"
|
||||||
|
|
||||||
[dev-packages]
|
[dev-packages]
|
||||||
black = "==20.8b1"
|
black = "==20.8b1"
|
||||||
|
|
|
@ -57,7 +57,6 @@ async def get_address(address: str) -> Addresses:
|
||||||
row = await db.fetchone("SELECT * FROM addresses WHERE address = ?", (address,))
|
row = await db.fetchone("SELECT * FROM addresses WHERE address = ?", (address,))
|
||||||
return Addresses.from_row(row) if row else None
|
return Addresses.from_row(row) if row else None
|
||||||
|
|
||||||
|
|
||||||
async def get_addresses(wallet_id: str) -> List[Addresses]:
|
async def get_addresses(wallet_id: str) -> List[Addresses]:
|
||||||
rows = await db.fetchall("SELECT * FROM addresses WHERE wallet = ?", (wallet_id,))
|
rows = await db.fetchall("SELECT * FROM addresses WHERE wallet = ?", (wallet_id,))
|
||||||
return [Addresses(**row) for row in rows]
|
return [Addresses(**row) for row in rows]
|
||||||
|
@ -90,6 +89,7 @@ async def get_watch_wallet(wallet_id: str) -> Wallets:
|
||||||
row = await db.fetchone("SELECT * FROM wallets WHERE id = ?", (wallet_id,))
|
row = await db.fetchone("SELECT * FROM wallets WHERE id = ?", (wallet_id,))
|
||||||
return Wallets.from_row(row) if row else None
|
return Wallets.from_row(row) if row else None
|
||||||
|
|
||||||
|
|
||||||
async def get_watch_wallets(user: str) -> List[Wallets]:
|
async def get_watch_wallets(user: str) -> List[Wallets]:
|
||||||
rows = await db.fetchall("SELECT * FROM wallets WHERE user = ?", (user,))
|
rows = await db.fetchall("SELECT * FROM wallets WHERE user = ?", (user,))
|
||||||
return [Wallets(**row) for row in rows]
|
return [Wallets(**row) for row in rows]
|
||||||
|
@ -108,24 +108,25 @@ async def delete_watch_wallet(wallet_id: str) -> None:
|
||||||
|
|
||||||
###############PAYMENTS##########################
|
###############PAYMENTS##########################
|
||||||
|
|
||||||
async def create_payment(*, user: str, ex_key: str, description: str, amount: int) -> Payments:
|
async def create_payment(*, walletid: str, user: str, title: str, time: str, amount: int) -> Payments:
|
||||||
|
|
||||||
address = await get_fresh_address(ex_key)
|
address = await get_fresh_address(walletid)
|
||||||
payment_id = urlsafe_short_hash()
|
payment_id = urlsafe_short_hash()
|
||||||
await db.execute(
|
await db.execute(
|
||||||
"""
|
"""
|
||||||
INSERT INTO payments (
|
INSERT INTO payments (
|
||||||
payment_id,
|
id,
|
||||||
user,
|
user,
|
||||||
ex_key,
|
title,
|
||||||
|
wallet,
|
||||||
address,
|
address,
|
||||||
|
time_to_pay,
|
||||||
amount
|
amount
|
||||||
)
|
)
|
||||||
VALUES (?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||||
""",
|
""",
|
||||||
(payment_id, user, ex_key, address, amount),
|
(payment_id, user, title, walletid, address.address, time, amount),
|
||||||
)
|
)
|
||||||
payment_id = db.cursor.lastrowid
|
|
||||||
return await get_payment(payment_id)
|
return await get_payment(payment_id)
|
||||||
|
|
||||||
|
|
||||||
|
@ -136,6 +137,7 @@ async def get_payment(payment_id: str) -> Payments:
|
||||||
|
|
||||||
async def get_payments(user: str) -> List[Payments]:
|
async def get_payments(user: str) -> List[Payments]:
|
||||||
rows = await db.fetchall("SELECT * FROM payments WHERE user IN ?", (user,))
|
rows = await db.fetchall("SELECT * FROM payments WHERE user IN ?", (user,))
|
||||||
|
print(rows[0])
|
||||||
return [Payments.from_row(row) for row in rows]
|
return [Payments.from_row(row) for row in rows]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,8 @@ async def m001_initial(db):
|
||||||
CREATE TABLE IF NOT EXISTS payments (
|
CREATE TABLE IF NOT EXISTS payments (
|
||||||
id TEXT NOT NULL PRIMARY KEY,
|
id TEXT NOT NULL PRIMARY KEY,
|
||||||
user TEXT,
|
user TEXT,
|
||||||
masterpub TEXT NOT NULL,
|
title TEXT,
|
||||||
|
wallet TEXT NOT NULL,
|
||||||
address TEXT NOT NULL,
|
address TEXT NOT NULL,
|
||||||
time_to_pay INTEGER NOT NULL,
|
time_to_pay INTEGER NOT NULL,
|
||||||
amount INTEGER NOT NULL,
|
amount INTEGER NOT NULL,
|
||||||
|
|
|
@ -16,7 +16,8 @@ class Wallets(NamedTuple):
|
||||||
class Payments(NamedTuple):
|
class Payments(NamedTuple):
|
||||||
id: str
|
id: str
|
||||||
user: str
|
user: str
|
||||||
ex_key: str
|
wallet: str
|
||||||
|
title: str
|
||||||
address: str
|
address: str
|
||||||
time_to_pay: str
|
time_to_pay: str
|
||||||
amount: int
|
amount: int
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<q-card>
|
<q-card>
|
||||||
<q-card-section>
|
<q-card-section>
|
||||||
<p>The WatchOnly extension uses https://mempool.block for blockchain data.<br />
|
<p>The WatchOnly extension uses https://mempool.space for blockchain data.<br />
|
||||||
<small>
|
<small>
|
||||||
Created by, <a href="https://github.com/benarc">Ben Arc</a></small
|
Created by, <a href="https://github.com/benarc">Ben Arc</a></small
|
||||||
>
|
>
|
||||||
|
|
|
@ -89,7 +89,7 @@
|
||||||
size="xs"
|
size="xs"
|
||||||
icon="toll"
|
icon="toll"
|
||||||
:color="($q.dark.isActive) ? 'grey-7' : 'grey-5'"
|
:color="($q.dark.isActive) ? 'grey-7' : 'grey-5'"
|
||||||
@click="formDialogPayment.show = true"
|
@click="formDialogPayment.show = true, formDialogPayment.data.walletid = props.row.id"
|
||||||
>
|
>
|
||||||
|
|
||||||
<q-tooltip>
|
<q-tooltip>
|
||||||
|
@ -157,20 +157,20 @@
|
||||||
<q-icon name="search"></q-icon>
|
<q-icon name="search"></q-icon>
|
||||||
</template>
|
</template>
|
||||||
</q-input>
|
</q-input>
|
||||||
{% endraw %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<q-table
|
<q-table
|
||||||
flat
|
flat
|
||||||
dense
|
dense
|
||||||
:data="payLinks"
|
:data="paymentLinks"
|
||||||
row-key="id"
|
row-key="id"
|
||||||
:columns="PaylinksTable.columns"
|
:columns="PaymentsTable.columns"
|
||||||
:pagination.sync="PaylinksTable.pagination"
|
:pagination.sync="PaymentsTable.pagination"
|
||||||
:filter="filter"
|
:filter="filter"
|
||||||
>
|
>
|
||||||
|
|
||||||
{% raw %}
|
|
||||||
<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 auto-width></q-th>
|
||||||
|
@ -360,21 +360,21 @@
|
||||||
<h5 class="text-subtitle1 q-my-none">Addresses</h5>
|
<h5 class="text-subtitle1 q-my-none">Addresses</h5>
|
||||||
<q-separator></q-separator><br/>
|
<q-separator></q-separator><br/>
|
||||||
<p><strong>Current:</strong>
|
<p><strong>Current:</strong>
|
||||||
{{ Addresses.data[0].address }}
|
{{ currentaddress }}
|
||||||
<q-btn
|
<q-btn
|
||||||
flat
|
flat
|
||||||
dense
|
dense
|
||||||
size="ms"
|
size="ms"
|
||||||
icon="visibility"
|
icon="visibility"
|
||||||
type="a"
|
type="a"
|
||||||
:href="mempool.endpoint + '/address/' + Addresses.data[0].address"
|
:href="mempool.endpoint + '/address/' + currentaddress"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
></q-btn>
|
></q-btn>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<q-responsive :ratio="1" class="q-mx-xl q-mb-md">
|
<q-responsive :ratio="1" class="q-mx-xl q-mb-md">
|
||||||
<qrcode
|
<qrcode
|
||||||
:value="Addresses.data[0].address"
|
:value="currentaddress"
|
||||||
:options="{width: 800}"
|
:options="{width: 800}"
|
||||||
class="rounded-borders"
|
class="rounded-borders"
|
||||||
></qrcode>
|
></qrcode>
|
||||||
|
@ -382,7 +382,7 @@
|
||||||
<p style="word-break: break-all;">
|
<p style="word-break: break-all;">
|
||||||
|
|
||||||
<q-scroll-area style="height: 200px; max-width: 100%;">
|
<q-scroll-area style="height: 200px; max-width: 100%;">
|
||||||
<q-list bordered v-for="data in Addresses.data">
|
<q-list bordered v-for="data in Addresses.data.slice().reverse()">
|
||||||
<q-item>
|
<q-item>
|
||||||
<q-item-section>{{ data.address }}</q-item-section>
|
<q-item-section>{{ data.address }}</q-item-section>
|
||||||
<q-btn
|
<q-btn
|
||||||
|
@ -424,7 +424,10 @@
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
Vue.component(VueQrcode.name, VueQrcode)
|
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 = [
|
var locationPath = [
|
||||||
window.location.protocol,
|
window.location.protocol,
|
||||||
'//',
|
'//',
|
||||||
|
@ -440,6 +443,15 @@
|
||||||
)
|
)
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
var mapPayment = function (obj) {
|
||||||
|
obj._data = _.clone(obj)
|
||||||
|
obj.date = Quasar.utils.date.formatDate(
|
||||||
|
new Date(obj.time * 1000),
|
||||||
|
'YYYY-MM-DD HH:mm'
|
||||||
|
)
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
new Vue({
|
new Vue({
|
||||||
el: '#vue',
|
el: '#vue',
|
||||||
|
@ -449,7 +461,8 @@
|
||||||
filter: '',
|
filter: '',
|
||||||
checker: null,
|
checker: null,
|
||||||
walletLinks: [],
|
walletLinks: [],
|
||||||
current: {},
|
paymentLinks: [],
|
||||||
|
currentaddress: "",
|
||||||
Addresses: {
|
Addresses: {
|
||||||
show: false,
|
show: false,
|
||||||
data: null
|
data: null
|
||||||
|
@ -483,7 +496,7 @@
|
||||||
rowsPerPage: 10
|
rowsPerPage: 10
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
PaylinksTable: {
|
PaymentsTable: {
|
||||||
columns: [
|
columns: [
|
||||||
{name: 'id', align: 'left', label: 'ID', field: 'id'},
|
{name: 'id', align: 'left', label: 'ID', field: 'id'},
|
||||||
{
|
{
|
||||||
|
@ -555,10 +568,12 @@
|
||||||
)
|
)
|
||||||
.then(function (response) {
|
.then(function (response) {
|
||||||
|
|
||||||
self.walletLinks = response.data.map(function (obj) {
|
|
||||||
self.Addresses.data = response.data
|
self.Addresses.data = response.data
|
||||||
|
self.currentaddress = self.Addresses.data[self.Addresses.data.length - 1].address
|
||||||
|
console.log(self.currentaddress)
|
||||||
|
|
||||||
})
|
})
|
||||||
})
|
|
||||||
.catch(function (error) {
|
.catch(function (error) {
|
||||||
LNbits.utils.notifyApiError(error)
|
LNbits.utils.notifyApiError(error)
|
||||||
})
|
})
|
||||||
|
@ -573,13 +588,12 @@
|
||||||
this.g.user.wallets[0].inkey
|
this.g.user.wallets[0].inkey
|
||||||
)
|
)
|
||||||
.then(function (response) {
|
.then(function (response) {
|
||||||
self.Addresses.show = false
|
console.log(response.data)
|
||||||
getAddresses(walletID)
|
self.Addresses.data = response.data
|
||||||
|
self.currentaddress = self.Addresses.data[self.Addresses.data.length - 1].address
|
||||||
|
|
||||||
})
|
})
|
||||||
.catch(function (error) {
|
|
||||||
LNbits.utils.notifyApiError(error)
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
addressRedirect: function (address){
|
addressRedirect: function (address){
|
||||||
window.location.href = this.mempool.endpoint + "/address/" + address;
|
window.location.href = this.mempool.endpoint + "/address/" + address;
|
||||||
|
@ -645,11 +659,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
openQrCodeDialog: function (linkId) {
|
openQrCodeDialog: function (linkId) {
|
||||||
|
var self = this
|
||||||
var getAddresses = this.getAddresses
|
var getAddresses = this.getAddresses
|
||||||
getAddresses(linkId)
|
getAddresses(linkId)
|
||||||
this.current = linkId
|
self.current = linkId
|
||||||
this.Addresses.show = true
|
self.Addresses.show = true
|
||||||
},
|
},
|
||||||
|
|
||||||
openUpdateDialog: function (linkId) {
|
openUpdateDialog: function (linkId) {
|
||||||
var link = _.findWhere(this.walletLinks, {id: linkId})
|
var link = _.findWhere(this.walletLinks, {id: linkId})
|
||||||
this.formDialog.data = _.clone(link._data)
|
this.formDialog.data = _.clone(link._data)
|
||||||
|
@ -665,22 +681,36 @@
|
||||||
this.createWalletLink(wallet, data)
|
this.createWalletLink(wallet, data)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
sendFormDataPayLink: function () {
|
|
||||||
var wallet = this.g.user.wallets[0]
|
|
||||||
var data = _.omit(this.formDialogPayLink.data, 'wallet')
|
|
||||||
|
|
||||||
data.wait_time =
|
getPayments: function () {
|
||||||
data.wait_time *
|
var self = this
|
||||||
{
|
|
||||||
seconds: 1,
|
|
||||||
minutes: 60,
|
|
||||||
hours: 3600
|
|
||||||
}[this.formDialogPayLink.secondMultiplier]
|
|
||||||
|
|
||||||
|
LNbits.api
|
||||||
|
.request(
|
||||||
|
'GET',
|
||||||
|
'/watchonly/api/v1/payment',
|
||||||
|
this.g.user.wallets[0].inkey
|
||||||
|
)
|
||||||
|
.then(function (response) {
|
||||||
|
self.paymentLinks = response.data.map(function (obj) {
|
||||||
|
return mapPayment(obj)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
LNbits.utils.notifyApiError(error)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
sendFormDataPayment: function () {
|
||||||
|
var self = this
|
||||||
|
var wallet = self.g.user.wallets[0]
|
||||||
|
var data = self.formDialogPayment.data
|
||||||
|
data.amount = parseInt(data.amount)
|
||||||
|
data.time = parseInt(data.time)
|
||||||
|
console.log(data)
|
||||||
if (data.id) {
|
if (data.id) {
|
||||||
this.updatePayLink(wallet, data)
|
this.updatePayment(wallet, data)
|
||||||
} else {
|
} else {
|
||||||
this.createPayLink(wallet, data)
|
this.createPayment(wallet, data)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updatePayment: function (wallet, data) {
|
updatePayment: function (wallet, data) {
|
||||||
|
@ -695,7 +725,7 @@
|
||||||
self.payment = _.reject(self.payment, function (obj) {
|
self.payment = _.reject(self.payment, function (obj) {
|
||||||
return obj.id === data.id
|
return obj.id === data.id
|
||||||
})
|
})
|
||||||
self.payment.push(mapWalletLink(response.data))
|
self.payment.push(mapPayment(response.data))
|
||||||
self.formDialogPayLink.show = false
|
self.formDialogPayLink.show = false
|
||||||
})
|
})
|
||||||
.catch(function (error) {
|
.catch(function (error) {
|
||||||
|
@ -708,14 +738,15 @@
|
||||||
LNbits.api
|
LNbits.api
|
||||||
.request('POST', '/watchonly/api/v1/payment', wallet.inkey, data)
|
.request('POST', '/watchonly/api/v1/payment', wallet.inkey, data)
|
||||||
.then(function (response) {
|
.then(function (response) {
|
||||||
self.payment.push(mapWalletLink(response.data))
|
self.paymentLinks.push(mapPayment(response.data))
|
||||||
self.formDialogPayLink.show = false
|
self.formDialogPayment.show = false
|
||||||
console.log(response.data[1][1])
|
console.log(response.data)
|
||||||
})
|
})
|
||||||
.catch(function (error) {
|
.catch(function (error) {
|
||||||
LNbits.utils.notifyApiError(error)
|
LNbits.utils.notifyApiError(error)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
deletePayment: function (linkId) {
|
deletePayment: function (linkId) {
|
||||||
var self = this
|
var self = this
|
||||||
var link = _.findWhere(this.payment, {id: linkId})
|
var link = _.findWhere(this.payment, {id: linkId})
|
||||||
|
@ -803,6 +834,8 @@
|
||||||
if (this.g.user.wallets.length) {
|
if (this.g.user.wallets.length) {
|
||||||
var getWalletLinks = this.getWalletLinks
|
var getWalletLinks = this.getWalletLinks
|
||||||
getWalletLinks()
|
getWalletLinks()
|
||||||
|
var getPayments = this.getPayments
|
||||||
|
getPayments()
|
||||||
var getMempool = this.getMempool
|
var getMempool = this.getMempool
|
||||||
getMempool()
|
getMempool()
|
||||||
|
|
||||||
|
|
|
@ -120,8 +120,10 @@ async def api_get_addresses(wallet_id):
|
||||||
async def api_payments_retrieve():
|
async def api_payments_retrieve():
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
payments = await get_payments(g.wallet.user)
|
||||||
|
print(payments)
|
||||||
return (
|
return (
|
||||||
jsonify(get_payments(g.wallet.user)),
|
jsonify(payments),
|
||||||
HTTPStatus.OK,
|
HTTPStatus.OK,
|
||||||
)
|
)
|
||||||
except:
|
except:
|
||||||
|
@ -146,21 +148,21 @@ async def api_payment_retrieve(payment_id):
|
||||||
@api_check_wallet_key("invoice")
|
@api_check_wallet_key("invoice")
|
||||||
@api_validate_post_request(
|
@api_validate_post_request(
|
||||||
schema={
|
schema={
|
||||||
"ex_key": {"type": "string", "empty": False, "required": True},
|
"walletid": {"type": "string", "empty": False, "required": True},
|
||||||
"pub_key": {"type": "string", "empty": False, "required": True},
|
"title": {"type": "string", "empty": False, "required": True},
|
||||||
"time_to_pay": {"type": "integer", "min": 1, "required": True},
|
"time": {"type": "integer", "min": 1, "required": True},
|
||||||
"amount": {"type": "integer", "min": 1, "required": True},
|
"amount": {"type": "integer", "min": 1, "required": True},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
async def api_payment_create_or_update(payment_id=None):
|
async def api_payment_create_or_update(payment_id=None):
|
||||||
|
|
||||||
if not payment_id:
|
if not payment_id:
|
||||||
payment = await create_payment(g.wallet.user, g.data.ex_key, g.data.pub_key, g.data.amount)
|
payment = await create_payment(user = g.wallet.user, **g.data)
|
||||||
return jsonify(get_payment(payment)), HTTPStatus.CREATED
|
return jsonify(payment), HTTPStatus.CREATED
|
||||||
|
|
||||||
else:
|
else:
|
||||||
payment = await update_payment(payment_id, g.data)
|
payment = await update_payment(user = g.wallet.user, **g.data)
|
||||||
return jsonify({payment}), HTTPStatus.OK
|
return jsonify(payment), HTTPStatus.OK
|
||||||
|
|
||||||
|
|
||||||
@watchonly_ext.route("/api/v1/payment/<payment_id>", methods=["DELETE"])
|
@watchonly_ext.route("/api/v1/payment/<payment_id>", methods=["DELETE"])
|
||||||
|
|
Loading…
Add table
Reference in a new issue