generated fresh addresses nicely

This commit is contained in:
benarc 2020-12-03 17:26:11 +00:00
parent 48cf23346c
commit c62678b3aa
7 changed files with 97 additions and 57 deletions

View file

@ -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"

View file

@ -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]

View file

@ -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,

View file

@ -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

View file

@ -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
> >

View file

@ -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()

View file

@ -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"])