From 54c0c9f3a8457ae3b179ce04b16e3ee9720885d8 Mon Sep 17 00:00:00 2001 From: benarc Date: Fri, 4 Dec 2020 09:59:42 +0000 Subject: [PATCH] Big, broken refactor payments/addresses to charges --- lnbits/extensions/watchonly/crud.py | 90 +++----- lnbits/extensions/watchonly/migrations.py | 16 +- lnbits/extensions/watchonly/models.py | 15 +- .../watchonly/templates/watchonly/index.html | 196 +++++++----------- lnbits/extensions/watchonly/views.py | 2 +- lnbits/extensions/watchonly/views_api.py | 104 +++------- 6 files changed, 142 insertions(+), 281 deletions(-) diff --git a/lnbits/extensions/watchonly/crud.py b/lnbits/extensions/watchonly/crud.py index 312c38abe..d58e28da0 100644 --- a/lnbits/extensions/watchonly/crud.py +++ b/lnbits/extensions/watchonly/crud.py @@ -2,7 +2,7 @@ from typing import List, Optional, Union #from lnbits.db import open_ext_db from . import db -from .models import Wallets, Payments, Addresses, Mempool +from .models import Wallets, charges, Addresses, Mempool from lnbits.helpers import urlsafe_short_hash @@ -20,46 +20,7 @@ from embit import script from embit import ec from embit.networks import NETWORKS from binascii import unhexlify, hexlify, a2b_base64, b2a_base64 - -########################ADDRESSES####################### - -async def get_derive_address(wallet_id: str, num: int): - - wallet = await get_watch_wallet(wallet_id) - k = bip32.HDKey.from_base58(str(wallet[2])) - child = k.derive([0, num]) - address = script.p2wpkh(child).address() - - return address - -async def get_fresh_address(wallet_id: str) -> Addresses: - wallet = await get_watch_wallet(wallet_id) - - address = await get_derive_address(wallet_id, wallet[4] + 1) - - await update_watch_wallet(wallet_id = wallet_id, address_no = wallet[4] + 1) - await db.execute( - """ - INSERT INTO addresses ( - address, - wallet, - amount - ) - VALUES (?, ?, ?) - """, - (address, wallet_id, 0), - ) - - return await get_address(address) - - -async def get_address(address: str) -> Addresses: - row = await db.fetchone("SELECT * FROM addresses WHERE address = ?", (address,)) - return Addresses.from_row(row) if row else None - -async def get_addresses(wallet_id: str) -> List[Addresses]: - rows = await db.fetchall("SELECT * FROM addresses WHERE wallet = ?", (wallet_id,)) - return [Addresses(**row) for row in rows] +import requests ##########################WALLETS#################### @@ -74,7 +35,7 @@ async def create_watch_wallet(*, user: str, masterpub: str, title: str) -> Walle masterpub, title, address_no, - amount + balance ) VALUES (?, ?, ?, ?, ?, ?) """, @@ -106,43 +67,56 @@ async def delete_watch_wallet(wallet_id: str) -> None: await db.execute("DELETE FROM wallets WHERE id = ?", (wallet_id,)) -###############PAYMENTS########################## +###############charges########################## -async def create_payment(*, walletid: str, user: str, title: str, time: str, amount: int) -> Payments: +async def create_charge(*, walletid: str, user: str, title: str, time: str, amount: int) -> charges: address = await get_fresh_address(walletid) - payment_id = urlsafe_short_hash() + charge_id = urlsafe_short_hash() await db.execute( """ - INSERT INTO payments ( + INSERT INTO charges ( id, user, title, wallet, address, time_to_pay, - amount + amount, + balance ) - VALUES (?, ?, ?, ?, ?, ?, ?) + VALUES (?, ?, ?, ?, ?, ?, ?, ?) """, - (payment_id, user, title, walletid, address.address, time, amount), + (charge_id, user, title, walletid, address.address, time, amount, 0), ) - return await get_payment(payment_id) + return await get_charge(charge_id) -async def get_payment(payment_id: str) -> Payments: - row = await db.fetchone("SELECT * FROM payments WHERE id = ?", (payment_id,)) - return Payments.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_payments(user: str) -> List[Payments]: - rows = await db.fetchall("SELECT * FROM payments WHERE user = ?", (user,)) - return [Payments.from_row(row) for row in rows] +async def get_charges(user: str) -> List[charges]: + rows = await db.fetchall("SELECT * FROM charges WHERE user = ?", (user,)) + for row in rows: + await check_address_balance(row.address) + rows = await db.fetchall("SELECT * FROM charges WHERE user = ?", (user,)) + return [charges.from_row(row) for row in rows] -async def delete_payment(payment_id: str) -> None: - await db.execute("DELETE FROM payments WHERE id = ?", (payment_id,)) +async def delete_charge(charge_id: str) -> None: + await db.execute("DELETE FROM charges WHERE id = ?", (charge_id,)) +async def check_address_balance(address: str) -> List[Addresses]: + address_data = await get_address(address) + mempool = await get_mempool(address_data.user) + r = requests.get(mempool.endpoint + "/api/address/" + address) + amount_paid = r.json()['chain_stats']['funded_txo_sum'] - r.json()['chain_stats']['spent_txo_sum'] + print(amount_paid) + await db.execute("UPDATE addresses SET amount_paid = ? WHERE address = ?", (amount_paid, address)) + row = await db.fetchone("SELECT * FROM addresses WHERE address = ?", (address,)) + return Addresses.from_row(row) if row else None ######################MEMPOOL####################### diff --git a/lnbits/extensions/watchonly/migrations.py b/lnbits/extensions/watchonly/migrations.py index 51d22b808..7bc632f5d 100644 --- a/lnbits/extensions/watchonly/migrations.py +++ b/lnbits/extensions/watchonly/migrations.py @@ -10,24 +10,14 @@ async def m001_initial(db): masterpub TEXT NOT NULL, title TEXT NOT NULL, address_no INTEGER NOT NULL DEFAULT 0, - amount INTEGER NOT NULL + balance INTEGER NOT NULL ); """ ) await db.execute( """ - CREATE TABLE IF NOT EXISTS addresses ( - address TEXT NOT NULL PRIMARY KEY, - wallet TEXT NOT NULL, - amount INTEGER NOT NULL - ); - """ - ) - - await db.execute( - """ - CREATE TABLE IF NOT EXISTS payments ( + CREATE TABLE IF NOT EXISTS charges ( id TEXT NOT NULL PRIMARY KEY, user TEXT, title TEXT, @@ -35,7 +25,7 @@ async def m001_initial(db): address TEXT NOT NULL, time_to_pay INTEGER NOT NULL, amount INTEGER NOT NULL, - amount_paid INTEGER DEFAULT 0, + balance INTEGER DEFAULT 0, time TIMESTAMP NOT NULL DEFAULT (strftime('%s', 'now')) ); """ diff --git a/lnbits/extensions/watchonly/models.py b/lnbits/extensions/watchonly/models.py index 968d1c372..57f411676 100644 --- a/lnbits/extensions/watchonly/models.py +++ b/lnbits/extensions/watchonly/models.py @@ -7,13 +7,13 @@ class Wallets(NamedTuple): masterpub: str title: str address_no: int - amount: int + balance: int @classmethod def from_row(cls, row: Row) -> "Wallets": return cls(**dict(row)) -class Payments(NamedTuple): +class Charges(NamedTuple): id: str user: str wallet: str @@ -21,22 +21,13 @@ class Payments(NamedTuple): address: str time_to_pay: str amount: int - amount_paid: int + balance: int time: int @classmethod def from_row(cls, row: Row) -> "Payments": return cls(**dict(row)) -class Addresses(NamedTuple): - address: str - wallet: str - amount: int - - @classmethod - def from_row(cls, row: Row) -> "Addresses": - return cls(**dict(row)) - class Mempool(NamedTuple): user: str endpoint: str diff --git a/lnbits/extensions/watchonly/templates/watchonly/index.html b/lnbits/extensions/watchonly/templates/watchonly/index.html index 57cf7e74f..c60d7e433 100644 --- a/lnbits/extensions/watchonly/templates/watchonly/index.html +++ b/lnbits/extensions/watchonly/templates/watchonly/index.html @@ -89,11 +89,11 @@ size="xs" icon="toll" :color="($q.dark.isActive) ? 'grey-7' : 'grey-5'" - @click="formDialogPayment.show = true, formDialogPayment.data.walletid = props.row.id" + @click="formDialogCharge.show = true, formDialogCharge.data.walletid = props.row.id" > - Payment link + Charge link @@ -190,6 +190,33 @@ + + + + + + + + + -
@@ -217,7 +243,6 @@
-
{% endraw %} @@ -299,14 +324,14 @@ - + - + @@ -314,7 +339,7 @@ @@ -322,14 +347,14 @@
Create Paylink @@ -444,7 +469,7 @@ ) return obj } - var mapPayment = function (obj) { + var mapCharge = function (obj) { obj._data = _.clone(obj) obj.date = Quasar.utils.date.formatDate( new Date(obj.time * 1000), @@ -463,7 +488,7 @@ balance: null, checker: null, walletLinks: [], - paymentLinks: [], + ChargeLinks: [], currentaddress: "", Addresses: { show: false, @@ -498,7 +523,7 @@ rowsPerPage: 10 } }, - PaymentsTable: { + ChargesTable: { columns: [ {name: 'id', align: 'left', label: 'ID', field: 'id'}, { @@ -510,14 +535,14 @@ { name: 'amount', align: 'left', - label: 'Amount', + label: 'Amount to pay', field: 'amount' }, { name: 'balance', align: 'left', - label: 'Paid', - field: 'getAddressBalance("1wizSAYSbuyXbt9d8JV8ytm5acqq2TorC")' + label: 'Balance', + field: 'amount_paid' }, { name: 'address', @@ -528,13 +553,13 @@ { name: 'time to pay', align: 'left', - label: 'Time to Pay (secs)', + label: 'Time to Pay', field: 'time_to_pay' }, { name: 'timeleft', align: 'left', - label: 'Time left (secs)', + label: 'Time left', field: 'timeleft' }, ], @@ -542,30 +567,11 @@ rowsPerPage: 10 } }, - AddressTable: { - columns: [ - { - name: 'address', - align: 'left', - label: 'Address', - field: 'address' - }, - { - name: 'amount', - align: 'left', - label: 'Amount', - field: 'amount' - }, - ], - pagination: { - rowsPerPage: 10 - } - }, formDialog: { show: false, data: {} }, - formDialogPayment: { + formDialogCharge: { show: false, data: {} }, @@ -579,45 +585,7 @@ methods: { - getAddresses: function (walletID) { - var self = this - - LNbits.api - .request( - 'GET', - '/watchonly/api/v1/addresses/' + walletID, - this.g.user.wallets[0].inkey - ) - .then(function (response) { - - self.Addresses.data = response.data - self.currentaddress = self.Addresses.data[self.Addresses.data.length - 1].address - console.log(self.currentaddress) - - }) - - .catch(function (error) { - LNbits.utils.notifyApiError(error) - }) - }, - getFreshAddress: function (walletID) { - var self = this - - LNbits.api - .request( - 'GET', - '/watchonly/api/v1/address/' + walletID, - this.g.user.wallets[0].inkey - ) - .then(function (response) { - console.log(response.data) - self.Addresses.data = response.data - self.currentaddress = self.Addresses.data[self.Addresses.data.length - 1].address - - }) - - }, - addressRedirect: function (address){ + chargeRedirect: function (address){ window.location.href = this.mempool.endpoint + "/address/" + address; }, getMempool: function () { @@ -703,14 +671,14 @@ } }, - getPayments: function () { + getCharges: function () { var self = this var getAddressBalance = this.getAddressBalance LNbits.api .request( 'GET', - '/watchonly/api/v1/payment', + '/watchonly/api/v1/ChargeLinks', this.g.user.wallets[0].inkey ) .then(function (response) { @@ -724,67 +692,64 @@ else{ response.data[i].timeleft = timeleft } - getAddressBalance("1wizSAYSbuyXbt9d8JV8ytm5acqq2TorC") - console.log(this.balance) - response.data[i].balance = this.balance } - self.paymentLinks = response.data.map(function (obj) { - return mapPayment(obj) + self.ChargeLinks = response.data.map(function (obj) { + return mapCharge(obj) }) }) .catch(function (error) { LNbits.utils.notifyApiError(error) }) }, - sendFormDataPayment: function () { + sendFormDataCharge: function () { var self = this var wallet = self.g.user.wallets[0] - var data = self.formDialogPayment.data + var data = self.formDialogCharge.data data.amount = parseInt(data.amount) data.time = parseInt(data.time) if (data.id) { - this.updatePayment(wallet, data) + this.updateCharge(wallet, data) } else { - this.createPayment(wallet, data) + this.createCharge(wallet, data) } }, - updatePayment: function (wallet, data) { + updateCharge: function (wallet, data) { var self = this LNbits.api .request( 'PUT', - '/watchonly/api/v1/payment/' + data.id, + '/watchonly/api/v1/Charge/' + data.id, wallet.inkey, data) .then(function (response) { - self.payment = _.reject(self.payment, function (obj) { + self.Charge = _.reject(self.Charge, function (obj) { return obj.id === data.id }) - self.payment.push(mapPayment(response.data)) + self.Charge.push(mapCharge(response.data)) self.formDialogPayLink.show = false }) .catch(function (error) { LNbits.utils.notifyApiError(error) }) }, - createPayment: function (wallet, data) { + createCharge: function (wallet, data) { var self = this LNbits.api - .request('POST', '/watchonly/api/v1/payment', wallet.inkey, data) + .request('POST', '/watchonly/api/v1/Charge', wallet.inkey, data) .then(function (response) { - self.paymentLinks.push(mapPayment(response.data)) - self.formDialogPayment.show = false + self.ChargeLinks.push(mapCharge(response.data)) + self.formDialogCharge.show = false }) .catch(function (error) { LNbits.utils.notifyApiError(error) }) }, - deletePayment: function (linkId) { + deleteCharge: function (linkId) { var self = this - var link = _.findWhere(this.payment, {id: linkId}) + 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?') @@ -792,11 +757,11 @@ LNbits.api .request( 'DELETE', - '/watchonly/api/v1/payment/' + linkId, + '/watchonly/api/v1/Charge/' + linkId, self.g.user.wallets[0].inkey ) .then(function (response) { - self.payment = _.reject(self.payment, function (obj) { + self.Charge = _.reject(self.Charge, function (obj) { return obj.id === linkId })}) .catch(function (error) { @@ -804,24 +769,7 @@ }) }) }, - getAddressBalance: function (address) { - var self = this - LNbits.api - .request( - 'GET', - '/watchonly/api/v1/mempool/' + address, - this.g.user.wallets[0].inkey - ) - .then(function (response) { - this.balance = response.data.balance - console.log(this.balance) - - }) - .catch(function (error) { - LNbits.utils.notifyApiError(error) - }) - }, updateWalletLink: function (wallet, data) { var self = this @@ -886,8 +834,8 @@ if (this.g.user.wallets.length) { var getWalletLinks = this.getWalletLinks getWalletLinks() - var getPayments = this.getPayments - getPayments() + var getCharges = this.getCharges + getCharges() var getMempool = this.getMempool getMempool() diff --git a/lnbits/extensions/watchonly/views.py b/lnbits/extensions/watchonly/views.py index ceaf6822e..dc7417952 100644 --- a/lnbits/extensions/watchonly/views.py +++ b/lnbits/extensions/watchonly/views.py @@ -14,7 +14,7 @@ async def index(): return await render_template("watchonly/index.html", user=g.user) -@watchonly_ext.route("/") +@watchonly_ext.route("/") async def display(payment_id): link = get_payment(payment_id) or abort(HTTPStatus.NOT_FOUND, "Pay link does not exist.") diff --git a/lnbits/extensions/watchonly/views_api.py b/lnbits/extensions/watchonly/views_api.py index 62b36154b..bdb297aec 100644 --- a/lnbits/extensions/watchonly/views_api.py +++ b/lnbits/extensions/watchonly/views_api.py @@ -2,7 +2,7 @@ import hashlib from quart import g, jsonify, request, url_for from http import HTTPStatus import httpx -import requests + from lnbits.core.crud import get_user from lnbits.decorators import api_check_wallet_key, api_validate_post_request @@ -14,10 +14,10 @@ from .crud import ( get_watch_wallets, update_watch_wallet, delete_watch_wallet, - create_payment, - get_payment, - get_payments, - delete_payment, + create_charge, + get_charge, + get_charges, + delete_charge, create_mempool, update_mempool, get_mempool, @@ -85,67 +85,35 @@ async def api_wallet_delete(wallet_id): return jsonify({"deleted": "true"}), HTTPStatus.NO_CONTENT -#############################ADDRESSES########################## +#############################CHARGES########################## -@watchonly_ext.route("/api/v1/address/", methods=["GET"]) +@watchonly_ext.route("/api/v1/charges", methods=["GET"]) @api_check_wallet_key("invoice") -async def api_fresh_address(wallet_id): - await get_fresh_address(wallet_id) - - addresses = await get_addresses(wallet_id) +async def api_charges_retrieve(): - return jsonify([address._asdict() for address in addresses]), HTTPStatus.OK - - -@watchonly_ext.route("/api/v1/addresses/", methods=["GET"]) -@api_check_wallet_key("invoice") -async def api_get_addresses(wallet_id): - print(wallet_id) - - wallet = await get_watch_wallet(wallet_id) - - if not wallet: - return jsonify({"message": "wallet does not exist"}), HTTPStatus.NOT_FOUND - - addresses = await get_addresses(wallet_id) - - if not addresses: - await get_fresh_address(wallet_id) - addresses = await get_addresses(wallet_id) - - return jsonify([address._asdict() for address in addresses]), HTTPStatus.OK - - -#############################PAYEMENTS########################## - -@watchonly_ext.route("/api/v1/payment", methods=["GET"]) -@api_check_wallet_key("invoice") -async def api_payments_retrieve(): - - payments = await get_payments(g.wallet.user) - print(payments) - if not payments: + charges = await get_charges(g.wallet.user) + if not charges: return ( jsonify(""), HTTPStatus.OK ) else: - return jsonify([payment._asdict() for payment in payments]), HTTPStatus.OK + return jsonify([charge._asdict() for charge in charges]), HTTPStatus.OK -@watchonly_ext.route("/api/v1/payment/", methods=["GET"]) +@watchonly_ext.route("/api/v1/charge/", methods=["GET"]) @api_check_wallet_key("invoice") -async def api_payment_retrieve(payment_id): - payment = get_payment(payment_id) +async def api_charge_retrieve(charge_id): + charge = get_charge(charge_id) - if not payment: - return jsonify({"message": "payment does not exist"}), HTTPStatus.NOT_FOUND + if not charge: + return jsonify({"message": "charge does not exist"}), HTTPStatus.NOT_FOUND - return jsonify({payment}), HTTPStatus.OK + return jsonify({charge}), HTTPStatus.OK -@watchonly_ext.route("/api/v1/payment", methods=["POST"]) -@watchonly_ext.route("/api/v1/payment/", methods=["PUT"]) +@watchonly_ext.route("/api/v1/charge", methods=["POST"]) +@watchonly_ext.route("/api/v1/charge/", methods=["PUT"]) @api_check_wallet_key("invoice") @api_validate_post_request( schema={ @@ -155,26 +123,26 @@ async def api_payment_retrieve(payment_id): "amount": {"type": "integer", "min": 1, "required": True}, } ) -async def api_payment_create_or_update(payment_id=None): +async def api_charge_create_or_update(charge_id=None): - if not payment_id: - payment = await create_payment(user = g.wallet.user, **g.data) - return jsonify(payment), HTTPStatus.CREATED + if not charge_id: + charge = await create_charge(user = g.wallet.user, **g.data) + return jsonify(charge), HTTPStatus.CREATED else: - payment = await update_payment(user = g.wallet.user, **g.data) - return jsonify(payment), HTTPStatus.OK + charge = await update_charge(user = g.wallet.user, **g.data) + return jsonify(charge), HTTPStatus.OK -@watchonly_ext.route("/api/v1/payment/", methods=["DELETE"]) +@watchonly_ext.route("/api/v1/charge/", methods=["DELETE"]) @api_check_wallet_key("invoice") -async def api_payment_delete(payment_id): - payment = await get_watch_wallet(payment_id) +async def api_charge_delete(charge_id): + charge = await get_watch_wallet(charge_id) - if not payment: + if not charge: return jsonify({"message": "Wallet link does not exist."}), HTTPStatus.NOT_FOUND - await delete_watch_wallet(payment_id) + await delete_watch_wallet(charge_id) return "", HTTPStatus.NO_CONTENT @@ -197,14 +165,4 @@ 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 - -@watchonly_ext.route("/api/v1/mempool/
", methods=["GET"]) -@api_check_wallet_key("invoice") -async def api_get_mempool_address_balance(address): - mempool = await get_mempool(g.wallet.user) - print(mempool.endpoint) - r = requests.get(mempool.endpoint + "/api/address/" + address) - balance = r.json()['chain_stats']['funded_txo_sum'] - r.json()['chain_stats']['spent_txo_sum'] - - return jsonify({"balance":balance}), HTTPStatus.OK \ No newline at end of file + return jsonify(mempool._asdict()), HTTPStatus.OK \ No newline at end of file