From c8a33b0b93bb3e04bfb3d4ef1903cd1396fb3068 Mon Sep 17 00:00:00 2001 From: ben Date: Fri, 21 Oct 2022 20:06:50 +0100 Subject: [PATCH 01/83] Adding loads on gpios to switch --- lnbits/extensions/lnurldevice/lnurl.py | 5 +++-- lnbits/extensions/lnurldevice/tasks.py | 2 +- lnbits/extensions/lnurldevice/views.py | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lnbits/extensions/lnurldevice/lnurl.py b/lnbits/extensions/lnurldevice/lnurl.py index 79892b78a..c83db6b8b 100644 --- a/lnbits/extensions/lnurldevice/lnurl.py +++ b/lnbits/extensions/lnurldevice/lnurl.py @@ -91,6 +91,7 @@ async def lnurl_v1_params( device_id: str = Query(None), p: str = Query(None), atm: str = Query(None), + gpio: str = Query(None), ): device = await get_lnurldevice(device_id) if not device: @@ -114,7 +115,7 @@ async def lnurl_v1_params( deviceid=device.id, payload="bla", sats=price_msat, - pin=1, + pin=gpio, payhash="bla", ) if not lnurldevicepayment: @@ -236,7 +237,7 @@ async def lnurl_callback( amount=lnurldevicepayment.sats / 1000, memo=device.title + "-" + lnurldevicepayment.id, unhashed_description=(await device.lnurlpay_metadata()).encode("utf-8"), - extra={"tag": "Switch", "id": paymentid, "time": device.amount}, + extra={"tag": "Switch", "pin": ,"id": paymentid, "time": device.amount}, ) lnurldevicepayment = await update_lnurldevicepayment( lnurldevicepayment_id=paymentid, payhash=payment_hash diff --git a/lnbits/extensions/lnurldevice/tasks.py b/lnbits/extensions/lnurldevice/tasks.py index c8f3db04f..55cbaa986 100644 --- a/lnbits/extensions/lnurldevice/tasks.py +++ b/lnbits/extensions/lnurldevice/tasks.py @@ -36,5 +36,5 @@ async def on_invoice_paid(payment: Payment) -> None: lnurldevicepayment = await update_lnurldevicepayment( lnurldevicepayment_id=payment.extra.get("id"), payhash="used" ) - return await updater(lnurldevicepayment.deviceid) + return await updater(lnurldevicepayment.deviceid, lnurldevicepayment.pin) return diff --git a/lnbits/extensions/lnurldevice/views.py b/lnbits/extensions/lnurldevice/views.py index 5c6eba24b..d17db7d74 100644 --- a/lnbits/extensions/lnurldevice/views.py +++ b/lnbits/extensions/lnurldevice/views.py @@ -103,8 +103,8 @@ async def websocket_endpoint(websocket: WebSocket, lnurldevice_id: str): manager.disconnect(websocket) -async def updater(lnurldevice_id): +async def updater(lnurldevice_id, lnurldevice_pin): lnurldevice = await get_lnurldevice(lnurldevice_id) if not lnurldevice: return - await manager.send_personal_message(f"{lnurldevice.amount}", lnurldevice_id) + return await manager.send_personal_message(f"pin:{lnurldevice.pin},amount:{lnurldevice.amount}", lnurldevice_id) From 3552443f993d4cdf484912f72024401e767afa03 Mon Sep 17 00:00:00 2001 From: ben Date: Tue, 25 Oct 2022 11:10:34 +0100 Subject: [PATCH 02/83] adding migrations --- lnbits/extensions/lnurldevice/migrations.py | 25 +++++++++++++++++++++ lnbits/extensions/lnurldevice/models.py | 14 ++++++++++++ 2 files changed, 39 insertions(+) diff --git a/lnbits/extensions/lnurldevice/migrations.py b/lnbits/extensions/lnurldevice/migrations.py index 7305ccebe..52ecba7e5 100644 --- a/lnbits/extensions/lnurldevice/migrations.py +++ b/lnbits/extensions/lnurldevice/migrations.py @@ -88,3 +88,28 @@ async def m003_redux(db): await db.execute( "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount INT DEFAULT 0;" ) + +async def m004_redux(db): + """ + Add 'meta' for storing various metadata about the wallet + """ + await db.execute( + """ + ALTER TABLE lnurldevice.lnurldevices ADD COLUMN ( + amount1, + amount2, + amount3, + amount4, + time, + time1, + time2, + time3, + time4, + pin1, + pin2, + pin3, + pin4, + ) + INT DEFAULT 0; + """ + ) \ No newline at end of file diff --git a/lnbits/extensions/lnurldevice/models.py b/lnbits/extensions/lnurldevice/models.py index 01bcc2ba6..a4af4404a 100644 --- a/lnbits/extensions/lnurldevice/models.py +++ b/lnbits/extensions/lnurldevice/models.py @@ -18,6 +18,20 @@ class createLnurldevice(BaseModel): device: str profit: float amount: int + amount1: int + amount2: int + amount3: int + amount4: int + pin: int + pin1: int + pin2: int + pin3: int + pin4: int + time: int + time1: int + time2: int + time3: int + time4: int class lnurldevices(BaseModel): From e88b18a41746c028b125a96fef4d8c2afd89e584 Mon Sep 17 00:00:00 2001 From: ben Date: Tue, 25 Oct 2022 12:09:40 +0100 Subject: [PATCH 03/83] added migrate --- lnbits/extensions/lnurldevice/crud.py | 30 ++- lnbits/extensions/lnurldevice/lnurl.py | 8 +- lnbits/extensions/lnurldevice/migrations.py | 37 ++-- lnbits/extensions/lnurldevice/models.py | 30 ++- lnbits/extensions/lnurldevice/tasks.py | 2 +- .../templates/lnurldevice/index.html | 189 ++++++++++++++++-- lnbits/extensions/lnurldevice/views.py | 4 +- 7 files changed, 241 insertions(+), 59 deletions(-) diff --git a/lnbits/extensions/lnurldevice/crud.py b/lnbits/extensions/lnurldevice/crud.py index 4c25e4cb4..f9a13b58d 100644 --- a/lnbits/extensions/lnurldevice/crud.py +++ b/lnbits/extensions/lnurldevice/crud.py @@ -23,9 +23,22 @@ async def create_lnurldevice( currency, device, profit, - amount + amount, + pin, + profit1, + amount1, + pin1, + profit2, + amount2, + pin2, + profit3, + amount3, + pin3, + profit4, + amount4, + pin4, ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( lnurldevice_id, @@ -36,6 +49,19 @@ async def create_lnurldevice( data.device, data.profit, data.amount, + data.pin, + data.profit1, + data.amount1, + data.pin1, + data.profit2, + data.amount2, + data.pin2, + data.profit3, + data.amount3, + data.pin3, + data.profit4, + data.amount4, + data.pin4 ), ) return await get_lnurldevice(lnurldevice_id) diff --git a/lnbits/extensions/lnurldevice/lnurl.py b/lnbits/extensions/lnurldevice/lnurl.py index c83db6b8b..72749e855 100644 --- a/lnbits/extensions/lnurldevice/lnurl.py +++ b/lnbits/extensions/lnurldevice/lnurl.py @@ -92,6 +92,8 @@ async def lnurl_v1_params( p: str = Query(None), atm: str = Query(None), gpio: str = Query(None), + profit: str = Query(None), + amount: str = Query(None), ): device = await get_lnurldevice(device_id) if not device: @@ -106,14 +108,14 @@ async def lnurl_v1_params( if device.device == "switch": price_msat = ( - await fiat_amount_as_satoshis(float(device.profit), device.currency) + await fiat_amount_as_satoshis(float(profit), device.currency) if device.currency != "sat" else amount_in_cent ) * 1000 lnurldevicepayment = await create_lnurldevicepayment( deviceid=device.id, - payload="bla", + payload=amount, sats=price_msat, pin=gpio, payhash="bla", @@ -237,7 +239,7 @@ async def lnurl_callback( amount=lnurldevicepayment.sats / 1000, memo=device.title + "-" + lnurldevicepayment.id, unhashed_description=(await device.lnurlpay_metadata()).encode("utf-8"), - extra={"tag": "Switch", "pin": ,"id": paymentid, "time": device.amount}, + extra={"tag": "Switch", "pin": lnurldevicepayment.pin,"amount": int(lnurldevicepayment.payload),"id": paymentid}, ) lnurldevicepayment = await update_lnurldevicepayment( lnurldevicepayment_id=paymentid, payhash=payment_hash diff --git a/lnbits/extensions/lnurldevice/migrations.py b/lnbits/extensions/lnurldevice/migrations.py index 52ecba7e5..ebe453010 100644 --- a/lnbits/extensions/lnurldevice/migrations.py +++ b/lnbits/extensions/lnurldevice/migrations.py @@ -93,23 +93,20 @@ async def m004_redux(db): """ Add 'meta' for storing various metadata about the wallet """ - await db.execute( - """ - ALTER TABLE lnurldevice.lnurldevices ADD COLUMN ( - amount1, - amount2, - amount3, - amount4, - time, - time1, - time2, - time3, - time4, - pin1, - pin2, - pin3, - pin4, - ) - INT DEFAULT 0; - """ - ) \ No newline at end of file + await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin INT DEFAULT 0") + + await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit1 FLOAT DEFAULT 0") + await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount1 INT DEFAULT 0") + await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin1 INT DEFAULT 0") + + await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit2 FLOAT DEFAULT 0") + await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount2 INT DEFAULT 0") + await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin2 INT DEFAULT 0") + + await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit3 FLOAT DEFAULT 0") + await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount3 INT DEFAULT 0") + await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin3 INT DEFAULT 0") + + await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit4 FLOAT DEFAULT 0") + await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount4 INT DEFAULT 0") + await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin4 INT DEFAULT 0") \ No newline at end of file diff --git a/lnbits/extensions/lnurldevice/models.py b/lnbits/extensions/lnurldevice/models.py index a4af4404a..f4638bcd4 100644 --- a/lnbits/extensions/lnurldevice/models.py +++ b/lnbits/extensions/lnurldevice/models.py @@ -18,20 +18,19 @@ class createLnurldevice(BaseModel): device: str profit: float amount: int - amount1: int - amount2: int - amount3: int - amount4: int pin: int + profit1: float + amount1: int pin1: int + profit2: float + amount2: int pin2: int + profit3: float + amount3: int pin3: int + profit4: float + amount4: int pin4: int - time: int - time1: int - time2: int - time3: int - time4: int class lnurldevices(BaseModel): @@ -43,6 +42,19 @@ class lnurldevices(BaseModel): device: str profit: float amount: int + pin: int + profit1: float + amount1: int + pin1: int + profit2: float + amount2: int + pin2: int + profit3: float + amount3: int + pin3: int + profit4: float + amount4: int + pin4: int timestamp: str def from_row(cls, row: Row) -> "lnurldevices": diff --git a/lnbits/extensions/lnurldevice/tasks.py b/lnbits/extensions/lnurldevice/tasks.py index 55cbaa986..2867577de 100644 --- a/lnbits/extensions/lnurldevice/tasks.py +++ b/lnbits/extensions/lnurldevice/tasks.py @@ -36,5 +36,5 @@ async def on_invoice_paid(payment: Payment) -> None: lnurldevicepayment = await update_lnurldevicepayment( lnurldevicepayment_id=payment.extra.get("id"), payhash="used" ) - return await updater(lnurldevicepayment.deviceid, lnurldevicepayment.pin) + return await updater(lnurldevicepayment.deviceid, lnurldevicepayment.pin, lnurldevicepayment.amount) return diff --git a/lnbits/extensions/lnurldevice/templates/lnurldevice/index.html b/lnbits/extensions/lnurldevice/templates/lnurldevice/index.html index 028dd94b4..ae56c2830 100644 --- a/lnbits/extensions/lnurldevice/templates/lnurldevice/index.html +++ b/lnbits/extensions/lnurldevice/templates/lnurldevice/index.html @@ -230,27 +230,167 @@ label="Profit margin (% added to invoices/deducted from faucets)" >
- - +

Switches

+ + + + + + + + + + +
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
@@ -338,6 +478,11 @@ wslocation: window.location.hostname, filter: '', currency: 'USD', + switch1: false, + switch2: false, + switch3: false, + switch4: false, + switch5: false, lnurldeviceLinks: [], lnurldeviceLinksObj: [], devices: [ @@ -592,7 +737,7 @@ LNbits.utils.notifyApiError(error) }) }, - clearFormDialoglnurldevice() { + clearFormDialoglnurldevice () { this.formDialoglnurldevice.data = { lnurl_toggle: false, show_message: false, diff --git a/lnbits/extensions/lnurldevice/views.py b/lnbits/extensions/lnurldevice/views.py index d17db7d74..d5d047af3 100644 --- a/lnbits/extensions/lnurldevice/views.py +++ b/lnbits/extensions/lnurldevice/views.py @@ -103,8 +103,8 @@ async def websocket_endpoint(websocket: WebSocket, lnurldevice_id: str): manager.disconnect(websocket) -async def updater(lnurldevice_id, lnurldevice_pin): +async def updater(lnurldevice_id, lnurldevice_pin, lnurldevice_amount): lnurldevice = await get_lnurldevice(lnurldevice_id) if not lnurldevice: return - return await manager.send_personal_message(f"pin:{lnurldevice.pin},amount:{lnurldevice.amount}", lnurldevice_id) + return await manager.send_personal_message(f"pin:{lnurldevice_pin},amount:{lnurldevice_amount}", lnurldevice_id) From 7881125c71af913aa26844fb3a97a1e94ffa12db Mon Sep 17 00:00:00 2001 From: ben Date: Wed, 26 Oct 2022 10:54:46 +0100 Subject: [PATCH 04/83] Fixed migrate --- lnbits/extensions/lnurldevice/migrations.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lnbits/extensions/lnurldevice/migrations.py b/lnbits/extensions/lnurldevice/migrations.py index ebe453010..2ba5b0b3e 100644 --- a/lnbits/extensions/lnurldevice/migrations.py +++ b/lnbits/extensions/lnurldevice/migrations.py @@ -94,19 +94,24 @@ async def m004_redux(db): Add 'meta' for storing various metadata about the wallet """ await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin INT DEFAULT 0") + await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit FLOAT DEFAULT 0") - await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit1 FLOAT DEFAULT 0") + await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount1 INT DEFAULT 0") await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin1 INT DEFAULT 0") + await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit1 FLOAT DEFAULT 0") - await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit2 FLOAT DEFAULT 0") + await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount2 INT DEFAULT 0") await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin2 INT DEFAULT 0") + await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit2 FLOAT DEFAULT 0") - await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit3 FLOAT DEFAULT 0") + await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount3 INT DEFAULT 0") await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin3 INT DEFAULT 0") + await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit3 FLOAT DEFAULT 0") - await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit4 FLOAT DEFAULT 0") + await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount4 INT DEFAULT 0") - await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin4 INT DEFAULT 0") \ No newline at end of file + await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin4 INT DEFAULT 0") + await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit4 FLOAT DEFAULT 0") \ No newline at end of file From 1bfa28da19ad5585fdb113a4283e2cd8ad9be021 Mon Sep 17 00:00:00 2001 From: ben Date: Wed, 26 Oct 2022 10:58:13 +0100 Subject: [PATCH 05/83] reverted migrate --- lnbits/extensions/lnurldevice/migrations.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/lnbits/extensions/lnurldevice/migrations.py b/lnbits/extensions/lnurldevice/migrations.py index 2ba5b0b3e..f29bca993 100644 --- a/lnbits/extensions/lnurldevice/migrations.py +++ b/lnbits/extensions/lnurldevice/migrations.py @@ -94,24 +94,20 @@ async def m004_redux(db): Add 'meta' for storing various metadata about the wallet """ await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin INT DEFAULT 0") - await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit FLOAT DEFAULT 0") - + await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit1 FLOAT DEFAULT 0") await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount1 INT DEFAULT 0") await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin1 INT DEFAULT 0") - await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit1 FLOAT DEFAULT 0") - + await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit2 FLOAT DEFAULT 0") await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount2 INT DEFAULT 0") await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin2 INT DEFAULT 0") - await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit2 FLOAT DEFAULT 0") - + await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit3 FLOAT DEFAULT 0") await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount3 INT DEFAULT 0") await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin3 INT DEFAULT 0") - await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit3 FLOAT DEFAULT 0") - + await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit4 FLOAT DEFAULT 0") await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount4 INT DEFAULT 0") await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin4 INT DEFAULT 0") - await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit4 FLOAT DEFAULT 0") \ No newline at end of file + \ No newline at end of file From 440c4b696671dc6809e81ee04c2c71236220b221 Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Wed, 26 Oct 2022 12:56:15 +0200 Subject: [PATCH 06/83] Update issue templates (#1085) --- .github/ISSUE_TEMPLATE/bug_report.md | 31 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 20 +++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..bfaddbebc --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,31 @@ +--- +name: Bug report +about: Create a report to help us improve +title: "[BUG]" +labels: bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - LNbits version: [e.g. 0.9.2 or commit hash] + - Database [e.g. sqlite, postgres] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..4f49a4973 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: "[Feature request]" +labels: feature request +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. From 2f1f92f1ee7465281cc57f2dd4e984b2c4d799b6 Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Wed, 26 Oct 2022 12:57:53 +0200 Subject: [PATCH 07/83] Update issue templates (#1086) --- .github/ISSUE_TEMPLATE/something-else.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/something-else.md diff --git a/.github/ISSUE_TEMPLATE/something-else.md b/.github/ISSUE_TEMPLATE/something-else.md new file mode 100644 index 000000000..1b3b7355d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/something-else.md @@ -0,0 +1,10 @@ +--- +name: Something else +about: Describe this issue template's purpose here. +title: '' +labels: '' +assignees: '' + +--- + + From 1d9be9619f46018e8fce7889d268f63ea915cf43 Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Wed, 26 Oct 2022 13:01:02 +0200 Subject: [PATCH 08/83] Update issue templates (#1087) --- .github/ISSUE_TEMPLATE/something-else.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/something-else.md b/.github/ISSUE_TEMPLATE/something-else.md index 1b3b7355d..4bd9ec2ac 100644 --- a/.github/ISSUE_TEMPLATE/something-else.md +++ b/.github/ISSUE_TEMPLATE/something-else.md @@ -1,6 +1,6 @@ --- name: Something else -about: Describe this issue template's purpose here. +about: Anything else that you need to say title: '' labels: '' assignees: '' From 7d736c3f77a1365a145de07da9cd8cc297091717 Mon Sep 17 00:00:00 2001 From: Lee Salminen Date: Wed, 26 Oct 2022 05:02:35 -0600 Subject: [PATCH 09/83] Add `FORWARDED_ALLOW_IPS` to example fly.io (#1082) This PR adds the needed `FORWARDED_ALLOW_IPS="*"` environment variable to the fly.io installation method, which is needed to work. --- docs/guide/installation.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/guide/installation.md b/docs/guide/installation.md index 6b95f93b1..11ded8e8e 100644 --- a/docs/guide/installation.md +++ b/docs/guide/installation.md @@ -155,6 +155,7 @@ kill_timeout = 30 HOST="127.0.0.1" PORT=5000 LNBITS_FORCE_HTTPS=true + FORWARDED_ALLOW_IPS="*" LNBITS_DATA_FOLDER="/data" ${PUT_YOUR_LNBITS_ENV_VARS_HERE} From 5a3524da8377d6706a171d31a9cd7d9aa0757bca Mon Sep 17 00:00:00 2001 From: rolznz <33993199+rolznz@users.noreply.github.com> Date: Wed, 26 Oct 2022 18:05:31 +0700 Subject: [PATCH 10/83] Fix usermanager API docs (#1073) - update incorrect response status codes - update invalid activate extension example --- .../templates/usermanager/_api_docs.html | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/lnbits/extensions/usermanager/templates/usermanager/_api_docs.html b/lnbits/extensions/usermanager/templates/usermanager/_api_docs.html index 886589e66..de477834b 100644 --- a/lnbits/extensions/usermanager/templates/usermanager/_api_docs.html +++ b/lnbits/extensions/usermanager/templates/usermanager/_api_docs.html @@ -38,7 +38,7 @@ >
Body (application/json)
- Returns 201 CREATED (application/json) + Returns 200 OK (application/json)
JSON list of users
Curl example
@@ -57,10 +57,15 @@ /usermanager/api/v1/users/<user_id>
Body (application/json)
+
- Returns 201 CREATED (application/json) + Returns 200 OK (application/json)
- JSON list of users + {"id": <string>, "name": <string>, "admin": + <string>, "email": <string>, "password": <string>} +
Curl example
curl -X GET {{ request.base_url @@ -81,7 +86,7 @@ {"X-Api-Key": <string>}
Body (application/json)
- Returns 201 CREATED (application/json) + Returns 200 OK (application/json)
JSON wallet data
Curl example
@@ -104,7 +109,7 @@ {"X-Api-Key": <string>}
Body (application/json)
- Returns 201 CREATED (application/json) + Returns 200 OK (application/json)
JSON a wallets transactions
Curl example
@@ -254,11 +259,15 @@ {"X-Api-Key": <string>}
Curl example
curl -X POST {{ request.base_url }}usermanager/api/v1/extensions -d - '{"userid": <string>, "extension": <string>, "active": - <integer>}' -H "X-Api-Key: {{ user.wallets[0].inkey }}" -H + >curl -X POST {{ request.base_url }}usermanager/api/v1/extensions?extension=withdraw&userid=user_id&active=true -H "X-Api-Key: {{ user.wallets[0].inkey }}" -H "Content-type: application/json" +
+ Returns 200 OK (application/json) +
+ {"extension": "updated"} From d702e1b6a5bb6fe304f98236d0ddddddad223107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Wed, 26 Oct 2022 13:07:34 +0200 Subject: [PATCH 11/83] add FORWARDED_ALLOW_IPS variable to .example.env (#1077) --- .env.example | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index 987c6ca69..4edaea971 100644 --- a/.env.example +++ b/.env.example @@ -1,6 +1,9 @@ HOST=127.0.0.1 PORT=5000 +# uvicorn variable, allow https behind a proxy +# FORWARDED_ALLOW_IPS="*" + DEBUG=false LNBITS_ALLOWED_USERS="" @@ -13,7 +16,7 @@ LNBITS_DEFAULT_WALLET_NAME="LNbits wallet" LNBITS_AD_SPACE="" # Hides wallet api, extensions can choose to honor -LNBITS_HIDE_API=false +LNBITS_HIDE_API=false # Disable extensions for all users, use "all" to disable all extensions LNBITS_DISABLED_EXTENSIONS="amilk" @@ -67,7 +70,7 @@ LNBITS_KEY=LNBITS_ADMIN_KEY LND_REST_ENDPOINT=https://127.0.0.1:8080/ LND_REST_CERT="/home/bob/.config/Zap/lnd/bitcoin/mainnet/wallet-1/data/chain/bitcoin/mainnet/tls.cert" LND_REST_MACAROON="/home/bob/.config/Zap/lnd/bitcoin/mainnet/wallet-1/data/chain/bitcoin/mainnet/admin.macaroon or HEXSTRING" -# To use an AES-encrypted macaroon, set +# To use an AES-encrypted macaroon, set # LND_REST_MACAROON_ENCRYPTED="eNcRyPtEdMaCaRoOn" # LNPayWallet From 937654e4f73e75b4f4446f1e7d15166fd89517ab Mon Sep 17 00:00:00 2001 From: ben Date: Wed, 26 Oct 2022 13:15:50 +0100 Subject: [PATCH 12/83] Fixed models --- lnbits/extensions/lnurldevice/crud.py | 2 +- lnbits/extensions/lnurldevice/models.py | 24 +-- .../templates/lnurldevice/index.html | 146 +++++++++++++----- 3 files changed, 124 insertions(+), 48 deletions(-) diff --git a/lnbits/extensions/lnurldevice/crud.py b/lnbits/extensions/lnurldevice/crud.py index f9a13b58d..818b99fdf 100644 --- a/lnbits/extensions/lnurldevice/crud.py +++ b/lnbits/extensions/lnurldevice/crud.py @@ -36,7 +36,7 @@ async def create_lnurldevice( pin3, profit4, amount4, - pin4, + pin4 ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, diff --git a/lnbits/extensions/lnurldevice/models.py b/lnbits/extensions/lnurldevice/models.py index f4638bcd4..62917632e 100644 --- a/lnbits/extensions/lnurldevice/models.py +++ b/lnbits/extensions/lnurldevice/models.py @@ -19,18 +19,18 @@ class createLnurldevice(BaseModel): profit: float amount: int pin: int - profit1: float - amount1: int - pin1: int - profit2: float - amount2: int - pin2: int - profit3: float - amount3: int - pin3: int - profit4: float - amount4: int - pin4: int + profit1: float = 0 + amount1: int = 0 + pin1: int = 0 + profit2: float = 0 + amount2: int = 0 + pin2: int = 0 + profit3: float = 0 + amount3: int = 0 + pin3: int = 0 + profit4: float = 0 + amount4: int = 0 + pin4: int = 0 class lnurldevices(BaseModel): diff --git a/lnbits/extensions/lnurldevice/templates/lnurldevice/index.html b/lnbits/extensions/lnurldevice/templates/lnurldevice/index.html index ae56c2830..72ea8082f 100644 --- a/lnbits/extensions/lnurldevice/templates/lnurldevice/index.html +++ b/lnbits/extensions/lnurldevice/templates/lnurldevice/index.html @@ -105,7 +105,7 @@ @click="openQrCodeDialog(props.row.id)" > LNURLs only work over HTTPS view LNURL view LNURLS + + + + + + + + + + + + +
Mails
+ Lorem ipsum dolor sit amet consectetur adipisicing elit. +
+ + +
Alarms
+ Lorem ipsum dolor sit amet consectetur adipisicing elit. +
+ + +
Movies
+ Lorem ipsum dolor sit amet consectetur adipisicing elit. +
+
+ +
LNURLDevice device string
-

Switches

- - + + - - - - - -
- +
+
+ - +
+ - +
+ +
+
-
- +
+
+ - +
+ - +
+ +
+
-
- +
+
+ - +
+ - +
+ +
+
-
- +
+
+ - +
+ - +
+ +
+
-
- +
+
+ - +
+ - +
+ +
+
-
Date: Wed, 26 Oct 2022 20:19:04 +0100 Subject: [PATCH 13/83] Web socket working --- lnbits/extensions/lnurldevice/lnurl.py | 25 +++++-- lnbits/extensions/lnurldevice/models.py | 29 ++++++-- lnbits/extensions/lnurldevice/tasks.py | 2 +- .../templates/lnurldevice/index.html | 69 +++++-------------- lnbits/extensions/lnurldevice/views_api.py | 8 +-- 5 files changed, 64 insertions(+), 69 deletions(-) diff --git a/lnbits/extensions/lnurldevice/lnurl.py b/lnbits/extensions/lnurldevice/lnurl.py index 72749e855..37a4c57d0 100644 --- a/lnbits/extensions/lnurldevice/lnurl.py +++ b/lnbits/extensions/lnurldevice/lnurl.py @@ -9,6 +9,7 @@ from embit import bech32, compact from fastapi import Request from fastapi.param_functions import Query from starlette.exceptions import HTTPException +from loguru import logger from lnbits.core.services import create_invoice from lnbits.core.views.api import pay_invoice @@ -113,6 +114,14 @@ async def lnurl_v1_params( else amount_in_cent ) * 1000 + # Check they're not trying to trick the switch! + check = False + for switch in device.switches(request): + if switch[0] == gpio and switch[1] == profit and switch[2] == amount: + check = True + if not check: + return {"status": "ERROR", "reason": f"Switch params wrong"} + lnurldevicepayment = await create_lnurldevicepayment( deviceid=device.id, payload=amount, @@ -129,7 +138,7 @@ async def lnurl_v1_params( ), "minSendable": price_msat, "maxSendable": price_msat, - "metadata": await device.lnurlpay_metadata(), + "metadata": device.lnurlpay_metadata, } if len(p) % 4 > 0: p += "=" * (4 - (len(p) % 4)) @@ -236,11 +245,17 @@ async def lnurl_callback( if device.device == "switch": payment_hash, payment_request = await create_invoice( wallet_id=device.wallet, - amount=lnurldevicepayment.sats / 1000, - memo=device.title + "-" + lnurldevicepayment.id, - unhashed_description=(await device.lnurlpay_metadata()).encode("utf-8"), - extra={"tag": "Switch", "pin": lnurldevicepayment.pin,"amount": int(lnurldevicepayment.payload),"id": paymentid}, + amount=int(lnurldevicepayment.sats / 1000), + memo=device.id + " PIN " + str(lnurldevicepayment.pin), + unhashed_description=device.lnurlpay_metadata.encode("utf-8"), + extra={ + "tag": "Switch", + "pin": str(lnurldevicepayment.pin), + "amount": str(lnurldevicepayment.payload), + "id": paymentid + }, ) + lnurldevicepayment = await update_lnurldevicepayment( lnurldevicepayment_id=paymentid, payhash=payment_hash ) diff --git a/lnbits/extensions/lnurldevice/models.py b/lnbits/extensions/lnurldevice/models.py index 62917632e..ace22ca1d 100644 --- a/lnbits/extensions/lnurldevice/models.py +++ b/lnbits/extensions/lnurldevice/models.py @@ -1,6 +1,6 @@ import json from sqlite3 import Row -from typing import Optional +from typing import Optional, List from fastapi import Request from lnurl import Lnurl @@ -9,7 +9,7 @@ from lnurl.models import LnurlPaySuccessAction, UrlAction # type: ignore from lnurl.types import LnurlPayMetadata # type: ignore from pydantic import BaseModel from pydantic.main import BaseModel - +from loguru import logger class createLnurldevice(BaseModel): title: str @@ -60,13 +60,28 @@ class lnurldevices(BaseModel): def from_row(cls, row: Row) -> "lnurldevices": return cls(**dict(row)) - def lnurl(self, req: Request) -> Lnurl: - url = req.url_for("lnurldevice.lnurl_v1_params", device_id=self.id) - return lnurl_encode(url) - - async def lnurlpay_metadata(self) -> LnurlPayMetadata: + @property + def lnurlpay_metadata(self) -> LnurlPayMetadata: return LnurlPayMetadata(json.dumps([["text/plain", self.title]])) + def switches(self, req: Request) -> List: + switches = [] + if self.profit > 0: + url = req.url_for("lnurldevice.lnurl_v1_params", device_id=self.id) + switches.append([str(self.pin), str(self.profit), str(self.amount), lnurl_encode(url + "?gpio=" + str(self.pin) + "&profit=" + str(self.profit) + "&amount=" + str(self.amount))]) + if self.profit1 > 0: + url = req.url_for("lnurldevice.lnurl_v1_params", device_id=self.id) + switches.append([str(self.pin1), str(self.profit1), str(self.amount1), lnurl_encode(url + "?gpio=" + str(self.pin1) + "&profit=" + str(self.profit1) + "&amount=" + str(self.amount1))]) + if self.profit2 > 0: + url = req.url_for("lnurldevice.lnurl_v1_params", device_id=self.id) + switches.append([str(self.pin2), str(self.profit2), str(self.amount2), lnurl_encode(url + "?gpio=" + str(self.pin2) + "&profit=" + str(self.profit2) + "&amount=" + str(self.amount2))]) + if self.profit3 > 0: + url = req.url_for("lnurldevice.lnurl_v1_params", device_id=self.id) + switches.append([str(self.pin3), str(self.profit3), str(self.amount3), lnurl_encode(url + "?gpio=" + str(self.pin3) + "&profit=" + str(self.profit3) + "&amount=" + str(self.amount3))]) + if self.profit4 > 0: + url = req.url_for("lnurldevice.lnurl_v1_params", device_id=self.id) + switches.append([str(self.pin4), str(self.profit4), str(self.amount4), lnurl_encode(url + "?gpio=" + str(self.pin4) + "&profit=" + str(self.profit4) + "&amount=" + str(self.amount4))]) + return switches class lnurldevicepayment(BaseModel): id: str diff --git a/lnbits/extensions/lnurldevice/tasks.py b/lnbits/extensions/lnurldevice/tasks.py index 2867577de..ca7aabb47 100644 --- a/lnbits/extensions/lnurldevice/tasks.py +++ b/lnbits/extensions/lnurldevice/tasks.py @@ -36,5 +36,5 @@ async def on_invoice_paid(payment: Payment) -> None: lnurldevicepayment = await update_lnurldevicepayment( lnurldevicepayment_id=payment.extra.get("id"), payhash="used" ) - return await updater(lnurldevicepayment.deviceid, lnurldevicepayment.pin, lnurldevicepayment.amount) + return await updater(lnurldevicepayment.deviceid, lnurldevicepayment.pin, lnurldevicepayment.payload) return diff --git a/lnbits/extensions/lnurldevice/templates/lnurldevice/index.html b/lnbits/extensions/lnurldevice/templates/lnurldevice/index.html index 72ea8082f..17ce9f284 100644 --- a/lnbits/extensions/lnurldevice/templates/lnurldevice/index.html +++ b/lnbits/extensions/lnurldevice/templates/lnurldevice/index.html @@ -148,42 +148,6 @@ style="width: 700px; max-width: 80vw" class="q-pa-lg q-pt-xl lnbits__dialog-card" > - - - - - - - - - - - - -
Mails
- Lorem ipsum dolor sit amet consectetur adipisicing elit. -
- - -
Alarms
- Lorem ipsum dolor sit amet consectetur adipisicing elit. -
- - -
Movies
- Lorem ipsum dolor sit amet consectetur adipisicing elit. -
-
- -
LNURLDevice device string
+ - {% raw %} -

- ID: {{ qrCodeDialog.data.id }}
-

- {% endraw %} -
- Copy LNURL +
+
+ + Close
+
@@ -545,11 +508,13 @@ mixins: [windowMixin], data: function () { return { + tab: 'mails', protocol: window.location.protocol, location: window.location.hostname, wslocation: window.location.hostname, filter: '', currency: 'USD', + lnurlValue: '', switches: 0, lnurldeviceLinks: [], lnurldeviceLinksObj: [], @@ -599,12 +564,6 @@ label: 'device', field: 'device' }, - { - name: 'profit', - align: 'left', - label: 'profit', - field: 'profit' - }, { name: 'currency', align: 'left', @@ -653,8 +612,12 @@ this.qrCodeDialog.data = _.clone(lnurldevice) this.qrCodeDialog.data.url = window.location.protocol + '//' + window.location.host + this.lnurlValueFetch(this.qrCodeDialog.data.switches[0][3]) this.qrCodeDialog.show = true }, + lnurlValueFetch: function (lnurl){ + this.lnurlValue = lnurl + }, addSwitch: function () { var self = this self.switches = self.switches + 1 @@ -719,7 +682,9 @@ .then(function (response) { if (response.data) { self.lnurldeviceLinks = response.data.map(maplnurldevice) + console.log("response.data") console.log(response.data) + console.log("response.data") } }) .catch(function (error) { diff --git a/lnbits/extensions/lnurldevice/views_api.py b/lnbits/extensions/lnurldevice/views_api.py index c034f66ed..c6766423c 100644 --- a/lnbits/extensions/lnurldevice/views_api.py +++ b/lnbits/extensions/lnurldevice/views_api.py @@ -39,10 +39,10 @@ async def api_lnurldevice_create_or_update( ): if not lnurldevice_id: lnurldevice = await create_lnurldevice(data) - return {**lnurldevice.dict(), **{"lnurl": lnurldevice.lnurl(req)}} + return {**lnurldevice.dict(), **{"switches": lnurldevice.switches(req)}} else: lnurldevice = await update_lnurldevice(data, lnurldevice_id=lnurldevice_id) - return {**lnurldevice.dict(), **{"lnurl": lnurldevice.lnurl(req)}} + return {**lnurldevice.dict(), **{"switches": lnurldevice.switches(req)}} @lnurldevice_ext.get("/api/v1/lnurlpos") @@ -52,7 +52,7 @@ async def api_lnurldevices_retrieve( wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids try: return [ - {**lnurldevice.dict(), **{"lnurl": lnurldevice.lnurl(req)}} + {**lnurldevice.dict(), **{"switches": lnurldevice.switches(req)}} for lnurldevice in await get_lnurldevices(wallet_ids) ] except: @@ -78,7 +78,7 @@ async def api_lnurldevice_retrieve( ) if not lnurldevice.lnurl_toggle: return {**lnurldevice.dict()} - return {**lnurldevice.dict(), **{"lnurl": lnurldevice.lnurl(req)}} + return {**lnurldevice.dict(), **{"switches": lnurldevice.switches(req)}} @lnurldevice_ext.delete("/api/v1/lnurlpos/{lnurldevice_id}") From 98d712fa7966e45a91563be66e3ced5d41b5b9bc Mon Sep 17 00:00:00 2001 From: ben Date: Thu, 27 Oct 2022 00:26:07 +0100 Subject: [PATCH 14/83] Fixed pin bug --- lnbits/extensions/lnurldevice/models.py | 2 +- lnbits/extensions/lnurldevice/views.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lnbits/extensions/lnurldevice/models.py b/lnbits/extensions/lnurldevice/models.py index ace22ca1d..29d49d3f4 100644 --- a/lnbits/extensions/lnurldevice/models.py +++ b/lnbits/extensions/lnurldevice/models.py @@ -18,7 +18,7 @@ class createLnurldevice(BaseModel): device: str profit: float amount: int - pin: int + pin: int = 0 profit1: float = 0 amount1: int = 0 pin1: int = 0 diff --git a/lnbits/extensions/lnurldevice/views.py b/lnbits/extensions/lnurldevice/views.py index d5d047af3..f5fd598ca 100644 --- a/lnbits/extensions/lnurldevice/views.py +++ b/lnbits/extensions/lnurldevice/views.py @@ -107,4 +107,4 @@ async def updater(lnurldevice_id, lnurldevice_pin, lnurldevice_amount): lnurldevice = await get_lnurldevice(lnurldevice_id) if not lnurldevice: return - return await manager.send_personal_message(f"pin:{lnurldevice_pin},amount:{lnurldevice_amount}", lnurldevice_id) + return await manager.send_personal_message(f"{lnurldevice_pin}-{lnurldevice_amount}", lnurldevice_id) From 5b1df5fffc02337f40b374fc9402900c17797c85 Mon Sep 17 00:00:00 2001 From: ben Date: Thu, 27 Oct 2022 00:35:49 +0100 Subject: [PATCH 15/83] fixed some ints --- lnbits/extensions/lnurldevice/lnurl.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lnbits/extensions/lnurldevice/lnurl.py b/lnbits/extensions/lnurldevice/lnurl.py index 37a4c57d0..ce2d1c695 100644 --- a/lnbits/extensions/lnurldevice/lnurl.py +++ b/lnbits/extensions/lnurldevice/lnurl.py @@ -200,7 +200,7 @@ async def lnurl_v1_params( ), "minSendable": price_msat * 1000, "maxSendable": price_msat * 1000, - "metadata": await device.lnurlpay_metadata(), + "metadata": device.lnurlpay_metadata, } @@ -266,9 +266,9 @@ async def lnurl_callback( payment_hash, payment_request = await create_invoice( wallet_id=device.wallet, - amount=lnurldevicepayment.sats / 1000, + amount=int(lnurldevicepayment.sats / 1000), memo=device.title, - unhashed_description=(await device.lnurlpay_metadata()).encode("utf-8"), + unhashed_description=device.lnurlpay_metadata.encode("utf-8"), extra={"tag": "PoS"}, ) lnurldevicepayment = await update_lnurldevicepayment( From 047d0fc761097d868c494009adde91bb39f86913 Mon Sep 17 00:00:00 2001 From: ben Date: Thu, 27 Oct 2022 00:37:15 +0100 Subject: [PATCH 16/83] black --- lnbits/extensions/lnurldevice/crud.py | 2 +- lnbits/extensions/lnurldevice/lnurl.py | 10 +-- lnbits/extensions/lnurldevice/migrations.py | 60 ++++++++++---- lnbits/extensions/lnurldevice/models.py | 87 +++++++++++++++++++-- lnbits/extensions/lnurldevice/tasks.py | 6 +- lnbits/extensions/lnurldevice/views.py | 4 +- 6 files changed, 139 insertions(+), 30 deletions(-) diff --git a/lnbits/extensions/lnurldevice/crud.py b/lnbits/extensions/lnurldevice/crud.py index 818b99fdf..e02d23b8b 100644 --- a/lnbits/extensions/lnurldevice/crud.py +++ b/lnbits/extensions/lnurldevice/crud.py @@ -61,7 +61,7 @@ async def create_lnurldevice( data.pin3, data.profit4, data.amount4, - data.pin4 + data.pin4, ), ) return await get_lnurldevice(lnurldevice_id) diff --git a/lnbits/extensions/lnurldevice/lnurl.py b/lnbits/extensions/lnurldevice/lnurl.py index ce2d1c695..6a80f74e5 100644 --- a/lnbits/extensions/lnurldevice/lnurl.py +++ b/lnbits/extensions/lnurldevice/lnurl.py @@ -9,7 +9,7 @@ from embit import bech32, compact from fastapi import Request from fastapi.param_functions import Query from starlette.exceptions import HTTPException -from loguru import logger +from loguru import logger from lnbits.core.services import create_invoice from lnbits.core.views.api import pay_invoice @@ -249,13 +249,13 @@ async def lnurl_callback( memo=device.id + " PIN " + str(lnurldevicepayment.pin), unhashed_description=device.lnurlpay_metadata.encode("utf-8"), extra={ - "tag": "Switch", + "tag": "Switch", "pin": str(lnurldevicepayment.pin), "amount": str(lnurldevicepayment.payload), - "id": paymentid - }, + "id": paymentid, + }, ) - + lnurldevicepayment = await update_lnurldevicepayment( lnurldevicepayment_id=paymentid, payhash=payment_hash ) diff --git a/lnbits/extensions/lnurldevice/migrations.py b/lnbits/extensions/lnurldevice/migrations.py index f29bca993..1df04075d 100644 --- a/lnbits/extensions/lnurldevice/migrations.py +++ b/lnbits/extensions/lnurldevice/migrations.py @@ -89,25 +89,51 @@ async def m003_redux(db): "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount INT DEFAULT 0;" ) + async def m004_redux(db): """ Add 'meta' for storing various metadata about the wallet """ - await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin INT DEFAULT 0") - - await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit1 FLOAT DEFAULT 0") - await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount1 INT DEFAULT 0") - await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin1 INT DEFAULT 0") + await db.execute( + "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin INT DEFAULT 0" + ) - await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit2 FLOAT DEFAULT 0") - await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount2 INT DEFAULT 0") - await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin2 INT DEFAULT 0") - - await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit3 FLOAT DEFAULT 0") - await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount3 INT DEFAULT 0") - await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin3 INT DEFAULT 0") - - await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit4 FLOAT DEFAULT 0") - await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount4 INT DEFAULT 0") - await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin4 INT DEFAULT 0") - \ No newline at end of file + await db.execute( + "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit1 FLOAT DEFAULT 0" + ) + await db.execute( + "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount1 INT DEFAULT 0" + ) + await db.execute( + "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin1 INT DEFAULT 0" + ) + + await db.execute( + "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit2 FLOAT DEFAULT 0" + ) + await db.execute( + "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount2 INT DEFAULT 0" + ) + await db.execute( + "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin2 INT DEFAULT 0" + ) + + await db.execute( + "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit3 FLOAT DEFAULT 0" + ) + await db.execute( + "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount3 INT DEFAULT 0" + ) + await db.execute( + "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin3 INT DEFAULT 0" + ) + + await db.execute( + "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit4 FLOAT DEFAULT 0" + ) + await db.execute( + "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount4 INT DEFAULT 0" + ) + await db.execute( + "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin4 INT DEFAULT 0" + ) diff --git a/lnbits/extensions/lnurldevice/models.py b/lnbits/extensions/lnurldevice/models.py index 29d49d3f4..1b7c0ab87 100644 --- a/lnbits/extensions/lnurldevice/models.py +++ b/lnbits/extensions/lnurldevice/models.py @@ -11,6 +11,7 @@ from pydantic import BaseModel from pydantic.main import BaseModel from loguru import logger + class createLnurldevice(BaseModel): title: str wallet: str @@ -68,21 +69,97 @@ class lnurldevices(BaseModel): switches = [] if self.profit > 0: url = req.url_for("lnurldevice.lnurl_v1_params", device_id=self.id) - switches.append([str(self.pin), str(self.profit), str(self.amount), lnurl_encode(url + "?gpio=" + str(self.pin) + "&profit=" + str(self.profit) + "&amount=" + str(self.amount))]) + switches.append( + [ + str(self.pin), + str(self.profit), + str(self.amount), + lnurl_encode( + url + + "?gpio=" + + str(self.pin) + + "&profit=" + + str(self.profit) + + "&amount=" + + str(self.amount) + ), + ] + ) if self.profit1 > 0: url = req.url_for("lnurldevice.lnurl_v1_params", device_id=self.id) - switches.append([str(self.pin1), str(self.profit1), str(self.amount1), lnurl_encode(url + "?gpio=" + str(self.pin1) + "&profit=" + str(self.profit1) + "&amount=" + str(self.amount1))]) + switches.append( + [ + str(self.pin1), + str(self.profit1), + str(self.amount1), + lnurl_encode( + url + + "?gpio=" + + str(self.pin1) + + "&profit=" + + str(self.profit1) + + "&amount=" + + str(self.amount1) + ), + ] + ) if self.profit2 > 0: url = req.url_for("lnurldevice.lnurl_v1_params", device_id=self.id) - switches.append([str(self.pin2), str(self.profit2), str(self.amount2), lnurl_encode(url + "?gpio=" + str(self.pin2) + "&profit=" + str(self.profit2) + "&amount=" + str(self.amount2))]) + switches.append( + [ + str(self.pin2), + str(self.profit2), + str(self.amount2), + lnurl_encode( + url + + "?gpio=" + + str(self.pin2) + + "&profit=" + + str(self.profit2) + + "&amount=" + + str(self.amount2) + ), + ] + ) if self.profit3 > 0: url = req.url_for("lnurldevice.lnurl_v1_params", device_id=self.id) - switches.append([str(self.pin3), str(self.profit3), str(self.amount3), lnurl_encode(url + "?gpio=" + str(self.pin3) + "&profit=" + str(self.profit3) + "&amount=" + str(self.amount3))]) + switches.append( + [ + str(self.pin3), + str(self.profit3), + str(self.amount3), + lnurl_encode( + url + + "?gpio=" + + str(self.pin3) + + "&profit=" + + str(self.profit3) + + "&amount=" + + str(self.amount3) + ), + ] + ) if self.profit4 > 0: url = req.url_for("lnurldevice.lnurl_v1_params", device_id=self.id) - switches.append([str(self.pin4), str(self.profit4), str(self.amount4), lnurl_encode(url + "?gpio=" + str(self.pin4) + "&profit=" + str(self.profit4) + "&amount=" + str(self.amount4))]) + switches.append( + [ + str(self.pin4), + str(self.profit4), + str(self.amount4), + lnurl_encode( + url + + "?gpio=" + + str(self.pin4) + + "&profit=" + + str(self.profit4) + + "&amount=" + + str(self.amount4) + ), + ] + ) return switches + class lnurldevicepayment(BaseModel): id: str deviceid: str diff --git a/lnbits/extensions/lnurldevice/tasks.py b/lnbits/extensions/lnurldevice/tasks.py index ca7aabb47..d3248ad57 100644 --- a/lnbits/extensions/lnurldevice/tasks.py +++ b/lnbits/extensions/lnurldevice/tasks.py @@ -36,5 +36,9 @@ async def on_invoice_paid(payment: Payment) -> None: lnurldevicepayment = await update_lnurldevicepayment( lnurldevicepayment_id=payment.extra.get("id"), payhash="used" ) - return await updater(lnurldevicepayment.deviceid, lnurldevicepayment.pin, lnurldevicepayment.payload) + return await updater( + lnurldevicepayment.deviceid, + lnurldevicepayment.pin, + lnurldevicepayment.payload, + ) return diff --git a/lnbits/extensions/lnurldevice/views.py b/lnbits/extensions/lnurldevice/views.py index f5fd598ca..f435931bd 100644 --- a/lnbits/extensions/lnurldevice/views.py +++ b/lnbits/extensions/lnurldevice/views.py @@ -107,4 +107,6 @@ async def updater(lnurldevice_id, lnurldevice_pin, lnurldevice_amount): lnurldevice = await get_lnurldevice(lnurldevice_id) if not lnurldevice: return - return await manager.send_personal_message(f"{lnurldevice_pin}-{lnurldevice_amount}", lnurldevice_id) + return await manager.send_personal_message( + f"{lnurldevice_pin}-{lnurldevice_amount}", lnurldevice_id + ) From 1ab0d0f70132ce5d75f41d4ecb3df37135695a4b Mon Sep 17 00:00:00 2001 From: ben Date: Thu, 27 Oct 2022 01:05:09 +0100 Subject: [PATCH 17/83] isort --- lnbits/extensions/lnurldevice/lnurl.py | 12 ++++-------- lnbits/extensions/lnurldevice/models.py | 4 ++-- lnbits/extensions/lnurldevice/tasks.py | 3 ++- lnbits/extensions/lnurldevice/views_api.py | 9 ++------- 4 files changed, 10 insertions(+), 18 deletions(-) diff --git a/lnbits/extensions/lnurldevice/lnurl.py b/lnbits/extensions/lnurldevice/lnurl.py index 6a80f74e5..bdbcbdaa1 100644 --- a/lnbits/extensions/lnurldevice/lnurl.py +++ b/lnbits/extensions/lnurldevice/lnurl.py @@ -8,21 +8,17 @@ from typing import Optional from embit import bech32, compact from fastapi import Request from fastapi.param_functions import Query -from starlette.exceptions import HTTPException from loguru import logger +from starlette.exceptions import HTTPException from lnbits.core.services import create_invoice from lnbits.core.views.api import pay_invoice from lnbits.utils.exchange_rates import fiat_amount_as_satoshis from . import lnurldevice_ext -from .crud import ( - create_lnurldevicepayment, - get_lnurldevice, - get_lnurldevicepayment, - get_lnurlpayload, - update_lnurldevicepayment, -) +from .crud import (create_lnurldevicepayment, get_lnurldevice, + get_lnurldevicepayment, get_lnurlpayload, + update_lnurldevicepayment) def bech32_decode(bech): diff --git a/lnbits/extensions/lnurldevice/models.py b/lnbits/extensions/lnurldevice/models.py index 1b7c0ab87..c27470b73 100644 --- a/lnbits/extensions/lnurldevice/models.py +++ b/lnbits/extensions/lnurldevice/models.py @@ -1,15 +1,15 @@ import json from sqlite3 import Row -from typing import Optional, List +from typing import List, Optional from fastapi import Request from lnurl import Lnurl from lnurl import encode as lnurl_encode # type: ignore from lnurl.models import LnurlPaySuccessAction, UrlAction # type: ignore from lnurl.types import LnurlPayMetadata # type: ignore +from loguru import logger from pydantic import BaseModel from pydantic.main import BaseModel -from loguru import logger class createLnurldevice(BaseModel): diff --git a/lnbits/extensions/lnurldevice/tasks.py b/lnbits/extensions/lnurldevice/tasks.py index d3248ad57..2c2ac7134 100644 --- a/lnbits/extensions/lnurldevice/tasks.py +++ b/lnbits/extensions/lnurldevice/tasks.py @@ -12,7 +12,8 @@ from lnbits.core.services import pay_invoice from lnbits.helpers import get_current_extension_name from lnbits.tasks import register_invoice_listener -from .crud import get_lnurldevice, get_lnurldevicepayment, update_lnurldevicepayment +from .crud import (get_lnurldevice, get_lnurldevicepayment, + update_lnurldevicepayment) from .views import updater diff --git a/lnbits/extensions/lnurldevice/views_api.py b/lnbits/extensions/lnurldevice/views_api.py index c6766423c..d0ea8659f 100644 --- a/lnbits/extensions/lnurldevice/views_api.py +++ b/lnbits/extensions/lnurldevice/views_api.py @@ -11,13 +11,8 @@ from lnbits.extensions.lnurldevice import lnurldevice_ext from lnbits.utils.exchange_rates import currencies from . import lnurldevice_ext -from .crud import ( - create_lnurldevice, - delete_lnurldevice, - get_lnurldevice, - get_lnurldevices, - update_lnurldevice, -) +from .crud import (create_lnurldevice, delete_lnurldevice, get_lnurldevice, + get_lnurldevices, update_lnurldevice) from .models import createLnurldevice From 8bafb9ab1992deaa7c9fe4c0cf9e01263ec10703 Mon Sep 17 00:00:00 2001 From: ben Date: Thu, 27 Oct 2022 01:10:03 +0100 Subject: [PATCH 18/83] black --- lnbits/extensions/lnurldevice/lnurl.py | 10 +++++++--- lnbits/extensions/lnurldevice/tasks.py | 3 +-- lnbits/extensions/lnurldevice/views_api.py | 9 +++++++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/lnbits/extensions/lnurldevice/lnurl.py b/lnbits/extensions/lnurldevice/lnurl.py index bdbcbdaa1..c8f9675e4 100644 --- a/lnbits/extensions/lnurldevice/lnurl.py +++ b/lnbits/extensions/lnurldevice/lnurl.py @@ -16,9 +16,13 @@ from lnbits.core.views.api import pay_invoice from lnbits.utils.exchange_rates import fiat_amount_as_satoshis from . import lnurldevice_ext -from .crud import (create_lnurldevicepayment, get_lnurldevice, - get_lnurldevicepayment, get_lnurlpayload, - update_lnurldevicepayment) +from .crud import ( + create_lnurldevicepayment, + get_lnurldevice, + get_lnurldevicepayment, + get_lnurlpayload, + update_lnurldevicepayment, +) def bech32_decode(bech): diff --git a/lnbits/extensions/lnurldevice/tasks.py b/lnbits/extensions/lnurldevice/tasks.py index 2c2ac7134..d3248ad57 100644 --- a/lnbits/extensions/lnurldevice/tasks.py +++ b/lnbits/extensions/lnurldevice/tasks.py @@ -12,8 +12,7 @@ from lnbits.core.services import pay_invoice from lnbits.helpers import get_current_extension_name from lnbits.tasks import register_invoice_listener -from .crud import (get_lnurldevice, get_lnurldevicepayment, - update_lnurldevicepayment) +from .crud import get_lnurldevice, get_lnurldevicepayment, update_lnurldevicepayment from .views import updater diff --git a/lnbits/extensions/lnurldevice/views_api.py b/lnbits/extensions/lnurldevice/views_api.py index d0ea8659f..c6766423c 100644 --- a/lnbits/extensions/lnurldevice/views_api.py +++ b/lnbits/extensions/lnurldevice/views_api.py @@ -11,8 +11,13 @@ from lnbits.extensions.lnurldevice import lnurldevice_ext from lnbits.utils.exchange_rates import currencies from . import lnurldevice_ext -from .crud import (create_lnurldevice, delete_lnurldevice, get_lnurldevice, - get_lnurldevices, update_lnurldevice) +from .crud import ( + create_lnurldevice, + delete_lnurldevice, + get_lnurldevice, + get_lnurldevices, + update_lnurldevice, +) from .models import createLnurldevice From 904dea37fc25641f3c283a3850af22474700d751 Mon Sep 17 00:00:00 2001 From: ben Date: Thu, 27 Oct 2022 01:16:05 +0100 Subject: [PATCH 19/83] prettier --- .../templates/lnurldevice/index.html | 317 ++++++++++-------- 1 file changed, 168 insertions(+), 149 deletions(-) diff --git a/lnbits/extensions/lnurldevice/templates/lnurldevice/index.html b/lnbits/extensions/lnurldevice/templates/lnurldevice/index.html index 17ce9f284..83ff4571e 100644 --- a/lnbits/extensions/lnurldevice/templates/lnurldevice/index.html +++ b/lnbits/extensions/lnurldevice/templates/lnurldevice/index.html @@ -230,201 +230,217 @@ label="Profit margin (% added to invoices/deducted from faucets)" >
- - - - + +
-
+
+ ref="setAmount" + filled + dense + v-model.trim="formDialoglnurldevice.data.profit" + class="q-pb-md" + :label="'Amount (' + formDialoglnurldevice.data.currency + ') *'" + :mask="'#.##'" + fill-mask="0" + reverse-fill-mask + :step="'0.01'" + value="0.00" + >
+ filled + dense + v-model.trim="formDialoglnurldevice.data.amount" + type="number" + value="1000" + label="milesecs to turn Switch on for (1sec = 1000ms)" + >
+ filled + dense + v-model.trim="formDialoglnurldevice.data.pin" + type="number" + label="GPIO to turn on" + >
-
+
+ ref="setAmount" + filled + dense + v-model.trim="formDialoglnurldevice.data.profit1" + class="q-pb-md" + :label="'Amount (' + formDialoglnurldevice.data.currency + ') *'" + :mask="'#.##'" + fill-mask="0" + reverse-fill-mask + :step="'0.01'" + value="0.00" + >
+ filled + dense + v-model.trim="formDialoglnurldevice.data.amount1" + type="number" + value="1000" + label="milesecs to turn Switch on for (1sec = 1000ms)" + >
+ filled + dense + v-model.trim="formDialoglnurldevice.data.pin1" + type="number" + label="GPIO to turn on" + >
-
+
+ ref="setAmount" + filled + dense + v-model.trim="formDialoglnurldevice.data.profit2" + class="q-pb-md" + :label="'Amount (' + formDialoglnurldevice.data.currency + ') *'" + :mask="'#.##'" + fill-mask="0" + reverse-fill-mask + :step="'0.01'" + value="0.00" + >
+ filled + dense + v-model.trim="formDialoglnurldevice.data.amount2" + type="number" + value="1000" + label="milesecs to turn Switch on for (1sec = 1000ms)" + >
+ filled + dense + v-model.trim="formDialoglnurldevice.data.pin2" + type="number" + label="GPIO to turn on" + >
-
+
-
+
+ ref="setAmount" + filled + dense + v-model.trim="formDialoglnurldevice.data.profit3" + class="q-pb-md" + :label="'Amount (' + formDialoglnurldevice.data.currency + ') *'" + :mask="'#.##'" + fill-mask="0" + reverse-fill-mask + :step="'0.01'" + value="0.00" + >
+ filled + dense + v-model.trim="formDialoglnurldevice.data.amount3" + type="number" + value="1000" + label="milesecs to turn Switch on for (1sec = 1000ms)" + >
+ filled + dense + v-model.trim="formDialoglnurldevice.data.pin3" + type="number" + label="GPIO to turn on" + >
-
+
-
+
+ ref="setAmount" + filled + dense + v-model.trim="formDialoglnurldevice.data.profit4" + class="q-pb-md" + :label="'Amount (' + formDialoglnurldevice.data.currency + ') *'" + :mask="'#.##'" + fill-mask="0" + reverse-fill-mask + :step="'0.01'" + value="0.00" + >
+ filled + dense + v-model.trim="formDialoglnurldevice.data.amount4" + type="number" + value="1000" + label="milesecs to turn Switch on for (1sec = 1000ms)" + >
+ filled + dense + v-model.trim="formDialoglnurldevice.data.pin4" + type="number" + label="GPIO to turn on" + >
@@ -458,7 +474,6 @@ - Copy LNURL -
+ outline + color="grey" + @click="copyText(lnurlValue, 'LNURL copied to clipboard!')" + >Copy LNURL +
- - + Close
-
@@ -615,7 +634,7 @@ this.lnurlValueFetch(this.qrCodeDialog.data.switches[0][3]) this.qrCodeDialog.show = true }, - lnurlValueFetch: function (lnurl){ + lnurlValueFetch: function (lnurl) { this.lnurlValue = lnurl }, addSwitch: function () { @@ -682,9 +701,9 @@ .then(function (response) { if (response.data) { self.lnurldeviceLinks = response.data.map(maplnurldevice) - console.log("response.data") + console.log('response.data') console.log(response.data) - console.log("response.data") + console.log('response.data') } }) .catch(function (error) { From 7be45d5d912a94b704178298c715676c8f484418 Mon Sep 17 00:00:00 2001 From: Arc <33088785+arcbtc@users.noreply.github.com> Date: Fri, 28 Oct 2022 10:22:59 +0100 Subject: [PATCH 20/83] Update installation.md --- docs/guide/installation.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/guide/installation.md b/docs/guide/installation.md index 11ded8e8e..bf40418d9 100644 --- a/docs/guide/installation.md +++ b/docs/guide/installation.md @@ -48,7 +48,9 @@ poetry run lnbits # Note that you have to add the line DEBUG=true in your .env file, too. ``` -## Option 2: Nix +## Option 2: Nix + +> note: currently not supported while we make some architectural changes on the path to leave beta ```sh git clone https://github.com/lnbits/lnbits-legend.git From b92fedbcc9f22415ed7b34d26a83e1c4f2ce8864 Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Fri, 28 Oct 2022 11:26:02 +0200 Subject: [PATCH 21/83] refactor try except block (#1084) --- lnbits/extensions/withdraw/lnurl.py | 55 +++++++++++++++-------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/lnbits/extensions/withdraw/lnurl.py b/lnbits/extensions/withdraw/lnurl.py index 18a99599c..660e5b7dd 100644 --- a/lnbits/extensions/withdraw/lnurl.py +++ b/lnbits/extensions/withdraw/lnurl.py @@ -78,34 +78,35 @@ async def api_lnurl_callback( return {"status": "ERROR", "reason": f"Wait {link.open_time - now} seconds."} usescsv = "" + + for x in range(1, link.uses - link.used): + usecv = link.usescsv.split(",") + usescsv += "," + str(usecv[x]) + usecsvback = usescsv + + found = False + if id_unique_hash is not None: + useslist = link.usescsv.split(",") + for ind, x in enumerate(useslist): + tohash = link.id + link.unique_hash + str(x) + if id_unique_hash == shortuuid.uuid(name=tohash): + found = True + useslist.pop(ind) + usescsv = ",".join(useslist) + if not found: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, detail="LNURL-withdraw not found." + ) + else: + usescsv = usescsv[1:] + + changesback = { + "open_time": link.wait_time, + "used": link.used, + "usescsv": usecsvback, + } + try: - for x in range(1, link.uses - link.used): - usecv = link.usescsv.split(",") - usescsv += "," + str(usecv[x]) - usecsvback = usescsv - - found = False - if id_unique_hash is not None: - useslist = link.usescsv.split(",") - for ind, x in enumerate(useslist): - tohash = link.id + link.unique_hash + str(x) - if id_unique_hash == shortuuid.uuid(name=tohash): - found = True - useslist.pop(ind) - usescsv = ",".join(useslist) - if not found: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="LNURL-withdraw not found." - ) - else: - usescsv = usescsv[1:] - - changesback = { - "open_time": link.wait_time, - "used": link.used, - "usescsv": usecsvback, - } - changes = { "open_time": link.wait_time + now, "used": link.used + 1, From 4ee571ca7139ffbfb132522fb29d7d1f9f23ea8a Mon Sep 17 00:00:00 2001 From: ChuckNorrison <2964146+ChuckNorrison@users.noreply.github.com> Date: Mon, 7 Nov 2022 11:30:18 +0100 Subject: [PATCH 22/83] Documentation for postgresql default port (#1106) * Documentation for postgresql default port A port is necessary for postgresql config. Add postgresql default port 5432 in documentation for LNBITS_DATABASE_URL config * Update docs/guide/installation.md Co-authored-by: calle <93376500+callebtc@users.noreply.github.com> Co-authored-by: calle <93376500+callebtc@users.noreply.github.com> --- docs/guide/installation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guide/installation.md b/docs/guide/installation.md index bf40418d9..072c4d91c 100644 --- a/docs/guide/installation.md +++ b/docs/guide/installation.md @@ -220,8 +220,8 @@ You need to edit the `.env` file. ```sh # add the database connection string to .env 'nano .env' LNBITS_DATABASE_URL= -# postgres://:@/ - alter line bellow with your user, password and db name -LNBITS_DATABASE_URL="postgres://postgres:postgres@localhost/lnbits" +# postgres://:@:/ - alter line bellow with your user, password and db name +LNBITS_DATABASE_URL="postgres://postgres:postgres@localhost:5432/lnbits" # save and exit ``` From c3ef4d726038aa81b9298afce682d573f9aa12d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Mon, 7 Nov 2022 11:30:44 +0100 Subject: [PATCH 23/83] formatting fixes, prettier (#1108) --- .../lnurldevice/templates/lnurldevice/index.html | 2 +- .../templates/usermanager/_api_docs.html | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/lnbits/extensions/lnurldevice/templates/lnurldevice/index.html b/lnbits/extensions/lnurldevice/templates/lnurldevice/index.html index 83ff4571e..b0b223fff 100644 --- a/lnbits/extensions/lnurldevice/templates/lnurldevice/index.html +++ b/lnbits/extensions/lnurldevice/templates/lnurldevice/index.html @@ -797,7 +797,7 @@ LNbits.utils.notifyApiError(error) }) }, - clearFormDialoglnurldevice () { + clearFormDialoglnurldevice() { this.formDialoglnurldevice.data = { lnurl_toggle: false, show_message: false, diff --git a/lnbits/extensions/usermanager/templates/usermanager/_api_docs.html b/lnbits/extensions/usermanager/templates/usermanager/_api_docs.html index de477834b..36593d74b 100644 --- a/lnbits/extensions/usermanager/templates/usermanager/_api_docs.html +++ b/lnbits/extensions/usermanager/templates/usermanager/_api_docs.html @@ -57,13 +57,14 @@ /usermanager/api/v1/users/<user_id>
Body (application/json)
- +
Returns 200 OK (application/json)
{"id": <string>, "name": <string>, "admin": - <string>, "email": <string>, "password": <string>}
Curl example
@@ -259,15 +260,15 @@ {"X-Api-Key": <string>}
Curl example
curl -X POST {{ request.base_url }}usermanager/api/v1/extensions?extension=withdraw&userid=user_id&active=true -H "X-Api-Key: {{ user.wallets[0].inkey }}" -H - "Content-type: application/json" + >curl -X POST {{ request.base_url + }}usermanager/api/v1/extensions?extension=withdraw&userid=user_id&active=true + -H "X-Api-Key: {{ user.wallets[0].inkey }}" -H "Content-type: + application/json"
Returns 200 OK (application/json)
- {"extension": "updated"} + {"extension": "updated"} From 0ea225b87e19e2e2b72657f3da0f8095b99d5257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Mon, 7 Nov 2022 13:31:42 +0100 Subject: [PATCH 24/83] add api docs button --- lnbits/templates/base.html | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lnbits/templates/base.html b/lnbits/templates/base.html index 67241bb5c..ef2703717 100644 --- a/lnbits/templates/base.html +++ b/lnbits/templates/base.html @@ -199,6 +199,18 @@ > + + API DOCS + View LNbits Swagger API docs + Date: Tue, 8 Nov 2022 01:15:54 +0100 Subject: [PATCH 25/83] fix sys is not defined --- tools/conv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/conv.py b/tools/conv.py index 5084660ff..cb8f05731 100644 --- a/tools/conv.py +++ b/tools/conv.py @@ -24,7 +24,7 @@ sqfolder = env.str("LNBITS_DATA_FOLDER", default=None) LNBITS_DATABASE_URL = env.str("LNBITS_DATABASE_URL", default=None) if LNBITS_DATABASE_URL is None: print("missing LNBITS_DATABASE_URL") - sys.exit(1) + os.sys.exit(1) else: # parse postgres://lnbits:postgres@localhost:5432/lnbits pgdb = LNBITS_DATABASE_URL.split("/")[-1] From 61dd9817b6ed966df90f175520da046c47ee28e6 Mon Sep 17 00:00:00 2001 From: ben Date: Tue, 8 Nov 2022 13:47:03 +0000 Subject: [PATCH 26/83] fixed atm --- lnbits/extensions/lnurldevice/lnurl.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lnbits/extensions/lnurldevice/lnurl.py b/lnbits/extensions/lnurldevice/lnurl.py index c8f9675e4..dd8dcb08e 100644 --- a/lnbits/extensions/lnurldevice/lnurl.py +++ b/lnbits/extensions/lnurldevice/lnurl.py @@ -105,9 +105,9 @@ async def lnurl_v1_params( paymentcheck = await get_lnurlpayload(p) if device.device == "atm": if paymentcheck: - return {"status": "ERROR", "reason": f"Payment already claimed"} + if paymentcheck.payhash != "payment_hash": + return {"status": "ERROR", "reason": f"Payment already claimed"} if device.device == "switch": - price_msat = ( await fiat_amount_as_satoshis(float(profit), device.currency) if device.currency != "sat" @@ -177,7 +177,7 @@ async def lnurl_v1_params( "callback": request.url_for( "lnurldevice.lnurl_callback", paymentid=lnurldevicepayment.id ), - "k1": lnurldevicepayment.id, + "k1": p, "minWithdrawable": price_msat * 1000, "maxWithdrawable": price_msat * 1000, "defaultDescription": device.title, @@ -227,14 +227,13 @@ async def lnurl_callback( status_code=HTTPStatus.FORBIDDEN, detail="No payment request" ) else: - if lnurldevicepayment.id != k1: + if lnurldevicepayment.payload != k1: return {"status": "ERROR", "reason": "Bad K1"} if lnurldevicepayment.payhash != "payment_hash": return {"status": "ERROR", "reason": f"Payment already claimed"} lnurldevicepayment = await update_lnurldevicepayment( lnurldevicepayment_id=paymentid, payhash=lnurldevicepayment.payload ) - await pay_invoice( wallet_id=device.wallet, payment_request=pr, From 0ae11df52f62d670a4759eb72a6e41460e809e9f Mon Sep 17 00:00:00 2001 From: Bitkarrot <73979971+bitkarrot@users.noreply.github.com> Date: Thu, 10 Nov 2022 22:22:17 -0800 Subject: [PATCH 27/83] Docker file fix for missing directory Currently Docker will error and exit because `data` directory is not created. This commit adds automatic `data` directory creation to Dockerfile so that the following docker command will not error. ``` docker run --detach --publish 5000:5000 --name lnbits-legend --volume ${PWD}/.env:/app/.env --volume ${PWD}/data/:/app/data lnbits-legend ``` --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 6259fe7b8..af3f36162 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,6 +8,7 @@ RUN curl -sSL https://install.python-poetry.org | python3 - ENV PATH="/root/.local/bin:$PATH" WORKDIR /app +RUN mkdir -p /app/lnbits/data COPY . . From db4232f2ced4e7e062e3e77ac14a8f1cb7998c73 Mon Sep 17 00:00:00 2001 From: ChuckNorrison <2964146+ChuckNorrison@users.noreply.github.com> Date: Fri, 11 Nov 2022 12:06:35 +0100 Subject: [PATCH 28/83] Documentation improved in example env LNBITS_ALLOWED_USERS and LNBITS_ADMIN_USERS wants usr string from wallet url List needs to be comma separated if used more than one user --- .env.example | 1 + 1 file changed, 1 insertion(+) diff --git a/.env.example b/.env.example index 4edaea971..e76296ab4 100644 --- a/.env.example +++ b/.env.example @@ -6,6 +6,7 @@ PORT=5000 DEBUG=false +# Find "usr" string in wallet url to explicit allow users or set admins (comma separated list) LNBITS_ALLOWED_USERS="" LNBITS_ADMIN_USERS="" # Extensions only admin can access From 029e8baf5310a664cfc809b768b80974bb291563 Mon Sep 17 00:00:00 2001 From: ben Date: Fri, 11 Nov 2022 23:46:22 +0000 Subject: [PATCH 29/83] added tasks to make tickets --- lnbits/extensions/events/__init__.py | 10 +++++++ lnbits/extensions/events/tasks.py | 40 +++++++++++++++++++++++++++ lnbits/extensions/events/views_api.py | 10 +++---- 3 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 lnbits/extensions/events/tasks.py diff --git a/lnbits/extensions/events/__init__.py b/lnbits/extensions/events/__init__.py index d0aa27bca..c64a866ba 100644 --- a/lnbits/extensions/events/__init__.py +++ b/lnbits/extensions/events/__init__.py @@ -1,7 +1,11 @@ +import asyncio + from fastapi import APIRouter from lnbits.db import Database from lnbits.helpers import template_renderer +from lnbits.tasks import catch_everything_and_restart + db = Database("ext_events") @@ -13,5 +17,11 @@ def events_renderer(): return template_renderer(["lnbits/extensions/events/templates"]) +from .tasks import wait_for_paid_invoices from .views import * # noqa from .views_api import * # noqa + + +def events_start(): + loop = asyncio.get_event_loop() + loop.create_task(catch_everything_and_restart(wait_for_paid_invoices)) diff --git a/lnbits/extensions/events/tasks.py b/lnbits/extensions/events/tasks.py new file mode 100644 index 000000000..1dcca9fae --- /dev/null +++ b/lnbits/extensions/events/tasks.py @@ -0,0 +1,40 @@ +import asyncio +import json +from http import HTTPStatus +from urllib.parse import urlparse + +import httpx +from fastapi import HTTPException + +from lnbits import bolt11 +from lnbits.core.models import Payment +from lnbits.core.services import pay_invoice +from lnbits.helpers import get_current_extension_name +from lnbits.tasks import register_invoice_listener + +from .views_api import api_ticket_send_ticket +from loguru import logger +from lnbits.extensions.events.models import CreateTicket + + +async def wait_for_paid_invoices(): + invoice_queue = asyncio.Queue() + register_invoice_listener(invoice_queue, get_current_extension_name()) + + while True: + payment = await invoice_queue.get() + await on_invoice_paid(payment) + + +async def on_invoice_paid(payment: Payment) -> None: + # (avoid loops) + logger.debug(f"cunt: sdvcsd") + if ( + "events" == payment.extra.get("tag") + and payment.extra.get("name") + and payment.extra.get("email") + ): + CreateTicket.name = str(payment.extra.get("name")) + CreateTicket.email = str(payment.extra.get("email")) + await api_ticket_send_ticket(payment.memo, payment.payment_hash, CreateTicket) + return diff --git a/lnbits/extensions/events/views_api.py b/lnbits/extensions/events/views_api.py index 9cb18f042..08651f5d2 100644 --- a/lnbits/extensions/events/views_api.py +++ b/lnbits/extensions/events/views_api.py @@ -10,6 +10,7 @@ from lnbits.core.services import create_invoice from lnbits.core.views.api import api_payment from lnbits.decorators import WalletTypeInfo, get_key_type from lnbits.extensions.events.models import CreateEvent, CreateTicket +from loguru import logger from . import events_ext from .crud import ( @@ -96,8 +97,8 @@ async def api_tickets( return [ticket.dict() for ticket in await get_tickets(wallet_ids)] -@events_ext.get("/api/v1/tickets/{event_id}") -async def api_ticket_make_ticket(event_id): +@events_ext.get("/api/v1/tickets/{event_id}/{name}/{email}") +async def api_ticket_make_ticket(event_id, name, email): event = await get_event(event_id) if not event: raise HTTPException( @@ -108,11 +109,10 @@ async def api_ticket_make_ticket(event_id): wallet_id=event.wallet, amount=event.price_per_ticket, memo=f"{event_id}", - extra={"tag": "events"}, + extra={"tag": "events", "name": name, "email": email}, ) except Exception as e: raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(e)) - return {"payment_hash": payment_hash, "payment_request": payment_request} @@ -156,7 +156,7 @@ async def api_ticket_delete(ticket_id, wallet: WalletTypeInfo = Depends(get_key_ ) await delete_ticket(ticket_id) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + return "", HTTPStatus.NO_CONTENT # Event Tickets From 9f84e7e408ac69f6e61b425ccfbe060557df5d6b Mon Sep 17 00:00:00 2001 From: ben Date: Fri, 11 Nov 2022 23:59:29 +0000 Subject: [PATCH 30/83] typo --- lnbits/extensions/events/tasks.py | 1 - lnbits/extensions/events/templates/events/display.html | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lnbits/extensions/events/tasks.py b/lnbits/extensions/events/tasks.py index 1dcca9fae..2068b3fa4 100644 --- a/lnbits/extensions/events/tasks.py +++ b/lnbits/extensions/events/tasks.py @@ -28,7 +28,6 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: # (avoid loops) - logger.debug(f"cunt: sdvcsd") if ( "events" == payment.extra.get("tag") and payment.extra.get("name") diff --git a/lnbits/extensions/events/templates/events/display.html b/lnbits/extensions/events/templates/events/display.html index 4589c5785..9dbb95bcd 100644 --- a/lnbits/extensions/events/templates/events/display.html +++ b/lnbits/extensions/events/templates/events/display.html @@ -135,7 +135,7 @@ var self = this axios - .get('/events/api/v1/tickets/' + '{{ event_id }}') + .get('/events/api/v1/tickets/' + '{{ event_id }}' + '/' + self.formDialog.data.name + '/' + self.formDialog.data.email) .then(function (response) { self.paymentReq = response.data.payment_request self.paymentCheck = response.data.payment_hash From f3b720b690c533b4b28793209f5a71fd01b9af6e Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Sat, 12 Nov 2022 17:11:24 +0000 Subject: [PATCH 31/83] Fix usermanager API keys (#1117) * fix wrong API keys on examples * add hability to keep wallet after user delete #344 * make format --- lnbits/extensions/usermanager/crud.py | 9 +++++---- .../templates/usermanager/_api_docs.html | 13 ++++++------- lnbits/extensions/usermanager/views_api.py | 10 ++++++---- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/lnbits/extensions/usermanager/crud.py b/lnbits/extensions/usermanager/crud.py index 1ce66d4fa..649888a83 100644 --- a/lnbits/extensions/usermanager/crud.py +++ b/lnbits/extensions/usermanager/crud.py @@ -63,10 +63,11 @@ async def get_usermanager_users(user_id: str) -> List[Users]: return [Users(**row) for row in rows] -async def delete_usermanager_user(user_id: str) -> None: - wallets = await get_usermanager_wallets(user_id) - for wallet in wallets: - await delete_wallet(user_id=user_id, wallet_id=wallet.id) +async def delete_usermanager_user(user_id: str, delete_core: bool = True) -> None: + if delete_core: + wallets = await get_usermanager_wallets(user_id) + for wallet in wallets: + await delete_wallet(user_id=user_id, wallet_id=wallet.id) await db.execute("DELETE FROM usermanager.users WHERE id = ?", (user_id,)) await db.execute("""DELETE FROM usermanager.wallets WHERE "user" = ?""", (user_id,)) diff --git a/lnbits/extensions/usermanager/templates/usermanager/_api_docs.html b/lnbits/extensions/usermanager/templates/usermanager/_api_docs.html index 36593d74b..ff3ba85a3 100644 --- a/lnbits/extensions/usermanager/templates/usermanager/_api_docs.html +++ b/lnbits/extensions/usermanager/templates/usermanager/_api_docs.html @@ -44,7 +44,7 @@
Curl example
curl -X GET {{ request.base_url }}usermanager/api/v1/users -H - "X-Api-Key: {{ user.wallets[0].inkey }}" + "X-Api-Key: {{ user.wallets[0].adminkey }}" @@ -81,7 +81,7 @@ GET - /usermanager/api/v1/wallets/<user_id>
Headers
{"X-Api-Key": <string>} @@ -92,9 +92,8 @@ JSON wallet data
Curl example
curl -X GET {{ request.base_url - }}usermanager/api/v1/wallets/<user_id> -H "X-Api-Key: {{ - user.wallets[0].inkey }}" + >curl -X GET {{ request.base_url }}usermanager/api/v1/wallets -H + "X-Api-Key: {{ user.wallets[0].adminkey }}"
@@ -221,7 +220,7 @@ curl -X DELETE {{ request.base_url }}usermanager/api/v1/users/<user_id> -H "X-Api-Key: {{ - user.wallets[0].inkey }}" + user.wallets[0].adminkey }}" @@ -239,7 +238,7 @@ curl -X DELETE {{ request.base_url }}usermanager/api/v1/wallets/<wallet_id> -H "X-Api-Key: {{ - user.wallets[0].inkey }}" + user.wallets[0].adminkey }}" diff --git a/lnbits/extensions/usermanager/views_api.py b/lnbits/extensions/usermanager/views_api.py index 7e7b7653a..b1bf8ef89 100644 --- a/lnbits/extensions/usermanager/views_api.py +++ b/lnbits/extensions/usermanager/views_api.py @@ -52,15 +52,17 @@ async def api_usermanager_users_create( @usermanager_ext.delete("/api/v1/users/{user_id}") async def api_usermanager_users_delete( - user_id, wallet: WalletTypeInfo = Depends(require_admin_key) + user_id, + delete_core: bool = Query(True), + wallet: WalletTypeInfo = Depends(require_admin_key), ): user = await get_usermanager_user(user_id) if not user: raise HTTPException( status_code=HTTPStatus.NOT_FOUND, detail="User does not exist." ) - await delete_usermanager_user(user_id) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + await delete_usermanager_user(user_id, delete_core) + return "", HTTPStatus.NO_CONTENT # Activate Extension @@ -124,4 +126,4 @@ async def api_usermanager_wallets_delete( status_code=HTTPStatus.NOT_FOUND, detail="Wallet does not exist." ) await delete_usermanager_wallet(wallet_id, get_wallet.user) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + return "", HTTPStatus.NO_CONTENT From 91be3c30b60ef76282ca67a4a31dce9dd37aa05e Mon Sep 17 00:00:00 2001 From: ChuckNorrison <2964146+ChuckNorrison@users.noreply.github.com> Date: Wed, 16 Nov 2022 14:13:25 +0100 Subject: [PATCH 32/83] add missing import sys allow to call sys module directly --- tools/conv.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/conv.py b/tools/conv.py index cb8f05731..5a535a8bd 100644 --- a/tools/conv.py +++ b/tools/conv.py @@ -1,5 +1,5 @@ import argparse -import os +import os, sys import sqlite3 from typing import List @@ -24,7 +24,7 @@ sqfolder = env.str("LNBITS_DATA_FOLDER", default=None) LNBITS_DATABASE_URL = env.str("LNBITS_DATABASE_URL", default=None) if LNBITS_DATABASE_URL is None: print("missing LNBITS_DATABASE_URL") - os.sys.exit(1) + sys.exit(1) else: # parse postgres://lnbits:postgres@localhost:5432/lnbits pgdb = LNBITS_DATABASE_URL.split("/")[-1] From 00aa0c6cd9e8c23e2ea658e3220caf5e641c8e5d Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Wed, 16 Nov 2022 16:32:57 +0200 Subject: [PATCH 33/83] chore: code format --- lnbits/extensions/events/__init__.py | 1 - lnbits/extensions/events/tasks.py | 4 ++-- lnbits/extensions/events/templates/events/display.html | 9 ++++++++- lnbits/extensions/events/views_api.py | 2 +- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lnbits/extensions/events/__init__.py b/lnbits/extensions/events/__init__.py index c64a866ba..f689aaa65 100644 --- a/lnbits/extensions/events/__init__.py +++ b/lnbits/extensions/events/__init__.py @@ -6,7 +6,6 @@ from lnbits.db import Database from lnbits.helpers import template_renderer from lnbits.tasks import catch_everything_and_restart - db = Database("ext_events") diff --git a/lnbits/extensions/events/tasks.py b/lnbits/extensions/events/tasks.py index 2068b3fa4..d29215bf2 100644 --- a/lnbits/extensions/events/tasks.py +++ b/lnbits/extensions/events/tasks.py @@ -5,16 +5,16 @@ from urllib.parse import urlparse import httpx from fastapi import HTTPException +from loguru import logger from lnbits import bolt11 from lnbits.core.models import Payment from lnbits.core.services import pay_invoice +from lnbits.extensions.events.models import CreateTicket from lnbits.helpers import get_current_extension_name from lnbits.tasks import register_invoice_listener from .views_api import api_ticket_send_ticket -from loguru import logger -from lnbits.extensions.events.models import CreateTicket async def wait_for_paid_invoices(): diff --git a/lnbits/extensions/events/templates/events/display.html b/lnbits/extensions/events/templates/events/display.html index 9dbb95bcd..e65b4e61a 100644 --- a/lnbits/extensions/events/templates/events/display.html +++ b/lnbits/extensions/events/templates/events/display.html @@ -135,7 +135,14 @@ var self = this axios - .get('/events/api/v1/tickets/' + '{{ event_id }}' + '/' + self.formDialog.data.name + '/' + self.formDialog.data.email) + .get( + '/events/api/v1/tickets/' + + '{{ event_id }}' + + '/' + + self.formDialog.data.name + + '/' + + self.formDialog.data.email + ) .then(function (response) { self.paymentReq = response.data.payment_request self.paymentCheck = response.data.payment_hash diff --git a/lnbits/extensions/events/views_api.py b/lnbits/extensions/events/views_api.py index 08651f5d2..30e7962ee 100644 --- a/lnbits/extensions/events/views_api.py +++ b/lnbits/extensions/events/views_api.py @@ -2,6 +2,7 @@ from http import HTTPStatus from fastapi.param_functions import Query from fastapi.params import Depends +from loguru import logger from starlette.exceptions import HTTPException from starlette.requests import Request @@ -10,7 +11,6 @@ from lnbits.core.services import create_invoice from lnbits.core.views.api import api_payment from lnbits.decorators import WalletTypeInfo, get_key_type from lnbits.extensions.events.models import CreateEvent, CreateTicket -from loguru import logger from . import events_ext from .crud import ( From 1971b9a24bd53a750ee8520b4714b4068d6f9dda Mon Sep 17 00:00:00 2001 From: ChuckNorrison <2964146+ChuckNorrison@users.noreply.github.com> Date: Wed, 16 Nov 2022 23:06:21 +0100 Subject: [PATCH 34/83] fix integer out of range for apipayments related to #1030, this was missing --- lnbits/core/migrations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lnbits/core/migrations.py b/lnbits/core/migrations.py index ebecb5e30..d92f384ac 100644 --- a/lnbits/core/migrations.py +++ b/lnbits/core/migrations.py @@ -51,7 +51,7 @@ async def m001_initial(db): f""" CREATE TABLE IF NOT EXISTS apipayments ( payhash TEXT NOT NULL, - amount INTEGER NOT NULL, + amount {db.big_int} NOT NULL, fee INTEGER NOT NULL DEFAULT 0, wallet TEXT NOT NULL, pending BOOLEAN NOT NULL, From fcc787ed35b6190da65395eec0f711d180a2c487 Mon Sep 17 00:00:00 2001 From: bitkarrot <73979971+bitkarrot@users.noreply.github.com> Date: Wed, 16 Nov 2022 15:34:35 -0800 Subject: [PATCH 35/83] update Dockerfile dir to lnbits/data --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index af3f36162..f107f68c8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,7 @@ RUN curl -sSL https://install.python-poetry.org | python3 - ENV PATH="/root/.local/bin:$PATH" WORKDIR /app -RUN mkdir -p /app/lnbits/data +RUN mkdir -p lnbits/data COPY . . From 032df0e50ca0151751ab6675b8c3fb01de9cd56f Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Tue, 8 Nov 2022 20:01:09 +0200 Subject: [PATCH 36/83] feat: allow decimal fee rate --- .../watchonly/static/components/fee-rate/fee-rate.html | 1 + 1 file changed, 1 insertion(+) diff --git a/lnbits/extensions/watchonly/static/components/fee-rate/fee-rate.html b/lnbits/extensions/watchonly/static/components/fee-rate/fee-rate.html index c65ad1c46..0df5bebf8 100644 --- a/lnbits/extensions/watchonly/static/components/fee-rate/fee-rate.html +++ b/lnbits/extensions/watchonly/static/components/fee-rate/fee-rate.html @@ -6,6 +6,7 @@ filled dense v-model.number="feeRate" + step="any" :rules="[val => !!val || 'Field is required']" type="number" label="sats/vbyte" From 0673245d112b4a781cb956a62c62c231d77b758e Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Tue, 8 Nov 2022 10:34:11 +0200 Subject: [PATCH 37/83] chore: update watchonly db --- tests/data/mock_data.zip | Bin 24852 -> 30790 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tests/data/mock_data.zip b/tests/data/mock_data.zip index d184f94ad6f20b2806bb438d047802f452c0847b..5a52941c74a0ef02265cb3ad046998b113cfa3a0 100644 GIT binary patch delta 18912 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�#n!dJLBWtVGzdvg~J(NREuW`TVok5g;$A8%xwjH%5+_41{?Y`c9s5n_%yl6kO z_(}*kH$fx7%}f%-q=j$OZpntx%4hqDqU3tHANcKcx~up}|Df7oMj21j*SVPb^}`{n zi1nCvy8~ZdunhK@n(X^nrZqXAcC2?rHCJdgY77x)9QCOd6BcnVOB9E z#Rt&w^fhwj`%Wd@1Y3PoAMPwVYgp~nG>zYT3C%cAB;c_pw>6_$LNL=5fyt?poUX&~ z=?>f)@93GX_O!NarYGcDb{GA~KA(aH|H5I1xrWnbp6bF%6ukyUFx(Anr7i?F~YTp`81HxH2t1nMPTv)rb z4XjN)_SbESk=9j*Qj_ZNtOlUMPca5vv`v60jJQ>gJqt0G(C6V7bw{L4(-uc^qXznm z1nkx#Sr?1FKYlr@pSCuCpVN4;BzbLB_<1_p$YVbTwL)+I*t4hd5E8*3^ANRL2y=_J!ykTWBIflu zn|gu?%G!!!G?bO^VJJiS$2CtvXJa!8*0dKd``^7oB6(iHXW}x4Gt$PqCI!I*O!Z$i9ut`=)qvZT2L;I!}FC) zt%qx(VpGQN(XFxDFw5K6!U*gtX=tOF`jPh2XT{GV$!Rl;p zdW8LIv-qM4Bejl-m&OIoYWv2y_>E`veX5^}@+w_ok3@jONrUfGqjdeDH(OZSc)ldp zCw{uCHi+D-qIuJndeyThP{e#?I7qI#ZaVb3r(;DK-YyLLVL<4)<_ZG%nv(O?^A3o; z*I3na39ya~*ajc0{u(=ioT1^E77DDbsHoYAX ze@S1Z4+y(v@nG=|X!^8^+wwJ}5w}HivG_Gw%TB8^ysojE4z%u+$zue7%n<6n&JGmd z`t*i-l^<$VCl2^nRiMPRcUfQLdwTtmWv|l7iPKWlNsyE<^&(|7RLkx;zJ7+tL-i2l zZGjcHKR@4Wt}q8H*_w=U848jha}Y`pAxjrk%d>$XlS?HksPIlpD zvx#=&&q#>R^5Ne*iEt`G0^pMUsL}UHyXwsJp91e+Ep19Ra%E@o^iu#J=Y^(x!=a>~ zaH!@>RtDu#<+ICK`g4iVLXC;Xb9FyM&&IXIgdEekNmm?1js>a?( Yui~vDy3FqV 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 From 7d7a2b67ee165dc40bafe31936fefb11bacc9dc9 Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Wed, 2 Nov 2022 15:30:18 +0000 Subject: [PATCH 38/83] fix raise error on delete request --- lnbits/extensions/bleskomat/views_api.py | 2 +- lnbits/extensions/boltcards/views_api.py | 2 +- lnbits/extensions/discordbot/views_api.py | 4 ++-- lnbits/extensions/events/views_api.py | 2 +- lnbits/extensions/livestream/views_api.py | 8 ++++---- lnbits/extensions/lnaddress/views_api.py | 4 ++-- lnbits/extensions/lnticket/views_api.py | 4 ++-- lnbits/extensions/lnurlpayout/views_api.py | 2 +- lnbits/extensions/offlineshop/views_api.py | 2 +- lnbits/extensions/paywall/views_api.py | 2 +- lnbits/extensions/satspay/views_api.py | 2 +- lnbits/extensions/scrub/views_api.py | 2 +- lnbits/extensions/streamalerts/views_api.py | 4 ++-- lnbits/extensions/subdomains/views_api.py | 4 ++-- lnbits/extensions/tpos/views_api.py | 2 +- 15 files changed, 23 insertions(+), 23 deletions(-) diff --git a/lnbits/extensions/bleskomat/views_api.py b/lnbits/extensions/bleskomat/views_api.py index e29e3fe76..b6e417bbe 100644 --- a/lnbits/extensions/bleskomat/views_api.py +++ b/lnbits/extensions/bleskomat/views_api.py @@ -95,4 +95,4 @@ async def api_bleskomat_delete( ) await delete_bleskomat(bleskomat_id) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + return "", HTTPStatus.NO_CONTENT diff --git a/lnbits/extensions/boltcards/views_api.py b/lnbits/extensions/boltcards/views_api.py index 7b8357cf8..3dfa6c21d 100644 --- a/lnbits/extensions/boltcards/views_api.py +++ b/lnbits/extensions/boltcards/views_api.py @@ -129,7 +129,7 @@ async def api_card_delete(card_id, wallet: WalletTypeInfo = Depends(require_admi raise HTTPException(detail="Not your card.", status_code=HTTPStatus.FORBIDDEN) await delete_card(card_id) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + return "", HTTPStatus.NO_CONTENT @boltcards_ext.get("/api/v1/hits") diff --git a/lnbits/extensions/discordbot/views_api.py b/lnbits/extensions/discordbot/views_api.py index e6d004dbb..b69c274ae 100644 --- a/lnbits/extensions/discordbot/views_api.py +++ b/lnbits/extensions/discordbot/views_api.py @@ -65,7 +65,7 @@ async def api_discordbot_users_delete( status_code=HTTPStatus.NOT_FOUND, detail="User does not exist." ) await delete_discordbot_user(user_id) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + return "", HTTPStatus.NO_CONTENT # Activate Extension @@ -129,4 +129,4 @@ async def api_discordbot_wallets_delete( status_code=HTTPStatus.NOT_FOUND, detail="Wallet does not exist." ) await delete_discordbot_wallet(wallet_id, get_wallet.user) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + return "", HTTPStatus.NO_CONTENT diff --git a/lnbits/extensions/events/views_api.py b/lnbits/extensions/events/views_api.py index 30e7962ee..668e7f779 100644 --- a/lnbits/extensions/events/views_api.py +++ b/lnbits/extensions/events/views_api.py @@ -79,7 +79,7 @@ async def api_form_delete(event_id, wallet: WalletTypeInfo = Depends(get_key_typ await delete_event(event_id) await delete_event_tickets(event_id) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + return "", HTTPStatus.NO_CONTENT #########Tickets########## diff --git a/lnbits/extensions/livestream/views_api.py b/lnbits/extensions/livestream/views_api.py index cc173a66e..0c169a71f 100644 --- a/lnbits/extensions/livestream/views_api.py +++ b/lnbits/extensions/livestream/views_api.py @@ -60,14 +60,14 @@ async def api_update_track(track_id, g: WalletTypeInfo = Depends(get_key_type)): ls = await get_or_create_livestream_by_wallet(g.wallet.id) await update_current_track(ls.id, id) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + return "", HTTPStatus.NO_CONTENT @livestream_ext.put("/api/v1/livestream/fee/{fee_pct}") async def api_update_fee(fee_pct, g: WalletTypeInfo = Depends(get_key_type)): ls = await get_or_create_livestream_by_wallet(g.wallet.id) await update_livestream_fee(ls.id, int(fee_pct)) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + return "", HTTPStatus.NO_CONTENT @livestream_ext.post("/api/v1/livestream/tracks") @@ -93,8 +93,8 @@ async def api_add_track( return -@livestream_ext.route("/api/v1/livestream/tracks/{track_id}") +@livestream_ext.delete("/api/v1/livestream/tracks/{track_id}") async def api_delete_track(track_id, g: WalletTypeInfo = Depends(get_key_type)): ls = await get_or_create_livestream_by_wallet(g.wallet.id) await delete_track_from_livestream(ls.id, track_id) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + return "", HTTPStatus.NO_CONTENT diff --git a/lnbits/extensions/lnaddress/views_api.py b/lnbits/extensions/lnaddress/views_api.py index 8f403a381..46ef6b999 100644 --- a/lnbits/extensions/lnaddress/views_api.py +++ b/lnbits/extensions/lnaddress/views_api.py @@ -93,7 +93,7 @@ async def api_domain_delete(domain_id, g: WalletTypeInfo = Depends(get_key_type) raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="Not your domain") await delete_domain(domain_id) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + return "", HTTPStatus.NO_CONTENT # ADDRESSES @@ -253,4 +253,4 @@ async def api_address_delete(address_id, g: WalletTypeInfo = Depends(get_key_typ ) await delete_address(address_id) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + return "", HTTPStatus.NO_CONTENT diff --git a/lnbits/extensions/lnticket/views_api.py b/lnbits/extensions/lnticket/views_api.py index 7c9eb52c0..cf6145b31 100644 --- a/lnbits/extensions/lnticket/views_api.py +++ b/lnbits/extensions/lnticket/views_api.py @@ -78,7 +78,7 @@ async def api_form_delete(form_id, wallet: WalletTypeInfo = Depends(get_key_type await delete_form(form_id) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + return "", HTTPStatus.NO_CONTENT #########tickets########## @@ -160,4 +160,4 @@ async def api_ticket_delete(ticket_id, wallet: WalletTypeInfo = Depends(get_key_ raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="Not your ticket.") await delete_ticket(ticket_id) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + return "", HTTPStatus.NO_CONTENT diff --git a/lnbits/extensions/lnurlpayout/views_api.py b/lnbits/extensions/lnurlpayout/views_api.py index 67562909c..324eb5dd5 100644 --- a/lnbits/extensions/lnurlpayout/views_api.py +++ b/lnbits/extensions/lnurlpayout/views_api.py @@ -80,7 +80,7 @@ async def api_lnurlpayout_delete( ) await delete_lnurlpayout(lnurlpayout_id) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + return "", HTTPStatus.NO_CONTENT @lnurlpayout_ext.get("/api/v1/lnurlpayouts/{lnurlpayout_id}", status_code=HTTPStatus.OK) diff --git a/lnbits/extensions/offlineshop/views_api.py b/lnbits/extensions/offlineshop/views_api.py index 1bd045dd9..71583b9e2 100644 --- a/lnbits/extensions/offlineshop/views_api.py +++ b/lnbits/extensions/offlineshop/views_api.py @@ -93,7 +93,7 @@ async def api_add_or_update_item( async def api_delete_item(item_id, wallet: WalletTypeInfo = Depends(get_key_type)): shop = await get_or_create_shop_by_wallet(wallet.wallet.id) await delete_item_from_shop(shop.id, item_id) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + return "", HTTPStatus.NO_CONTENT class CreateMethodData(BaseModel): diff --git a/lnbits/extensions/paywall/views_api.py b/lnbits/extensions/paywall/views_api.py index d2d498536..3c1cd8fc4 100644 --- a/lnbits/extensions/paywall/views_api.py +++ b/lnbits/extensions/paywall/views_api.py @@ -49,7 +49,7 @@ async def api_paywall_delete( ) await delete_paywall(paywall_id) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + return "", HTTPStatus.NO_CONTENT @paywall_ext.post("/api/v1/paywalls/invoice/{paywall_id}") diff --git a/lnbits/extensions/satspay/views_api.py b/lnbits/extensions/satspay/views_api.py index 73c87e7c2..e1b87c41f 100644 --- a/lnbits/extensions/satspay/views_api.py +++ b/lnbits/extensions/satspay/views_api.py @@ -94,7 +94,7 @@ async def api_charge_delete(charge_id, wallet: WalletTypeInfo = Depends(get_key_ ) await delete_charge(charge_id) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + return "", HTTPStatus.NO_CONTENT #############################BALANCE########################## diff --git a/lnbits/extensions/scrub/views_api.py b/lnbits/extensions/scrub/views_api.py index 3714a3043..cc55c15d8 100644 --- a/lnbits/extensions/scrub/views_api.py +++ b/lnbits/extensions/scrub/views_api.py @@ -109,4 +109,4 @@ async def api_link_delete(link_id, wallet: WalletTypeInfo = Depends(require_admi ) await delete_scrub_link(link_id) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + return "", HTTPStatus.NO_CONTENT diff --git a/lnbits/extensions/streamalerts/views_api.py b/lnbits/extensions/streamalerts/views_api.py index bb2998ee5..058f51266 100644 --- a/lnbits/extensions/streamalerts/views_api.py +++ b/lnbits/extensions/streamalerts/views_api.py @@ -245,7 +245,7 @@ async def api_delete_donation(donation_id, g: WalletTypeInfo = Depends(get_key_t detail="Not authorized to delete this donation!", ) await delete_donation(donation_id) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + return "", HTTPStatus.NO_CONTENT @streamalerts_ext.delete("/api/v1/services/{service_id}") @@ -262,4 +262,4 @@ async def api_delete_service(service_id, g: WalletTypeInfo = Depends(get_key_typ detail="Not authorized to delete this service!", ) await delete_service(service_id) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + return "", HTTPStatus.NO_CONTENT diff --git a/lnbits/extensions/subdomains/views_api.py b/lnbits/extensions/subdomains/views_api.py index 34d8e75be..b30daabd6 100644 --- a/lnbits/extensions/subdomains/views_api.py +++ b/lnbits/extensions/subdomains/views_api.py @@ -81,7 +81,7 @@ async def api_domain_delete( raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="Not your domain.") await delete_domain(domain_id) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + return "", HTTPStatus.NO_CONTENT #########subdomains########## @@ -198,4 +198,4 @@ async def api_subdomain_delete( ) await delete_subdomain(subdomain_id) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + return "", HTTPStatus.NO_CONTENT diff --git a/lnbits/extensions/tpos/views_api.py b/lnbits/extensions/tpos/views_api.py index b7f14b98f..805014917 100644 --- a/lnbits/extensions/tpos/views_api.py +++ b/lnbits/extensions/tpos/views_api.py @@ -51,7 +51,7 @@ async def api_tpos_delete( raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="Not your TPoS.") await delete_tpos(tpos_id) - raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + return "", HTTPStatus.NO_CONTENT @tpos_ext.post("/api/v1/tposs/{tpos_id}/invoices", status_code=HTTPStatus.CREATED) From 0b883d02b3f2cd6a302d60ea09c60641306b1911 Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Tue, 8 Nov 2022 13:16:08 +0000 Subject: [PATCH 39/83] get payment from db --- lnbits/extensions/tpos/crud.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lnbits/extensions/tpos/crud.py b/lnbits/extensions/tpos/crud.py index 94e2c0068..04b5eaa9d 100644 --- a/lnbits/extensions/tpos/crud.py +++ b/lnbits/extensions/tpos/crud.py @@ -1,5 +1,6 @@ from typing import List, Optional, Union +from lnbits.core.models import Payment from lnbits.helpers import urlsafe_short_hash from . import db @@ -47,3 +48,12 @@ async def get_tposs(wallet_ids: Union[str, List[str]]) -> List[TPoS]: async def delete_tpos(tpos_id: str) -> None: await db.execute("DELETE FROM tpos.tposs WHERE id = ?", (tpos_id,)) + + +async def get_tpos_payments(tpos_id: str, limit: int = 5): + + rows = await db.fetchall( + f"SELECT * FROM apipayments WHERE extra LIKE '%tposId%' AND extra LIKE '%{tpos_id}%' ORDER BY time DESC LIMIT {limit}" + ) + + return [Payment.from_row(row) for row in rows] From 8d8a309258dcd560d2277a8d0e7c4d1cf1394515 Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Tue, 8 Nov 2022 13:16:27 +0000 Subject: [PATCH 40/83] api endpoint to get last payments --- lnbits/extensions/tpos/views_api.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/lnbits/extensions/tpos/views_api.py b/lnbits/extensions/tpos/views_api.py index 805014917..9167b5a11 100644 --- a/lnbits/extensions/tpos/views_api.py +++ b/lnbits/extensions/tpos/views_api.py @@ -13,7 +13,7 @@ from lnbits.core.views.api import api_payment from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key from . import tpos_ext -from .crud import create_tpos, delete_tpos, get_tpos, get_tposs +from .crud import create_tpos, delete_tpos, get_tpos, get_tpos_payments, get_tposs from .models import CreateTposData, PayLnurlWData @@ -81,6 +81,22 @@ async def api_tpos_create_invoice( return {"payment_hash": payment_hash, "payment_request": payment_request} +@tpos_ext.get("/api/v1/tposs/{tpos_id}/invoices") +async def api_tpos_get_latest_invoices(tpos_id: str = None): + payments = await get_tpos_payments(tpos_id) + + return [ + { + "checking_id": payment.checking_id, + "amount": payment.amount, + "time": payment.time, + "bolt11": payment.bolt11, + "pending": payment.pending, + } + for payment in payments + ] + + @tpos_ext.post( "/api/v1/tposs/{tpos_id}/invoices/{payment_request}/pay", status_code=HTTPStatus.OK ) From 9f7b4c1370a93eb51a419951b2db0d570f572eb2 Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Tue, 8 Nov 2022 13:16:47 +0000 Subject: [PATCH 41/83] add button and list --- .../extensions/tpos/templates/tpos/tpos.html | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/lnbits/extensions/tpos/templates/tpos/tpos.html b/lnbits/extensions/tpos/templates/tpos/tpos.html index ad04b3bea..36d76cf78 100644 --- a/lnbits/extensions/tpos/templates/tpos/tpos.html +++ b/lnbits/extensions/tpos/templates/tpos/tpos.html @@ -148,6 +148,9 @@
+ + + + + + + + + + + + + {%raw%} + + {{payment.amount / 1000}} sats + {{payment.checking_id}} + + + {{payment.dateFrom}} + + + {%endraw%} + + + + {% endblock %} {% block styles %} @@ -296,6 +322,10 @@ tipAmount: 0.0, hasNFC: false, nfcTagReading: false, + lastPaymentsDialog: { + show: false, + data: [] + }, invoiceDialog: { show: false, data: null, @@ -520,6 +550,25 @@ self.exchangeRate = response.data.data['BTC' + self.currency][self.currency] }) + }, + getLastPayments(){ + return axios + .get(`/tpos/api/v1/tposs/${this.tposId}/invoices`) + .then(res => { + if(res.data && res.data.length){ + let last = [...res.data] + //last.length = Math.min(last.length, 5) + this.lastPaymentsDialog.data = last.map(obj => { + obj.dateFrom = moment(obj.time * 1000).fromNow() + return obj + }) + } + }) + .catch(e => console.error(e)) + }, + showLastPayments(){ + this.getLastPayments() + this.lastPaymentsDialog.show = true } }, created: function () { From 8e85651c4fbefdec0c389af029a419c7ad3966c5 Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Tue, 8 Nov 2022 13:18:10 +0000 Subject: [PATCH 42/83] make format --- .../extensions/tpos/templates/tpos/tpos.html | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/lnbits/extensions/tpos/templates/tpos/tpos.html b/lnbits/extensions/tpos/templates/tpos/tpos.html index 36d76cf78..32ed0b884 100644 --- a/lnbits/extensions/tpos/templates/tpos/tpos.html +++ b/lnbits/extensions/tpos/templates/tpos/tpos.html @@ -149,7 +149,12 @@
- + {{payment.amount / 1000}} sats - {{payment.checking_id}} + {{payment.checking_id}} {{payment.dateFrom}} - + {%endraw%} - + @@ -551,11 +561,11 @@ response.data.data['BTC' + self.currency][self.currency] }) }, - getLastPayments(){ + getLastPayments() { return axios .get(`/tpos/api/v1/tposs/${this.tposId}/invoices`) .then(res => { - if(res.data && res.data.length){ + if (res.data && res.data.length) { let last = [...res.data] //last.length = Math.min(last.length, 5) this.lastPaymentsDialog.data = last.map(obj => { @@ -566,7 +576,7 @@ }) .catch(e => console.error(e)) }, - showLastPayments(){ + showLastPayments() { this.getLastPayments() this.lastPaymentsDialog.show = true } From a2092675cdceaf974bce48fcee1257107c51361b Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Tue, 8 Nov 2022 15:18:07 +0000 Subject: [PATCH 43/83] added some UI sugar, removed pending tx --- lnbits/extensions/tpos/crud.py | 8 +++++++- lnbits/extensions/tpos/templates/tpos/tpos.html | 11 +++++------ lnbits/extensions/tpos/views_api.py | 1 - 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/lnbits/extensions/tpos/crud.py b/lnbits/extensions/tpos/crud.py index 04b5eaa9d..c403eb5a0 100644 --- a/lnbits/extensions/tpos/crud.py +++ b/lnbits/extensions/tpos/crud.py @@ -53,7 +53,13 @@ async def delete_tpos(tpos_id: str) -> None: async def get_tpos_payments(tpos_id: str, limit: int = 5): rows = await db.fetchall( - f"SELECT * FROM apipayments WHERE extra LIKE '%tposId%' AND extra LIKE '%{tpos_id}%' ORDER BY time DESC LIMIT {limit}" + f""" + SELECT * FROM apipayments + WHERE pending = 'false' + AND extra LIKE '%tposId%' + AND extra LIKE '%{tpos_id}%' + ORDER BY time DESC LIMIT {limit} + """ ) return [Payment.from_row(row) for row in rows] diff --git a/lnbits/extensions/tpos/templates/tpos/tpos.html b/lnbits/extensions/tpos/templates/tpos/tpos.html index 32ed0b884..8fe61452e 100644 --- a/lnbits/extensions/tpos/templates/tpos/tpos.html +++ b/lnbits/extensions/tpos/templates/tpos/tpos.html @@ -275,17 +275,16 @@ {%raw%} - {{payment.amount / 1000}} sats + {{payment.amount / 1000}} sats {{payment.checking_id}}Hash: {{payment.checking_id.slice(0, 30)}}... {{payment.dateFrom}} - + {%endraw%} diff --git a/lnbits/extensions/tpos/views_api.py b/lnbits/extensions/tpos/views_api.py index 9167b5a11..206c19561 100644 --- a/lnbits/extensions/tpos/views_api.py +++ b/lnbits/extensions/tpos/views_api.py @@ -90,7 +90,6 @@ async def api_tpos_get_latest_invoices(tpos_id: str = None): "checking_id": payment.checking_id, "amount": payment.amount, "time": payment.time, - "bolt11": payment.bolt11, "pending": payment.pending, } for payment in payments From e667d2dc190edfb94736374bf90643b1553f8bc0 Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Thu, 17 Nov 2022 14:59:03 +0200 Subject: [PATCH 44/83] chore: code format --- tools/conv.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/conv.py b/tools/conv.py index 5a535a8bd..541a0b75d 100644 --- a/tools/conv.py +++ b/tools/conv.py @@ -1,6 +1,7 @@ import argparse -import os, sys +import os import sqlite3 +import sys from typing import List import psycopg2 From 4549190e8688a58f874706c41ee2ddf223586d79 Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Thu, 17 Nov 2022 12:59:40 +0000 Subject: [PATCH 45/83] abstract get latest payments for extensions --- lnbits/core/crud.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lnbits/core/crud.py b/lnbits/core/crud.py index bb1ca0c1c..881d10014 100644 --- a/lnbits/core/crud.py +++ b/lnbits/core/crud.py @@ -229,6 +229,24 @@ async def get_wallet_payment( return Payment.from_row(row) if row else None +async def get_latest_payments_by_extension(ext_name: str, ext_id: str, limit: int = 5): + rows = await db.fetchall( + f""" + SELECT * FROM apipayments + WHERE pending = 'false' + AND extra LIKE ? + AND extra LIKE ? + ORDER BY time DESC LIMIT {limit} + """, + ( + f"%{ext_name}%", + f"%{ext_id}%", + ), + ) + + return rows + + async def get_payments( *, wallet_id: Optional[str] = None, From facc7bbf5e3e7ffb70da6490f695dafeb5428d9f Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Thu, 17 Nov 2022 13:00:17 +0000 Subject: [PATCH 46/83] remove core db action from extension --- lnbits/extensions/tpos/crud.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/lnbits/extensions/tpos/crud.py b/lnbits/extensions/tpos/crud.py index c403eb5a0..94e2c0068 100644 --- a/lnbits/extensions/tpos/crud.py +++ b/lnbits/extensions/tpos/crud.py @@ -1,6 +1,5 @@ from typing import List, Optional, Union -from lnbits.core.models import Payment from lnbits.helpers import urlsafe_short_hash from . import db @@ -48,18 +47,3 @@ async def get_tposs(wallet_ids: Union[str, List[str]]) -> List[TPoS]: async def delete_tpos(tpos_id: str) -> None: await db.execute("DELETE FROM tpos.tposs WHERE id = ?", (tpos_id,)) - - -async def get_tpos_payments(tpos_id: str, limit: int = 5): - - rows = await db.fetchall( - f""" - SELECT * FROM apipayments - WHERE pending = 'false' - AND extra LIKE '%tposId%' - AND extra LIKE '%{tpos_id}%' - ORDER BY time DESC LIMIT {limit} - """ - ) - - return [Payment.from_row(row) for row in rows] From 121331fa0b0d884b705eb89ce8160b530c3375c6 Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Thu, 17 Nov 2022 13:00:53 +0000 Subject: [PATCH 47/83] refactor get latest payments --- lnbits/extensions/tpos/views_api.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lnbits/extensions/tpos/views_api.py b/lnbits/extensions/tpos/views_api.py index 206c19561..e8dec2b42 100644 --- a/lnbits/extensions/tpos/views_api.py +++ b/lnbits/extensions/tpos/views_api.py @@ -7,13 +7,14 @@ from lnurl import decode as decode_lnurl from loguru import logger from starlette.exceptions import HTTPException -from lnbits.core.crud import get_user +from lnbits.core.crud import get_user, get_latest_payments_by_extension from lnbits.core.services import create_invoice from lnbits.core.views.api import api_payment from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key +from lnbits.core.models import Payment from . import tpos_ext -from .crud import create_tpos, delete_tpos, get_tpos, get_tpos_payments, get_tposs +from .crud import create_tpos, delete_tpos, get_tpos, get_tposs from .models import CreateTposData, PayLnurlWData @@ -83,7 +84,12 @@ async def api_tpos_create_invoice( @tpos_ext.get("/api/v1/tposs/{tpos_id}/invoices") async def api_tpos_get_latest_invoices(tpos_id: str = None): - payments = await get_tpos_payments(tpos_id) + payments = [ + Payment.from_row(row) + for row in await get_latest_payments_by_extension( + ext_name="tpos", ext_id=tpos_id + ) + ] return [ { From e93d1b322be5b71567a8e6ca4ed8cd5eadbea74a Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Thu, 17 Nov 2022 13:02:32 +0000 Subject: [PATCH 48/83] make format --- lnbits/extensions/tpos/views_api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lnbits/extensions/tpos/views_api.py b/lnbits/extensions/tpos/views_api.py index e8dec2b42..204548b1b 100644 --- a/lnbits/extensions/tpos/views_api.py +++ b/lnbits/extensions/tpos/views_api.py @@ -7,11 +7,11 @@ from lnurl import decode as decode_lnurl from loguru import logger from starlette.exceptions import HTTPException -from lnbits.core.crud import get_user, get_latest_payments_by_extension +from lnbits.core.crud import get_latest_payments_by_extension, get_user +from lnbits.core.models import Payment from lnbits.core.services import create_invoice from lnbits.core.views.api import api_payment from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key -from lnbits.core.models import Payment from . import tpos_ext from .crud import create_tpos, delete_tpos, get_tpos, get_tposs From 9f03d25a8c7563ea5241c5e40db14cb6c4fe0a59 Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Fri, 28 Oct 2022 11:27:11 +0100 Subject: [PATCH 49/83] fix issue with export to CSV --- lnbits/extensions/withdraw/static/js/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lnbits/extensions/withdraw/static/js/index.js b/lnbits/extensions/withdraw/static/js/index.js index 943e90246..c8d24f108 100644 --- a/lnbits/extensions/withdraw/static/js/index.js +++ b/lnbits/extensions/withdraw/static/js/index.js @@ -290,8 +290,8 @@ new Vue({ }) } }, - exportCSV: function () { - LNbits.utils.exportCSV(this.paywallsTable.columns, this.paywalls) + exportCSV() { + LNbits.utils.exportCSV(this.withdrawLinksTable.columns, this.withdrawLinks) } }, created: function () { From bd85e5dbe37ef1ee818ca333764c982e528633f5 Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Thu, 17 Nov 2022 15:05:12 +0200 Subject: [PATCH 50/83] feat: set custom file name to the exported `CSV` --- lnbits/extensions/withdraw/static/js/index.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lnbits/extensions/withdraw/static/js/index.js b/lnbits/extensions/withdraw/static/js/index.js index c8d24f108..a3eaa593a 100644 --- a/lnbits/extensions/withdraw/static/js/index.js +++ b/lnbits/extensions/withdraw/static/js/index.js @@ -291,7 +291,11 @@ new Vue({ } }, exportCSV() { - LNbits.utils.exportCSV(this.withdrawLinksTable.columns, this.withdrawLinks) + LNbits.utils.exportCSV( + this.withdrawLinksTable.columns, + this.withdrawLinks, + 'withdraw-links' + ) } }, created: function () { From 8370acc1f79b7b362850de8ed043746c386258f0 Mon Sep 17 00:00:00 2001 From: cryptoteun Date: Thu, 1 Sep 2022 21:59:38 +0200 Subject: [PATCH 51/83] added warning to backup keys --- lnbits/extensions/boltcards/templates/boltcards/index.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lnbits/extensions/boltcards/templates/boltcards/index.html b/lnbits/extensions/boltcards/templates/boltcards/index.html index 55cc1e5e2..b95a52bf4 100644 --- a/lnbits/extensions/boltcards/templates/boltcards/index.html +++ b/lnbits/extensions/boltcards/templates/boltcards/index.html @@ -380,7 +380,10 @@ Lock key: {{ qrCodeDialog.data.k0 }}
Meta key: {{ qrCodeDialog.data.k1 }}
File key: {{ qrCodeDialog.data.k2 }}
+
+ Always backup all keys that you're trying to write on the card. Without them you may not be able to change them in the future!

+
Date: Thu, 17 Nov 2022 15:48:34 +0200 Subject: [PATCH 52/83] chore: code format --- lnbits/extensions/boltcards/templates/boltcards/index.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lnbits/extensions/boltcards/templates/boltcards/index.html b/lnbits/extensions/boltcards/templates/boltcards/index.html index b95a52bf4..6398c20e5 100644 --- a/lnbits/extensions/boltcards/templates/boltcards/index.html +++ b/lnbits/extensions/boltcards/templates/boltcards/index.html @@ -380,8 +380,9 @@ Lock key: {{ qrCodeDialog.data.k0 }}
Meta key: {{ qrCodeDialog.data.k1 }}
File key: {{ qrCodeDialog.data.k2 }}
-
- Always backup all keys that you're trying to write on the card. Without them you may not be able to change them in the future!
+
+ Always backup all keys that you're trying to write on the card. Without + them you may not be able to change them in the future!


From 2eaf5e5668501c2bfb348d9af34c2b03f3e1a12f Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Thu, 17 Nov 2022 15:33:20 +0000 Subject: [PATCH 53/83] remove commented out code --- lnbits/extensions/tpos/templates/tpos/tpos.html | 1 - 1 file changed, 1 deletion(-) diff --git a/lnbits/extensions/tpos/templates/tpos/tpos.html b/lnbits/extensions/tpos/templates/tpos/tpos.html index 8fe61452e..12e18bec9 100644 --- a/lnbits/extensions/tpos/templates/tpos/tpos.html +++ b/lnbits/extensions/tpos/templates/tpos/tpos.html @@ -566,7 +566,6 @@ .then(res => { if (res.data && res.data.length) { let last = [...res.data] - //last.length = Math.min(last.length, 5) this.lastPaymentsDialog.data = last.map(obj => { obj.dateFrom = moment(obj.time * 1000).fromNow() return obj From ebeecdecca4bd15fff506e6fd383b90bfdf879d9 Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Fri, 18 Nov 2022 10:22:11 +0000 Subject: [PATCH 54/83] add "No paid invoices" if... no paid invoices --- lnbits/extensions/tpos/templates/tpos/tpos.html | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lnbits/extensions/tpos/templates/tpos/tpos.html b/lnbits/extensions/tpos/templates/tpos/tpos.html index 12e18bec9..6bc6a6268 100644 --- a/lnbits/extensions/tpos/templates/tpos/tpos.html +++ b/lnbits/extensions/tpos/templates/tpos/tpos.html @@ -272,6 +272,13 @@ + + + No paid invoices + + {%raw%} From 28e62f3333f5ea651bae4d52923d59e4f793399d Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Fri, 18 Nov 2022 10:27:23 +0000 Subject: [PATCH 55/83] make format --- lnbits/extensions/tpos/templates/tpos/tpos.html | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lnbits/extensions/tpos/templates/tpos/tpos.html b/lnbits/extensions/tpos/templates/tpos/tpos.html index 6bc6a6268..c66238f76 100644 --- a/lnbits/extensions/tpos/templates/tpos/tpos.html +++ b/lnbits/extensions/tpos/templates/tpos/tpos.html @@ -274,9 +274,7 @@ - No paid invoices + No paid invoices From 79fc0b9be4785f7a8a3f403c785e9029338a4544 Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Fri, 18 Nov 2022 10:56:14 +0000 Subject: [PATCH 56/83] wrap db call in try except --- lnbits/extensions/tpos/views_api.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lnbits/extensions/tpos/views_api.py b/lnbits/extensions/tpos/views_api.py index 204548b1b..fe63a2471 100644 --- a/lnbits/extensions/tpos/views_api.py +++ b/lnbits/extensions/tpos/views_api.py @@ -84,12 +84,16 @@ async def api_tpos_create_invoice( @tpos_ext.get("/api/v1/tposs/{tpos_id}/invoices") async def api_tpos_get_latest_invoices(tpos_id: str = None): - payments = [ - Payment.from_row(row) - for row in await get_latest_payments_by_extension( - ext_name="tpos", ext_id=tpos_id - ) - ] + try: + payments = [ + Payment.from_row(row) + for row in await get_latest_payments_by_extension( + ext_name="tpos", ext_id=tpos_id + ) + ] + + except Exception as e: + raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(e)) return [ { From b0b14464835a9b460407d1c8fe4d142b43bbf3a2 Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Thu, 27 Oct 2022 19:14:26 +0100 Subject: [PATCH 57/83] fixed display amount --- .../extensions/tpos/templates/tpos/tpos.html | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/lnbits/extensions/tpos/templates/tpos/tpos.html b/lnbits/extensions/tpos/templates/tpos/tpos.html index c66238f76..9e462abaf 100644 --- a/lnbits/extensions/tpos/templates/tpos/tpos.html +++ b/lnbits/extensions/tpos/templates/tpos/tpos.html @@ -360,15 +360,15 @@ computed: { amount: function () { if (!this.stack.length) return 0.0 - return (Number(this.stack.join('')) / 100).toFixed(2) + return Number(this.stack.join('') / 100) }, famount: function () { - return LNbits.utils.formatCurrency(this.amount, this.currency) + return LNbits.utils.formatCurrency(this.amount.toFixed(2), this.currency) }, sat: function () { if (!this.exchangeRate) return 0 return Math.ceil( - ((this.amount - this.tipAmount) / this.exchangeRate) * 100000000 + (this.amount / this.exchangeRate) * 100000000 ) }, tipAmountSat: function () { @@ -392,26 +392,25 @@ processTipSelection: function (selectedTipOption) { this.tipDialog.show = false - if (selectedTipOption) { - const tipAmount = parseFloat( - parseFloat((selectedTipOption / 100) * this.amount) - ) - const subtotal = parseFloat(this.amount) - const grandTotal = parseFloat((tipAmount + subtotal).toFixed(2)) - const totalString = grandTotal.toFixed(2).toString() + if(!selectedTipOption) return this.showInvoice() - this.stack = [] - for (var i = 0; i < totalString.length; i++) { - const char = totalString[i] + const tipAmount = (selectedTipOption / 100) * this.amount + const subtotal = this.amount + const grandTotal = (tipAmount + subtotal) + const totalString = grandTotal.toFixed(2) - if (char !== '.') { - this.stack.push(char) - } + this.stack = [] + for (var i = 0; i < totalString.length; i++) { + const char = totalString[i] + + if (char !== '.') { + this.stack.push(char) } - - this.tipAmount = tipAmount } + + this.tipAmount = tipAmount + this.showInvoice() }, submitForm: function () { From 476f915fd28a41b2676025d7b1834d850ca0c914 Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Thu, 27 Oct 2022 19:16:40 +0100 Subject: [PATCH 58/83] format --- lnbits/extensions/tpos/templates/tpos/tpos.html | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lnbits/extensions/tpos/templates/tpos/tpos.html b/lnbits/extensions/tpos/templates/tpos/tpos.html index 9e462abaf..929af4d7a 100644 --- a/lnbits/extensions/tpos/templates/tpos/tpos.html +++ b/lnbits/extensions/tpos/templates/tpos/tpos.html @@ -363,13 +363,14 @@ return Number(this.stack.join('') / 100) }, famount: function () { - return LNbits.utils.formatCurrency(this.amount.toFixed(2), this.currency) + return LNbits.utils.formatCurrency( + this.amount.toFixed(2), + this.currency + ) }, sat: function () { if (!this.exchangeRate) return 0 - return Math.ceil( - (this.amount / this.exchangeRate) * 100000000 - ) + return Math.ceil((this.amount / this.exchangeRate) * 100000000) }, tipAmountSat: function () { if (!this.exchangeRate) return 0 @@ -392,11 +393,11 @@ processTipSelection: function (selectedTipOption) { this.tipDialog.show = false - if(!selectedTipOption) return this.showInvoice() + if (!selectedTipOption) return this.showInvoice() const tipAmount = (selectedTipOption / 100) * this.amount const subtotal = this.amount - const grandTotal = (tipAmount + subtotal) + const grandTotal = tipAmount + subtotal const totalString = grandTotal.toFixed(2) this.stack = [] @@ -408,7 +409,6 @@ } } - this.tipAmount = tipAmount this.showInvoice() From 9ecf6f273b092f33573c9f541e616852be330e2f Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Fri, 18 Nov 2022 11:42:30 +0200 Subject: [PATCH 59/83] fix: total amount for invoice --- lnbits/extensions/tpos/templates/tpos/tpos.html | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/lnbits/extensions/tpos/templates/tpos/tpos.html b/lnbits/extensions/tpos/templates/tpos/tpos.html index 929af4d7a..0dd105b9b 100644 --- a/lnbits/extensions/tpos/templates/tpos/tpos.html +++ b/lnbits/extensions/tpos/templates/tpos/tpos.html @@ -395,22 +395,7 @@ if (!selectedTipOption) return this.showInvoice() - const tipAmount = (selectedTipOption / 100) * this.amount - const subtotal = this.amount - const grandTotal = tipAmount + subtotal - const totalString = grandTotal.toFixed(2) - - this.stack = [] - for (var i = 0; i < totalString.length; i++) { - const char = totalString[i] - - if (char !== '.') { - this.stack.push(char) - } - } - - this.tipAmount = tipAmount - + this.tipAmount = (selectedTipOption / 100) * this.amount this.showInvoice() }, submitForm: function () { From 0039a48e730565c308d2e5bef02e97de823207bc Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Fri, 18 Nov 2022 12:02:51 +0200 Subject: [PATCH 60/83] fix: total amount (amount + tip) --- .../extensions/tpos/templates/tpos/tpos.html | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/lnbits/extensions/tpos/templates/tpos/tpos.html b/lnbits/extensions/tpos/templates/tpos/tpos.html index 0dd105b9b..0f9620a96 100644 --- a/lnbits/extensions/tpos/templates/tpos/tpos.html +++ b/lnbits/extensions/tpos/templates/tpos/tpos.html @@ -13,7 +13,7 @@
-

{% raw %}{{ famount }}{% endraw %}

+

{% raw %}{{ amountFormatted }}{% endraw %}

{% raw %}{{ fsat }}{% endraw %} sat
@@ -173,12 +173,14 @@ >
-

{% raw %}{{ famount }}{% endraw %}

+

+ {% raw %}{{ amountWithTipFormatted }}{% endraw %} +

{% raw %}{{ fsat }} sat ( + {{ tipAmountSat }} tip)( + {{ tipAmountFormatted }} tip) {% endraw %}
@@ -362,12 +364,18 @@ if (!this.stack.length) return 0.0 return Number(this.stack.join('') / 100) }, - famount: function () { + amountFormatted: function () { return LNbits.utils.formatCurrency( this.amount.toFixed(2), this.currency ) }, + amountWithTipFormatted: function () { + return LNbits.utils.formatCurrency( + (this.amount + this.tipAmount).toFixed(2), + this.currency + ) + }, sat: function () { if (!this.exchangeRate) return 0 return Math.ceil((this.amount / this.exchangeRate) * 100000000) @@ -376,6 +384,9 @@ if (!this.exchangeRate) return 0 return Math.ceil((this.tipAmount / this.exchangeRate) * 100000000) }, + tipAmountFormatted: function () { + return LNbits.utils.formatSat(this.tipAmountSat) + }, fsat: function () { return LNbits.utils.formatSat(this.sat) } @@ -393,7 +404,10 @@ processTipSelection: function (selectedTipOption) { this.tipDialog.show = false - if (!selectedTipOption) return this.showInvoice() + if (!selectedTipOption) { + this.tipAmount = 0.0 + return this.showInvoice() + } this.tipAmount = (selectedTipOption / 100) * this.amount this.showInvoice() From 96046b8d0cd459ca7bf54cd13b3b74398c737f94 Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Fri, 14 Oct 2022 21:59:28 +0100 Subject: [PATCH 61/83] add default tip by rounding to value --- .../extensions/tpos/templates/tpos/tpos.html | 63 ++++++++++++++++++- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/lnbits/extensions/tpos/templates/tpos/tpos.html b/lnbits/extensions/tpos/templates/tpos/tpos.html index 0f9620a96..4b1b0ad3c 100644 --- a/lnbits/extensions/tpos/templates/tpos/tpos.html +++ b/lnbits/extensions/tpos/templates/tpos/tpos.html @@ -17,6 +17,7 @@
{% raw %}{{ fsat }}{% endraw %} sat
+

{% raw %}{{ parseFloat(roundToSugestion) }}{% endraw %}

@@ -214,14 +215,37 @@ style="padding: 10px; margin: 3px" unelevated @click="processTipSelection(tip)" - size="xl" + size="lg" :outline="!($q.dark.isActive)" rounded color="primary" - v-for="tip in this.tip_options" + v-for="tip in tip_options.filter(f => f != 'Round')" :key="tip" >{% raw %}{{ tip }}{% endraw %}% + + + +

No, thanks

@@ -336,6 +360,7 @@ exchangeRate: null, stack: [], tipAmount: 0.0, + tipRounding: null, hasNFC: false, nfcTagReading: false, lastPaymentsDialog: { @@ -356,7 +381,8 @@ }, complete: { show: false - } + }, + rounding: false } }, computed: { @@ -389,9 +415,36 @@ }, fsat: function () { return LNbits.utils.formatSat(this.sat) + }, + isRoundValid(){ + return this.tipRounding > this.amount + }, + roundToSugestion(){ + //let toNext = 1 + switch(true){ + case this.amount > 50: + toNext = 10 + break + case this.amount > 6: + toNext = 5 + break + case this.amount > 2.5: + toNext = 1 + break + default: + toNext = 0.5 + break + } + + return Math.ceil(this.amount/toNext)*toNext } }, methods: { + setRounding(){ + this.rounding = true + this.tipRounding = this.roundToSugestion + this.$nextTick(() => this.$refs.inputRounding.focus()) + }, closeInvoiceDialog: function () { this.stack = [] this.tipAmount = 0.0 @@ -589,6 +642,10 @@ '{{ tpos.tip_options | tojson }}' == 'null' ? null : JSON.parse('{{ tpos.tip_options }}') + + if('{{ tpos.tip_wallet }}') { + this.tip_options.push("Round") + } setInterval(function () { getRates() }, 120000) From 9430aa28c7cb68c014076aaace4cf30827e08a4c Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Mon, 17 Oct 2022 11:40:30 +0100 Subject: [PATCH 62/83] add rounding tip option --- .../extensions/tpos/templates/tpos/index.html | 8 +++- .../extensions/tpos/templates/tpos/tpos.html | 47 ++++++++++++------- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/lnbits/extensions/tpos/templates/tpos/index.html b/lnbits/extensions/tpos/templates/tpos/index.html index 3c4fa24f8..1aa75fcf1 100644 --- a/lnbits/extensions/tpos/templates/tpos/index.html +++ b/lnbits/extensions/tpos/templates/tpos/index.html @@ -139,8 +139,12 @@ input-debounce="0" new-value-mode="add-unique" label="Tip % Options (hit enter to add values)" - >Hit enter to add values + >Hit enter to add values + +
{% raw %}{{ fsat }}{% endraw %} sat -

{% raw %}{{ parseFloat(roundToSugestion) }}{% endraw %}

@@ -232,9 +231,9 @@ rounded color="primary" label="Round" - >
+ >
- - -
-
+ No, thanks Close
@@ -416,12 +415,12 @@ fsat: function () { return LNbits.utils.formatSat(this.sat) }, - isRoundValid(){ + isRoundValid() { return this.tipRounding > this.amount }, - roundToSugestion(){ + roundToSugestion() { //let toNext = 1 - switch(true){ + switch (true) { case this.amount > 50: toNext = 10 break @@ -435,16 +434,28 @@ toNext = 0.5 break } - - return Math.ceil(this.amount/toNext)*toNext + + return Math.ceil(this.amount / toNext) * toNext } }, methods: { - setRounding(){ + setRounding() { this.rounding = true this.tipRounding = this.roundToSugestion this.$nextTick(() => this.$refs.inputRounding.focus()) }, + calculatePercent() { + let change = ((this.tipRounding - this.amount) / this.amount) * 100 + if (change < 0) { + this.$q.notify({ + type: 'warning', + message: 'Value must be greater than initial amount' + }) + this.tipRounding = this.roundToSugestion + return + } + this.processTipSelection(change) + }, closeInvoiceDialog: function () { this.stack = [] this.tipAmount = 0.0 @@ -643,8 +654,8 @@ ? null : JSON.parse('{{ tpos.tip_options }}') - if('{{ tpos.tip_wallet }}') { - this.tip_options.push("Round") + if ('{{ tpos.tip_wallet }}') { + this.tip_options.push('Round') } setInterval(function () { getRates() From f4c0c92655ac0373d8e98d36313134f6fd85c8f8 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Mon, 24 Oct 2022 14:09:40 +0200 Subject: [PATCH 63/83] strings --- lnbits/extensions/tpos/templates/tpos/tpos.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lnbits/extensions/tpos/templates/tpos/tpos.html b/lnbits/extensions/tpos/templates/tpos/tpos.html index 6a74d95b3..f432901a3 100644 --- a/lnbits/extensions/tpos/templates/tpos/tpos.html +++ b/lnbits/extensions/tpos/templates/tpos/tpos.html @@ -230,7 +230,7 @@ :outline="!($q.dark.isActive)" rounded color="primary" - label="Round" + label="Custom" >
@@ -449,7 +449,7 @@ if (change < 0) { this.$q.notify({ type: 'warning', - message: 'Value must be greater than initial amount' + message: 'Amount with tip must be greater than initial amount.' }) this.tipRounding = this.roundToSugestion return From 12b69a7f826a178ba2ee7d30141266295d4cf1f3 Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Thu, 17 Nov 2022 15:13:21 +0000 Subject: [PATCH 64/83] fix reseting rounding and better UX --- .../extensions/tpos/templates/tpos/tpos.html | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/lnbits/extensions/tpos/templates/tpos/tpos.html b/lnbits/extensions/tpos/templates/tpos/tpos.html index f432901a3..3be6d4a52 100644 --- a/lnbits/extensions/tpos/templates/tpos/tpos.html +++ b/lnbits/extensions/tpos/templates/tpos/tpos.html @@ -230,21 +230,25 @@ :outline="!($q.dark.isActive)" rounded color="primary" - label="Custom" + label="Round to" > - + + + + Ok - - +
Date: Thu, 17 Nov 2022 15:14:53 +0000 Subject: [PATCH 65/83] format --- lnbits/extensions/tpos/templates/tpos/tpos.html | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lnbits/extensions/tpos/templates/tpos/tpos.html b/lnbits/extensions/tpos/templates/tpos/tpos.html index 3be6d4a52..c0adfca49 100644 --- a/lnbits/extensions/tpos/templates/tpos/tpos.html +++ b/lnbits/extensions/tpos/templates/tpos/tpos.html @@ -245,9 +245,13 @@ --> - Ok + Ok
From edf76ad7cc7d34165c5034fdab573ee7041ab2fb Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Thu, 17 Nov 2022 15:32:20 +0000 Subject: [PATCH 66/83] add input number --- lnbits/extensions/tpos/templates/tpos/tpos.html | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lnbits/extensions/tpos/templates/tpos/tpos.html b/lnbits/extensions/tpos/templates/tpos/tpos.html index c0adfca49..6c56b8fb7 100644 --- a/lnbits/extensions/tpos/templates/tpos/tpos.html +++ b/lnbits/extensions/tpos/templates/tpos/tpos.html @@ -238,6 +238,7 @@ ref="inputRounding" v-model.number="tipRounding" :placeholder="roundToSugestion" + type="number" hint="Total amount including tip" :prefix="currency" > @@ -673,4 +674,18 @@ } }) + {% endblock %} From d64e960ef67990b143ed951a0a9d5920091f0eb7 Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Fri, 18 Nov 2022 13:58:56 +0200 Subject: [PATCH 67/83] chore: code clean-up and formatting --- lnbits/extensions/tpos/templates/tpos/tpos.html | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/lnbits/extensions/tpos/templates/tpos/tpos.html b/lnbits/extensions/tpos/templates/tpos/tpos.html index 6c56b8fb7..c38862341 100644 --- a/lnbits/extensions/tpos/templates/tpos/tpos.html +++ b/lnbits/extensions/tpos/templates/tpos/tpos.html @@ -242,9 +242,6 @@ hint="Total amount including tip" :prefix="currency" > - this.amount }, roundToSugestion() { - //let toNext = 1 switch (true) { case this.amount > 50: toNext = 10 @@ -675,17 +671,15 @@ }) {% endblock %} From b698dac52c281ca0188e6a6edbf41785ed020877 Mon Sep 17 00:00:00 2001 From: Thomas Verstreken <111072251+ThomasFarstrike@users.noreply.github.com> Date: Sat, 19 Nov 2022 21:10:12 +0100 Subject: [PATCH 68/83] Fix typo's (#1136) Costumer to Customer, costumer to customer --- lnbits/extensions/offlineshop/README.md | 12 ++++++------ lnbits/extensions/satspay/README.md | 2 +- lnbits/extensions/tpos/README.md | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lnbits/extensions/offlineshop/README.md b/lnbits/extensions/offlineshop/README.md index 79bbe41d6..25ead5dfd 100644 --- a/lnbits/extensions/offlineshop/README.md +++ b/lnbits/extensions/offlineshop/README.md @@ -6,9 +6,9 @@ LNBits Offline Shop allows for merchants to receive Bitcoin payments while offline and without any electronic device. -Merchant will create items and associate a QR code ([a LNURLp](https://github.com/lnbits/lnbits/blob/master/lnbits/extensions/lnurlp/README.md)) with a price. He can then print the QR codes and display them on their shop. When a costumer chooses an item, scans the QR code, gets the description and price. After payment, the costumer gets a confirmation code that the merchant can validate to be sure the payment was successful. +Merchant will create items and associate a QR code ([a LNURLp](https://github.com/lnbits/lnbits/blob/master/lnbits/extensions/lnurlp/README.md)) with a price. He can then print the QR codes and display them on their shop. When a customer chooses an item, scans the QR code, gets the description and price. After payment, the customer gets a confirmation code that the merchant can validate to be sure the payment was successful. -Costumers must use an LNURL pay capable wallet. +Customers must use an LNURL pay capable wallet. [**Wallets supporting LNURL**](https://github.com/fiatjaf/awesome-lnurl#wallets) @@ -18,18 +18,18 @@ Costumers must use an LNURL pay capable wallet. ![offline shop back office](https://i.imgur.com/Ei7cxj9.png) 2. Begin by creating an item, click "ADD NEW ITEM" - set the item name and a small description - - you can set an optional, preferably square image, that will show up on the costumer wallet - _depending on wallet_ - - set the item price, if you choose a fiat currency the bitcoin conversion will happen at the time costumer scans to pay\ + - you can set an optional, preferably square image, that will show up on the customer wallet - _depending on wallet_ + - set the item price, if you choose a fiat currency the bitcoin conversion will happen at the time customer scans to pay\ ![add new item](https://i.imgur.com/pkZqRgj.png) 3. After creating some products, click on "PRINT QR CODES"\ ![print qr codes](https://i.imgur.com/2GAiSTe.png) 4. You'll see a QR code for each product in your LNBits Offline Shop with a title and price ready for printing\ ![qr codes sheet](https://i.imgur.com/faEqOcd.png) 5. Place the printed QR codes on your shop, or at the fair stall, or have them as a menu style laminated sheet -6. Choose what type of confirmation do you want costumers to report to merchant after a successful payment\ +6. Choose what type of confirmation do you want customers to report to merchant after a successful payment\ ![wordlist](https://i.imgur.com/9aM6NUL.png) - - Wordlist is the default option: after a successful payment the costumer will receive a word from this list, **sequentially**. Starting in _albatross_ as costumers pay for the items they will get the next word in the list until _zebra_, then it starts at the top again. The list can be changed, for example if you think A-Z is a big list to track, you can use _apple_, _banana_, _coconut_\ + - Wordlist is the default option: after a successful payment the customer will receive a word from this list, **sequentially**. Starting in _albatross_ as customers pay for the items they will get the next word in the list until _zebra_, then it starts at the top again. The list can be changed, for example if you think A-Z is a big list to track, you can use _apple_, _banana_, _coconut_\ ![totp authenticator](https://i.imgur.com/MrJXFxz.png) - TOTP (time-based one time password) can be used instead. If you use Google Authenticator just scan the presented QR with the app and after a successful payment the user will get the password that you can check with GA\ ![disable confirmations](https://i.imgur.com/2OFs4yi.png) diff --git a/lnbits/extensions/satspay/README.md b/lnbits/extensions/satspay/README.md index d52547aea..7a12feb3e 100644 --- a/lnbits/extensions/satspay/README.md +++ b/lnbits/extensions/satspay/README.md @@ -18,7 +18,7 @@ Easilly create invoices that support Lightning Network and on-chain BTC payment. ![charge form](https://i.imgur.com/F10yRiW.png) 3. The charge will appear on the _Charges_ section\ ![charges](https://i.imgur.com/zqHpVxc.png) -4. Your costumer/payee will get the payment page +4. Your customer/payee will get the payment page - they can choose to pay on LN\ ![offchain payment](https://i.imgur.com/4191SMV.png) - or pay on chain\ diff --git a/lnbits/extensions/tpos/README.md b/lnbits/extensions/tpos/README.md index 04e049e37..c7e3481d2 100644 --- a/lnbits/extensions/tpos/README.md +++ b/lnbits/extensions/tpos/README.md @@ -11,5 +11,5 @@ An easy, fast and secure way to accept Bitcoin, over Lightning Network, at your ![create](https://imgur.com/8jNj8Zq.jpg) 3. Open TPOS on the browser\ ![open](https://imgur.com/LZuoWzb.jpg) -4. Present invoice QR to costumer\ +4. Present invoice QR to customer\ ![pay](https://imgur.com/tOwxn77.jpg) From 22bb67a249a42953054d6141948994820cbe00c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Sat, 19 Nov 2022 21:12:33 +0100 Subject: [PATCH 69/83] lnurl withdraw, better errorhandling for callback endpoint (#1107) --- lnbits/extensions/withdraw/lnurl.py | 37 ++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/lnbits/extensions/withdraw/lnurl.py b/lnbits/extensions/withdraw/lnurl.py index 660e5b7dd..5737e54f5 100644 --- a/lnbits/extensions/withdraw/lnurl.py +++ b/lnbits/extensions/withdraw/lnurl.py @@ -9,7 +9,7 @@ from fastapi import HTTPException from fastapi.param_functions import Query from loguru import logger from starlette.requests import Request -from starlette.responses import HTMLResponse # type: ignore +from starlette.responses import HTMLResponse from lnbits.core.services import pay_invoice @@ -51,10 +51,24 @@ async def api_lnurl_response(request: Request, unique_hash): # CALLBACK -@withdraw_ext.get("/api/v1/lnurl/cb/{unique_hash}", name="withdraw.api_lnurl_callback") +@withdraw_ext.get( + "/api/v1/lnurl/cb/{unique_hash}", + name="withdraw.api_lnurl_callback", + summary="lnurl withdraw callback", + description=""" + This enpoints allows you to put unique_hash, k1 + and a payment_request to get your payment_request paid. + """, + response_description="JSON with status", + responses={ + 200: {"description": "status: OK"}, + 400: {"description": "k1 is wrong or link open time or withdraw not working."}, + 404: {"description": "withdraw link not found."}, + 405: {"description": "withdraw link is spent."}, + }, +) async def api_lnurl_callback( unique_hash, - request: Request, k1: str = Query(...), pr: str = Query(...), id_unique_hash=None, @@ -63,19 +77,22 @@ async def api_lnurl_callback( now = int(datetime.now().timestamp()) if not link: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="LNURL-withdraw not found" + status_code=HTTPStatus.NOT_FOUND, detail="withdraw not found." ) if link.is_spent: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="Withdraw is spent." + status_code=HTTPStatus.METHOD_NOT_ALLOWED, detail="withdraw is spent." ) if link.k1 != k1: - raise HTTPException(status_code=HTTPStatus.NOT_FOUND, detail="Bad request.") + raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="k1 is wrong.") if now < link.open_time: - return {"status": "ERROR", "reason": f"Wait {link.open_time - now} seconds."} + raise HTTPException( + status_code=HTTPStatus.BAD_REQUEST, + detail=f"wait link open_time {link.open_time - now} seconds.", + ) usescsv = "" @@ -95,7 +112,7 @@ async def api_lnurl_callback( usescsv = ",".join(useslist) if not found: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="LNURL-withdraw not found." + status_code=HTTPStatus.NOT_FOUND, detail="withdraw not found." ) else: usescsv = usescsv[1:] @@ -144,7 +161,9 @@ async def api_lnurl_callback( except Exception as e: await update_withdraw_link(link.id, **changesback) logger.error(traceback.format_exc()) - return {"status": "ERROR", "reason": "Link not working"} + raise HTTPException( + status_code=HTTPStatus.BAD_REQUEST, detail=f"withdraw not working. {str(e)}" + ) # FOR LNURLs WHICH ARE UNIQUE From 0096ce8ad1c75df3a3dcca91e480d963987781dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Sat, 19 Nov 2022 21:41:37 +0100 Subject: [PATCH 70/83] let poetry run lnbits recognize forwarded_ips for https (#1109) --- lnbits/server.py | 17 +++++++++++++---- lnbits/settings.py | 2 ++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/lnbits/server.py b/lnbits/server.py index e9849851b..7aaaa964b 100644 --- a/lnbits/server.py +++ b/lnbits/server.py @@ -1,9 +1,7 @@ -import time - import click import uvicorn -from lnbits.settings import HOST, PORT +from lnbits.settings import FORWARDED_ALLOW_IPS, HOST, PORT @click.command( @@ -14,10 +12,20 @@ from lnbits.settings import HOST, PORT ) @click.option("--port", default=PORT, help="Port to listen on") @click.option("--host", default=HOST, help="Host to run LNBits on") +@click.option( + "--forwarded-allow-ips", default=FORWARDED_ALLOW_IPS, help="Allowed proxy servers" +) @click.option("--ssl-keyfile", default=None, help="Path to SSL keyfile") @click.option("--ssl-certfile", default=None, help="Path to SSL certificate") @click.pass_context -def main(ctx, port: int, host: str, ssl_keyfile: str, ssl_certfile: str): +def main( + ctx, + port: int, + host: str, + forwarded_allow_ips: str, + ssl_keyfile: str, + ssl_certfile: str, +): """Launched with `poetry run lnbits` at root level""" # this beautiful beast parses all command line arguments and passes them to the uvicorn server d = dict() @@ -37,6 +45,7 @@ def main(ctx, port: int, host: str, ssl_keyfile: str, ssl_certfile: str): "lnbits.__main__:app", port=port, host=host, + forwarded_allow_ips=forwarded_allow_ips, ssl_keyfile=ssl_keyfile, ssl_certfile=ssl_certfile, **d diff --git a/lnbits/settings.py b/lnbits/settings.py index 3f4e31cc5..73b0d6c9e 100644 --- a/lnbits/settings.py +++ b/lnbits/settings.py @@ -18,6 +18,8 @@ DEBUG = env.bool("DEBUG", default=False) HOST = env.str("HOST", default="127.0.0.1") PORT = env.int("PORT", default=5000) +FORWARDED_ALLOW_IPS = env.str("FORWARDED_ALLOW_IPS", default="127.0.0.1") + LNBITS_PATH = path.dirname(path.realpath(__file__)) LNBITS_DATA_FOLDER = env.str( "LNBITS_DATA_FOLDER", default=path.join(LNBITS_PATH, "data") From 604e52c45dc14b4a088c98580cfd492268494f5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Sat, 19 Nov 2022 21:42:10 +0100 Subject: [PATCH 71/83] more mypy extension fixes (#1096) * mypy fix jukebox * mypy fix ngrok * mypy fix satsdice * remove exts from mypy exclude --- lnbits/extensions/jukebox/crud.py | 16 ++--- lnbits/extensions/jukebox/models.py | 29 ++++---- lnbits/extensions/jukebox/tasks.py | 9 +-- lnbits/extensions/jukebox/views.py | 7 +- lnbits/extensions/jukebox/views_api.py | 93 +++++++++++-------------- lnbits/extensions/ngrok/views.py | 5 +- lnbits/extensions/satsdice/crud.py | 47 ++++++------- lnbits/extensions/satsdice/lnurl.py | 37 +++++----- lnbits/extensions/satsdice/models.py | 7 +- lnbits/extensions/satsdice/views.py | 36 ++++++---- lnbits/extensions/satsdice/views_api.py | 24 ++++--- pyproject.toml | 3 - 12 files changed, 157 insertions(+), 156 deletions(-) diff --git a/lnbits/extensions/jukebox/crud.py b/lnbits/extensions/jukebox/crud.py index d160daeec..9d6548b6e 100644 --- a/lnbits/extensions/jukebox/crud.py +++ b/lnbits/extensions/jukebox/crud.py @@ -1,4 +1,4 @@ -from typing import List, Optional +from typing import List, Optional, Union from lnbits.helpers import urlsafe_short_hash @@ -6,11 +6,9 @@ from . import db from .models import CreateJukeboxPayment, CreateJukeLinkData, Jukebox, JukeboxPayment -async def create_jukebox( - data: CreateJukeLinkData, inkey: Optional[str] = "" -) -> Jukebox: +async def create_jukebox(data: CreateJukeLinkData) -> Jukebox: juke_id = urlsafe_short_hash() - result = await db.execute( + await db.execute( """ INSERT INTO jukebox.jukebox (id, "user", title, wallet, sp_user, sp_secret, sp_access_token, sp_refresh_token, sp_device, sp_playlists, price, profit) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) @@ -36,13 +34,13 @@ async def create_jukebox( async def update_jukebox( - data: CreateJukeLinkData, juke_id: Optional[str] = "" + data: Union[CreateJukeLinkData, Jukebox], juke_id: str = "" ) -> Optional[Jukebox]: q = ", ".join([f"{field[0]} = ?" for field in data]) items = [f"{field[1]}" for field in data] items.append(juke_id) q = q.replace("user", '"user"', 1) # hack to make user be "user"! - await db.execute(f"UPDATE jukebox.jukebox SET {q} WHERE id = ?", (items)) + await db.execute(f"UPDATE jukebox.jukebox SET {q} WHERE id = ?", (items,)) row = await db.fetchone("SELECT * FROM jukebox.jukebox WHERE id = ?", (juke_id,)) return Jukebox(**row) if row else None @@ -72,7 +70,7 @@ async def delete_jukebox(juke_id: str): """ DELETE FROM jukebox.jukebox WHERE id = ? """, - (juke_id), + (juke_id,), ) @@ -80,7 +78,7 @@ async def delete_jukebox(juke_id: str): async def create_jukebox_payment(data: CreateJukeboxPayment) -> JukeboxPayment: - result = await db.execute( + await db.execute( """ INSERT INTO jukebox.jukebox_payment (payment_hash, juke_id, song_id, paid) VALUES (?, ?, ?, ?) diff --git a/lnbits/extensions/jukebox/models.py b/lnbits/extensions/jukebox/models.py index 90984b036..70cf65230 100644 --- a/lnbits/extensions/jukebox/models.py +++ b/lnbits/extensions/jukebox/models.py @@ -1,6 +1,3 @@ -from sqlite3 import Row -from typing import NamedTuple, Optional - from fastapi.param_functions import Query from pydantic import BaseModel from pydantic.main import BaseModel @@ -20,19 +17,19 @@ class CreateJukeLinkData(BaseModel): class Jukebox(BaseModel): - id: Optional[str] - user: Optional[str] - title: Optional[str] - wallet: Optional[str] - inkey: Optional[str] - sp_user: Optional[str] - sp_secret: Optional[str] - sp_access_token: Optional[str] - sp_refresh_token: Optional[str] - sp_device: Optional[str] - sp_playlists: Optional[str] - price: Optional[int] - profit: Optional[int] + id: str + user: str + title: str + wallet: str + inkey: str + sp_user: str + sp_secret: str + sp_access_token: str + sp_refresh_token: str + sp_device: str + sp_playlists: str + price: int + profit: int class JukeboxPayment(BaseModel): diff --git a/lnbits/extensions/jukebox/tasks.py b/lnbits/extensions/jukebox/tasks.py index 5614d9261..8a68fd271 100644 --- a/lnbits/extensions/jukebox/tasks.py +++ b/lnbits/extensions/jukebox/tasks.py @@ -17,7 +17,8 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: - if payment.extra.get("tag") != "jukebox": - # not a jukebox invoice - return - await update_jukebox_payment(payment.payment_hash, paid=True) + if payment.extra: + if payment.extra.get("tag") != "jukebox": + # not a jukebox invoice + return + await update_jukebox_payment(payment.payment_hash, paid=True) diff --git a/lnbits/extensions/jukebox/views.py b/lnbits/extensions/jukebox/views.py index 56774394e..28359a9ac 100644 --- a/lnbits/extensions/jukebox/views.py +++ b/lnbits/extensions/jukebox/views.py @@ -17,7 +17,9 @@ templates = Jinja2Templates(directory="templates") @jukebox_ext.get("/", response_class=HTMLResponse) -async def index(request: Request, user: User = Depends(check_user_exists)): +async def index( + request: Request, user: User = Depends(check_user_exists) # type: ignore +): return jukebox_renderer().TemplateResponse( "jukebox/index.html", {"request": request, "user": user.dict()} ) @@ -31,6 +33,7 @@ async def connect_to_jukebox(request: Request, juke_id): status_code=HTTPStatus.NOT_FOUND, detail="Jukebox does not exist." ) devices = await api_get_jukebox_device_check(juke_id) + deviceConnected = False for device in devices["devices"]: if device["id"] == jukebox.sp_device.split("-")[1]: deviceConnected = True @@ -48,5 +51,5 @@ async def connect_to_jukebox(request: Request, juke_id): else: return jukebox_renderer().TemplateResponse( "jukebox/error.html", - {"request": request, "jukebox": jukebox.jukebox(req=request)}, + {"request": request, "jukebox": jukebox.dict()}, ) diff --git a/lnbits/extensions/jukebox/views_api.py b/lnbits/extensions/jukebox/views_api.py index 1f3723a74..5cf1a83b3 100644 --- a/lnbits/extensions/jukebox/views_api.py +++ b/lnbits/extensions/jukebox/views_api.py @@ -3,7 +3,6 @@ import json from http import HTTPStatus import httpx -from fastapi import Request from fastapi.param_functions import Query from fastapi.params import Depends from starlette.exceptions import HTTPException @@ -29,9 +28,7 @@ from .models import CreateJukeboxPayment, CreateJukeLinkData @jukebox_ext.get("/api/v1/jukebox") async def api_get_jukeboxs( - req: Request, - wallet: WalletTypeInfo = Depends(require_admin_key), - all_wallets: bool = Query(False), + wallet: WalletTypeInfo = Depends(require_admin_key), # type: ignore ): wallet_user = wallet.wallet.user @@ -53,54 +50,52 @@ async def api_check_credentials_callbac( access_token: str = Query(None), refresh_token: str = Query(None), ): - sp_code = "" - sp_access_token = "" - sp_refresh_token = "" - try: - jukebox = await get_jukebox(juke_id) - except: + jukebox = await get_jukebox(juke_id) + if not jukebox: raise HTTPException(detail="No Jukebox", status_code=HTTPStatus.FORBIDDEN) if code: jukebox.sp_access_token = code - jukebox = await update_jukebox(jukebox, juke_id=juke_id) + await update_jukebox(jukebox, juke_id=juke_id) if access_token: jukebox.sp_access_token = access_token jukebox.sp_refresh_token = refresh_token - jukebox = await update_jukebox(jukebox, juke_id=juke_id) + await update_jukebox(jukebox, juke_id=juke_id) return "

Success!

You can close this window

" -@jukebox_ext.get("/api/v1/jukebox/{juke_id}") -async def api_check_credentials_check( - juke_id: str = Query(None), wallet: WalletTypeInfo = Depends(require_admin_key) -): +@jukebox_ext.get("/api/v1/jukebox/{juke_id}", dependencies=[Depends(require_admin_key)]) +async def api_check_credentials_check(juke_id: str = Query(None)): jukebox = await get_jukebox(juke_id) return jukebox -@jukebox_ext.post("/api/v1/jukebox", status_code=HTTPStatus.CREATED) +@jukebox_ext.post( + "/api/v1/jukebox", + status_code=HTTPStatus.CREATED, + dependencies=[Depends(require_admin_key)], +) @jukebox_ext.put("/api/v1/jukebox/{juke_id}", status_code=HTTPStatus.OK) async def api_create_update_jukebox( - data: CreateJukeLinkData, - juke_id: str = Query(None), - wallet: WalletTypeInfo = Depends(require_admin_key), + data: CreateJukeLinkData, juke_id: str = Query(None) ): if juke_id: jukebox = await update_jukebox(data, juke_id=juke_id) else: - jukebox = await create_jukebox(data, inkey=wallet.wallet.inkey) + jukebox = await create_jukebox(data) return jukebox -@jukebox_ext.delete("/api/v1/jukebox/{juke_id}") +@jukebox_ext.delete( + "/api/v1/jukebox/{juke_id}", dependencies=[Depends(require_admin_key)] +) async def api_delete_item( - juke_id=None, wallet: WalletTypeInfo = Depends(require_admin_key) + juke_id: str = Query(None), ): await delete_jukebox(juke_id) - try: - return [{**jukebox} for jukebox in await get_jukeboxs(wallet.wallet.user)] - except: - raise HTTPException(status_code=HTTPStatus.NO_CONTENT, detail="No Jukebox") + # try: + # return [{**jukebox} for jukebox in await get_jukeboxs(wallet.wallet.user)] + # except: + # raise HTTPException(status_code=HTTPStatus.NO_CONTENT, detail="No Jukebox") ################JUKEBOX ENDPOINTS################## @@ -114,9 +109,8 @@ async def api_get_jukebox_song( sp_playlist: str = Query(None), retry: bool = Query(False), ): - try: - jukebox = await get_jukebox(juke_id) - except: + jukebox = await get_jukebox(juke_id) + if not jukebox: raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="No Jukeboxes") tracks = [] async with httpx.AsyncClient() as client: @@ -152,14 +146,13 @@ async def api_get_jukebox_song( } ) except: - something = None + pass return [track for track in tracks] -async def api_get_token(juke_id=None): - try: - jukebox = await get_jukebox(juke_id) - except: +async def api_get_token(juke_id): + jukebox = await get_jukebox(juke_id) + if not jukebox: raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="No Jukeboxes") async with httpx.AsyncClient() as client: @@ -187,7 +180,7 @@ async def api_get_token(juke_id=None): jukebox.sp_access_token = r.json()["access_token"] await update_jukebox(jukebox, juke_id=juke_id) except: - something = None + pass return True @@ -198,9 +191,8 @@ async def api_get_token(juke_id=None): async def api_get_jukebox_device_check( juke_id: str = Query(None), retry: bool = Query(False) ): - try: - jukebox = await get_jukebox(juke_id) - except: + jukebox = await get_jukebox(juke_id) + if not jukebox: raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="No Jukeboxes") async with httpx.AsyncClient() as client: rDevice = await client.get( @@ -221,7 +213,7 @@ async def api_get_jukebox_device_check( status_code=HTTPStatus.FORBIDDEN, detail="Failed to get auth" ) else: - return api_get_jukebox_device_check(juke_id, retry=True) + return await api_get_jukebox_device_check(juke_id, retry=True) else: raise HTTPException( status_code=HTTPStatus.FORBIDDEN, detail="No device connected" @@ -233,10 +225,8 @@ async def api_get_jukebox_device_check( @jukebox_ext.get("/api/v1/jukebox/jb/invoice/{juke_id}/{song_id}") async def api_get_jukebox_invoice(juke_id, song_id): - try: - jukebox = await get_jukebox(juke_id) - - except: + jukebox = await get_jukebox(juke_id) + if not jukebox: raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="No jukebox") try: @@ -266,8 +256,7 @@ async def api_get_jukebox_invoice(juke_id, song_id): invoice=invoice[1], payment_hash=payment_hash, juke_id=juke_id, song_id=song_id ) jukebox_payment = await create_jukebox_payment(data) - - return data + return jukebox_payment @jukebox_ext.get("/api/v1/jukebox/jb/checkinvoice/{pay_hash}/{juke_id}") @@ -296,13 +285,12 @@ async def api_get_jukebox_invoice_paid( pay_hash: str = Query(None), retry: bool = Query(False), ): - try: - jukebox = await get_jukebox(juke_id) - except: + jukebox = await get_jukebox(juke_id) + if not jukebox: raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="No jukebox") await api_get_jukebox_invoice_check(pay_hash, juke_id) jukebox_payment = await get_jukebox_payment(pay_hash) - if jukebox_payment.paid: + if jukebox_payment and jukebox_payment.paid: async with httpx.AsyncClient() as client: r = await client.get( "https://api.spotify.com/v1/me/player/currently-playing?market=ES", @@ -407,9 +395,8 @@ async def api_get_jukebox_invoice_paid( async def api_get_jukebox_currently( retry: bool = Query(False), juke_id: str = Query(None) ): - try: - jukebox = await get_jukebox(juke_id) - except: + jukebox = await get_jukebox(juke_id) + if not jukebox: raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="No jukebox") async with httpx.AsyncClient() as client: try: diff --git a/lnbits/extensions/ngrok/views.py b/lnbits/extensions/ngrok/views.py index 1a34fd51a..16c3708ac 100644 --- a/lnbits/extensions/ngrok/views.py +++ b/lnbits/extensions/ngrok/views.py @@ -1,3 +1,4 @@ +# type: ignore from os import getenv from fastapi import Request @@ -34,7 +35,9 @@ ngrok_tunnel = ngrok.connect(port) @ngrok_ext.get("/") -async def index(request: Request, user: User = Depends(check_user_exists)): +async def index( + request: Request, user: User = Depends(check_user_exists) # type: ignore +): return ngrok_renderer().TemplateResponse( "ngrok/index.html", {"request": request, "ngrok": string5, "user": user.dict()} ) diff --git a/lnbits/extensions/satsdice/crud.py b/lnbits/extensions/satsdice/crud.py index 7da5a1f1f..6aeaf31ff 100644 --- a/lnbits/extensions/satsdice/crud.py +++ b/lnbits/extensions/satsdice/crud.py @@ -8,7 +8,6 @@ from .models import ( CreateSatsDiceLink, CreateSatsDicePayment, CreateSatsDiceWithdraw, - HashCheck, satsdiceLink, satsdicePayment, satsdiceWithdraw, @@ -76,7 +75,7 @@ async def get_satsdice_pays(wallet_ids: Union[str, List[str]]) -> List[satsdiceL return [satsdiceLink(**row) for row in rows] -async def update_satsdice_pay(link_id: int, **kwargs) -> Optional[satsdiceLink]: +async def update_satsdice_pay(link_id: str, **kwargs) -> satsdiceLink: q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()]) await db.execute( f"UPDATE satsdice.satsdice_pay SET {q} WHERE id = ?", @@ -85,10 +84,10 @@ async def update_satsdice_pay(link_id: int, **kwargs) -> Optional[satsdiceLink]: row = await db.fetchone( "SELECT * FROM satsdice.satsdice_pay WHERE id = ?", (link_id,) ) - return satsdiceLink(**row) if row else None + return satsdiceLink(**row) -async def increment_satsdice_pay(link_id: int, **kwargs) -> Optional[satsdiceLink]: +async def increment_satsdice_pay(link_id: str, **kwargs) -> Optional[satsdiceLink]: q = ", ".join([f"{field[0]} = {field[0]} + ?" for field in kwargs.items()]) await db.execute( f"UPDATE satsdice.satsdice_pay SET {q} WHERE id = ?", @@ -100,7 +99,7 @@ async def increment_satsdice_pay(link_id: int, **kwargs) -> Optional[satsdiceLin return satsdiceLink(**row) if row else None -async def delete_satsdice_pay(link_id: int) -> None: +async def delete_satsdice_pay(link_id: str) -> None: await db.execute("DELETE FROM satsdice.satsdice_pay WHERE id = ?", (link_id,)) @@ -119,9 +118,15 @@ async def create_satsdice_payment(data: CreateSatsDicePayment) -> satsdicePaymen ) VALUES (?, ?, ?, ?, ?) """, - (data["payment_hash"], data["satsdice_pay"], data["value"], False, False), + ( + data.payment_hash, + data.satsdice_pay, + data.value, + False, + False, + ), ) - payment = await get_satsdice_payment(data["payment_hash"]) + payment = await get_satsdice_payment(data.payment_hash) assert payment, "Newly created withdraw couldn't be retrieved" return payment @@ -134,9 +139,7 @@ async def get_satsdice_payment(payment_hash: str) -> Optional[satsdicePayment]: return satsdicePayment(**row) if row else None -async def update_satsdice_payment( - payment_hash: int, **kwargs -) -> Optional[satsdicePayment]: +async def update_satsdice_payment(payment_hash: str, **kwargs) -> satsdicePayment: q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()]) await db.execute( @@ -147,7 +150,7 @@ async def update_satsdice_payment( "SELECT * FROM satsdice.satsdice_payment WHERE payment_hash = ?", (payment_hash,), ) - return satsdicePayment(**row) if row else None + return satsdicePayment(**row) ##################SATSDICE WITHDRAW LINKS @@ -168,16 +171,16 @@ async def create_satsdice_withdraw(data: CreateSatsDiceWithdraw) -> satsdiceWith VALUES (?, ?, ?, ?, ?, ?, ?) """, ( - data["payment_hash"], - data["satsdice_pay"], - data["value"], + data.payment_hash, + data.satsdice_pay, + data.value, urlsafe_short_hash(), urlsafe_short_hash(), int(datetime.now().timestamp()), - data["used"], + data.used, ), ) - withdraw = await get_satsdice_withdraw(data["payment_hash"], 0) + withdraw = await get_satsdice_withdraw(data.payment_hash, 0) assert withdraw, "Newly created withdraw couldn't be retrieved" return withdraw @@ -247,7 +250,7 @@ async def delete_satsdice_withdraw(withdraw_id: str) -> None: ) -async def create_withdraw_hash_check(the_hash: str, lnurl_id: str) -> HashCheck: +async def create_withdraw_hash_check(the_hash: str, lnurl_id: str): await db.execute( """ INSERT INTO satsdice.hash_checkw ( @@ -262,19 +265,15 @@ async def create_withdraw_hash_check(the_hash: str, lnurl_id: str) -> HashCheck: return hashCheck -async def get_withdraw_hash_checkw(the_hash: str, lnurl_id: str) -> Optional[HashCheck]: +async def get_withdraw_hash_checkw(the_hash: str, lnurl_id: str): rowid = await db.fetchone( "SELECT * FROM satsdice.hash_checkw WHERE id = ?", (the_hash,) ) rowlnurl = await db.fetchone( "SELECT * FROM satsdice.hash_checkw WHERE lnurl_id = ?", (lnurl_id,) ) - if not rowlnurl: + if not rowlnurl or not rowid: await create_withdraw_hash_check(the_hash, lnurl_id) return {"lnurl": True, "hash": False} else: - if not rowid: - await create_withdraw_hash_check(the_hash, lnurl_id) - return {"lnurl": True, "hash": False} - else: - return {"lnurl": True, "hash": True} + return {"lnurl": True, "hash": True} diff --git a/lnbits/extensions/satsdice/lnurl.py b/lnbits/extensions/satsdice/lnurl.py index caafc3a48..a9b3cf083 100644 --- a/lnbits/extensions/satsdice/lnurl.py +++ b/lnbits/extensions/satsdice/lnurl.py @@ -1,4 +1,3 @@ -import hashlib import json import math from http import HTTPStatus @@ -83,15 +82,18 @@ async def api_lnurlp_callback( success_action = link.success_action(payment_hash=payment_hash, req=req) - data: CreateSatsDicePayment = { - "satsdice_pay": link.id, - "value": amount_received / 1000, - "payment_hash": payment_hash, - } + data = CreateSatsDicePayment( + satsdice_pay=link.id, + value=amount_received / 1000, + payment_hash=payment_hash, + ) await create_satsdice_payment(data) - payResponse = {"pr": payment_request, "successAction": success_action, "routes": []} - + payResponse: dict = { + "pr": payment_request, + "successAction": success_action, + "routes": [], + } return json.dumps(payResponse) @@ -133,9 +135,7 @@ async def api_lnurlw_response(req: Request, unique_hash: str = Query(None)): name="satsdice.api_lnurlw_callback", ) async def api_lnurlw_callback( - req: Request, unique_hash: str = Query(None), - k1: str = Query(None), pr: str = Query(None), ): @@ -146,12 +146,13 @@ async def api_lnurlw_callback( return {"status": "ERROR", "reason": "spent"} paylink = await get_satsdice_pay(link.satsdice_pay) - await update_satsdice_withdraw(link.id, used=1) - await pay_invoice( - wallet_id=paylink.wallet, - payment_request=pr, - max_sat=link.value, - extra={"tag": "withdraw"}, - ) + if paylink: + await update_satsdice_withdraw(link.id, used=1) + await pay_invoice( + wallet_id=paylink.wallet, + payment_request=pr, + max_sat=link.value, + extra={"tag": "withdraw"}, + ) - return {"status": "OK"} + return {"status": "OK"} diff --git a/lnbits/extensions/satsdice/models.py b/lnbits/extensions/satsdice/models.py index fd9af74f7..2537f8d79 100644 --- a/lnbits/extensions/satsdice/models.py +++ b/lnbits/extensions/satsdice/models.py @@ -4,7 +4,7 @@ from typing import Dict, Optional from fastapi import Request from fastapi.param_functions import Query -from lnurl import Lnurl, LnurlWithdrawResponse +from lnurl import Lnurl from lnurl import encode as lnurl_encode # type: ignore from lnurl.types import LnurlPayMetadata # type: ignore from pydantic import BaseModel @@ -80,8 +80,7 @@ class satsdiceWithdraw(BaseModel): def is_spent(self) -> bool: return self.used >= 1 - @property - def lnurl_response(self, req: Request) -> LnurlWithdrawResponse: + def lnurl_response(self, req: Request): url = req.url_for("satsdice.api_lnurlw_callback", unique_hash=self.unique_hash) withdrawResponse = { "tag": "withdrawRequest", @@ -99,7 +98,7 @@ class HashCheck(BaseModel): lnurl_id: str @classmethod - def from_row(cls, row: Row) -> "Hash": + def from_row(cls, row: Row): return cls(**dict(row)) diff --git a/lnbits/extensions/satsdice/views.py b/lnbits/extensions/satsdice/views.py index 72e248679..d2b5e6016 100644 --- a/lnbits/extensions/satsdice/views.py +++ b/lnbits/extensions/satsdice/views.py @@ -1,6 +1,8 @@ import random from http import HTTPStatus +from io import BytesIO +import pyqrcode from fastapi import Request from fastapi.param_functions import Query from fastapi.params import Depends @@ -20,13 +22,15 @@ from .crud import ( get_satsdice_withdraw, update_satsdice_payment, ) -from .models import CreateSatsDiceWithdraw, satsdiceLink +from .models import CreateSatsDiceWithdraw templates = Jinja2Templates(directory="templates") @satsdice_ext.get("/", response_class=HTMLResponse) -async def index(request: Request, user: User = Depends(check_user_exists)): +async def index( + request: Request, user: User = Depends(check_user_exists) # type: ignore +): return satsdice_renderer().TemplateResponse( "satsdice/index.html", {"request": request, "user": user.dict()} ) @@ -67,7 +71,7 @@ async def displaywin( ) withdrawLink = await get_satsdice_withdraw(payment_hash) payment = await get_satsdice_payment(payment_hash) - if payment.lost: + if not payment or payment.lost: return satsdice_renderer().TemplateResponse( "satsdice/error.html", {"request": request, "link": satsdicelink.id, "paid": False, "lost": True}, @@ -96,13 +100,18 @@ async def displaywin( ) await update_satsdice_payment(payment_hash, paid=1) paylink = await get_satsdice_payment(payment_hash) + if not paylink: + return satsdice_renderer().TemplateResponse( + "satsdice/error.html", + {"request": request, "link": satsdicelink.id, "paid": False, "lost": True}, + ) - data: CreateSatsDiceWithdraw = { - "satsdice_pay": satsdicelink.id, - "value": paylink.value * satsdicelink.multiplier, - "payment_hash": payment_hash, - "used": 0, - } + data = CreateSatsDiceWithdraw( + satsdice_pay=satsdicelink.id, + value=paylink.value * satsdicelink.multiplier, + payment_hash=payment_hash, + used=0, + ) withdrawLink = await create_satsdice_withdraw(data) return satsdice_renderer().TemplateResponse( @@ -121,9 +130,12 @@ async def displaywin( @satsdice_ext.get("/img/{link_id}", response_class=HTMLResponse) async def img(link_id): - link = await get_satsdice_pay(link_id) or abort( - HTTPStatus.NOT_FOUND, "satsdice link does not exist." - ) + link = await get_satsdice_pay(link_id) + if not link: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, detail="satsdice link does not exist." + ) + qr = pyqrcode.create(link.lnurl) stream = BytesIO() qr.svg(stream, scale=3) diff --git a/lnbits/extensions/satsdice/views_api.py b/lnbits/extensions/satsdice/views_api.py index bccaa5ff6..d33b76b8b 100644 --- a/lnbits/extensions/satsdice/views_api.py +++ b/lnbits/extensions/satsdice/views_api.py @@ -15,9 +15,10 @@ from .crud import ( delete_satsdice_pay, get_satsdice_pay, get_satsdice_pays, + get_withdraw_hash_checkw, update_satsdice_pay, ) -from .models import CreateSatsDiceLink, CreateSatsDiceWithdraws, satsdiceLink +from .models import CreateSatsDiceLink ################LNURL pay @@ -25,13 +26,15 @@ from .models import CreateSatsDiceLink, CreateSatsDiceWithdraws, satsdiceLink @satsdice_ext.get("/api/v1/links") async def api_links( request: Request, - wallet: WalletTypeInfo = Depends(get_key_type), + wallet: WalletTypeInfo = Depends(get_key_type), # type: ignore all_wallets: bool = Query(False), ): wallet_ids = [wallet.wallet.id] if all_wallets: - wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids + user = await get_user(wallet.wallet.user) + if user: + wallet_ids = user.wallet_ids try: links = await get_satsdice_pays(wallet_ids) @@ -46,7 +49,7 @@ async def api_links( @satsdice_ext.get("/api/v1/links/{link_id}") async def api_link_retrieve( - link_id: str = Query(None), wallet: WalletTypeInfo = Depends(get_key_type) + link_id: str = Query(None), wallet: WalletTypeInfo = Depends(get_key_type) # type: ignore ): link = await get_satsdice_pay(link_id) @@ -67,7 +70,7 @@ async def api_link_retrieve( @satsdice_ext.put("/api/v1/links/{link_id}", status_code=HTTPStatus.OK) async def api_link_create_or_update( data: CreateSatsDiceLink, - wallet: WalletTypeInfo = Depends(get_key_type), + wallet: WalletTypeInfo = Depends(get_key_type), # type: ignore link_id: str = Query(None), ): if data.min_bet > data.max_bet: @@ -95,10 +98,10 @@ async def api_link_create_or_update( @satsdice_ext.delete("/api/v1/links/{link_id}") async def api_link_delete( - wallet: WalletTypeInfo = Depends(get_key_type), link_id: str = Query(None) + wallet: WalletTypeInfo = Depends(get_key_type), # type: ignore + link_id: str = Query(None), ): link = await get_satsdice_pay(link_id) - if not link: raise HTTPException( status_code=HTTPStatus.NOT_FOUND, detail="Pay link does not exist." @@ -117,11 +120,12 @@ async def api_link_delete( ##########LNURL withdraw -@satsdice_ext.get("/api/v1/withdraws/{the_hash}/{lnurl_id}") +@satsdice_ext.get( + "/api/v1/withdraws/{the_hash}/{lnurl_id}", dependencies=[Depends(get_key_type)] +) async def api_withdraw_hash_retrieve( - wallet: WalletTypeInfo = Depends(get_key_type), lnurl_id: str = Query(None), the_hash: str = Query(None), ): - hashCheck = await get_withdraw_hash_check(the_hash, lnurl_id) + hashCheck = await get_withdraw_hash_checkw(the_hash, lnurl_id) return hashCheck diff --git a/pyproject.toml b/pyproject.toml index 7418de272..e66073c5d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -95,7 +95,6 @@ exclude = """(?x)( | ^lnbits/extensions/events. | ^lnbits/extensions/hivemind. | ^lnbits/extensions/invoices. - | ^lnbits/extensions/jukebox. | ^lnbits/extensions/livestream. | ^lnbits/extensions/lnaddress. | ^lnbits/extensions/lndhub. @@ -103,10 +102,8 @@ exclude = """(?x)( | ^lnbits/extensions/lnurldevice. | ^lnbits/extensions/lnurlp. | ^lnbits/extensions/lnurlpayout. - | ^lnbits/extensions/ngrok. | ^lnbits/extensions/offlineshop. | ^lnbits/extensions/paywall. - | ^lnbits/extensions/satsdice. | ^lnbits/extensions/satspay. | ^lnbits/extensions/scrub. | ^lnbits/extensions/splitpayments. From 41aa0743507b5ef62517e48afefa6c0c25e37fbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Sat, 19 Nov 2022 21:44:21 +0100 Subject: [PATCH 72/83] Add webhook_api_key and webhook_custom_data to lnurlp webhook (#1065) * add webhook_api_key and webhook_custom_data to lnurlp * formatting * add json validation to lnurlp custom_data * motorina0 improvements --- lnbits/extensions/lnurlp/crud.py | 6 +++++- lnbits/extensions/lnurlp/migrations.py | 8 ++++++++ lnbits/extensions/lnurlp/models.py | 4 ++++ lnbits/extensions/lnurlp/tasks.py | 15 ++++++++++----- .../lnurlp/templates/lnurlp/index.html | 18 ++++++++++++++++++ lnbits/extensions/lnurlp/views_api.py | 19 +++++++++++++++++++ 6 files changed, 64 insertions(+), 6 deletions(-) diff --git a/lnbits/extensions/lnurlp/crud.py b/lnbits/extensions/lnurlp/crud.py index 9cb01fdef..d02ae80eb 100644 --- a/lnbits/extensions/lnurlp/crud.py +++ b/lnbits/extensions/lnurlp/crud.py @@ -21,13 +21,15 @@ async def create_pay_link(data: CreatePayLinkData, wallet_id: str) -> PayLink: served_meta, served_pr, webhook_url, + webhook_headers, + webhook_body, success_text, success_url, comment_chars, currency, fiat_base_multiplier ) - VALUES (?, ?, ?, ?, 0, 0, ?, ?, ?, ?, ?, ?) + VALUES (?, ?, ?, ?, 0, 0, ?, ?, ?, ?, ?, ?, ?, ?) {returning} """, ( @@ -36,6 +38,8 @@ async def create_pay_link(data: CreatePayLinkData, wallet_id: str) -> PayLink: data.min, data.max, data.webhook_url, + data.webhook_headers, + data.webhook_body, data.success_text, data.success_url, data.comment_chars, diff --git a/lnbits/extensions/lnurlp/migrations.py b/lnbits/extensions/lnurlp/migrations.py index 81dd62f83..5258471da 100644 --- a/lnbits/extensions/lnurlp/migrations.py +++ b/lnbits/extensions/lnurlp/migrations.py @@ -60,3 +60,11 @@ async def m004_fiat_base_multiplier(db): await db.execute( "ALTER TABLE lnurlp.pay_links ADD COLUMN fiat_base_multiplier INTEGER DEFAULT 1;" ) + + +async def m005_webhook_headers_and_body(db): + """ + Add headers and body to webhooks + """ + await db.execute("ALTER TABLE lnurlp.pay_links ADD COLUMN webhook_headers TEXT;") + await db.execute("ALTER TABLE lnurlp.pay_links ADD COLUMN webhook_body TEXT;") diff --git a/lnbits/extensions/lnurlp/models.py b/lnbits/extensions/lnurlp/models.py index 4bd438a4f..2cb4d0ab0 100644 --- a/lnbits/extensions/lnurlp/models.py +++ b/lnbits/extensions/lnurlp/models.py @@ -18,6 +18,8 @@ class CreatePayLinkData(BaseModel): currency: str = Query(None) comment_chars: int = Query(0, ge=0, lt=800) webhook_url: str = Query(None) + webhook_headers: str = Query(None) + webhook_body: str = Query(None) success_text: str = Query(None) success_url: str = Query(None) fiat_base_multiplier: int = Query(100, ge=1) @@ -31,6 +33,8 @@ class PayLink(BaseModel): served_meta: int served_pr: int webhook_url: Optional[str] + webhook_headers: Optional[str] + webhook_body: Optional[str] success_text: Optional[str] success_url: Optional[str] currency: Optional[str] diff --git a/lnbits/extensions/lnurlp/tasks.py b/lnbits/extensions/lnurlp/tasks.py index 86f1579a0..23f312cb5 100644 --- a/lnbits/extensions/lnurlp/tasks.py +++ b/lnbits/extensions/lnurlp/tasks.py @@ -33,17 +33,22 @@ async def on_invoice_paid(payment: Payment) -> None: if pay_link and pay_link.webhook_url: async with httpx.AsyncClient() as client: try: - r = await client.post( - pay_link.webhook_url, - json={ + kwargs = { + "json": { "payment_hash": payment.payment_hash, "payment_request": payment.bolt11, "amount": payment.amount, "comment": payment.extra.get("comment"), "lnurlp": pay_link.id, }, - timeout=40, - ) + "timeout": 40, + } + if pay_link.webhook_body: + kwargs["json"]["body"] = json.loads(pay_link.webhook_body) + if pay_link.webhook_headers: + kwargs["headers"] = json.loads(pay_link.webhook_headers) + + r = await client.post(pay_link.webhook_url, **kwargs) await mark_webhook_sent(payment, r.status_code) except (httpx.ConnectError, httpx.RequestError): await mark_webhook_sent(payment, -1) diff --git a/lnbits/extensions/lnurlp/templates/lnurlp/index.html b/lnbits/extensions/lnurlp/templates/lnurlp/index.html index de90f5af9..eb594cec5 100644 --- a/lnbits/extensions/lnurlp/templates/lnurlp/index.html +++ b/lnbits/extensions/lnurlp/templates/lnurlp/index.html @@ -213,6 +213,24 @@ label="Webhook URL (optional)" hint="A URL to be called whenever this link receives a payment." > + + Date: Sun, 20 Nov 2022 17:29:07 +0000 Subject: [PATCH 73/83] Improved ad space function --- .env.example | 5 +++-- lnbits/core/templates/core/wallet.html | 13 ++++++++++--- lnbits/helpers.py | 1 + lnbits/settings.py | 3 +-- lnbits/static/images/lnbits-shop-dark.png | Bin 0 -> 12184 bytes lnbits/static/images/lnbits-shop-light.png | Bin 0 -> 14426 bytes lnbits/static/images/lnbits-shop.png | Bin 0 -> 14426 bytes 7 files changed, 15 insertions(+), 7 deletions(-) create mode 100644 lnbits/static/images/lnbits-shop-dark.png create mode 100644 lnbits/static/images/lnbits-shop-light.png create mode 100644 lnbits/static/images/lnbits-shop.png diff --git a/.env.example b/.env.example index e76296ab4..f90c10a64 100644 --- a/.env.example +++ b/.env.example @@ -6,14 +6,15 @@ PORT=5000 DEBUG=false -# Find "usr" string in wallet url to explicit allow users or set admins (comma separated list) LNBITS_ALLOWED_USERS="" LNBITS_ADMIN_USERS="" # Extensions only admin can access LNBITS_ADMIN_EXTENSIONS="ngrok" LNBITS_DEFAULT_WALLET_NAME="LNbits wallet" -# csv ad image filepaths or urls, extensions can choose to honor +# Ad space description +LNBITS_AD_SPACE_TITE"" +# csv ad space, format ";;, ;;", extensions can choose to honor LNBITS_AD_SPACE="" # Hides wallet api, extensions can choose to honor diff --git a/lnbits/core/templates/core/wallet.html b/lnbits/core/templates/core/wallet.html index 4bf6067c0..813ae7678 100644 --- a/lnbits/core/templates/core/wallet.html +++ b/lnbits/core/templates/core/wallet.html @@ -388,9 +388,16 @@ {% endif %} {% if AD_SPACE %} {% for ADS in AD_SPACE %} {% set AD = ADS.split(';') %} - +
+ {{ AD_TITLE }} +
+ + + + + + {% endfor %} {% endif %}
diff --git a/lnbits/helpers.py b/lnbits/helpers.py index e213240cd..838761603 100644 --- a/lnbits/helpers.py +++ b/lnbits/helpers.py @@ -163,6 +163,7 @@ def template_renderer(additional_folders: List = []) -> Jinja2Templates: ) if settings.LNBITS_AD_SPACE: + t.env.globals["AD_TITLE"] = settings.LNBITS_AD_SPACE_TITLE t.env.globals["AD_SPACE"] = settings.LNBITS_AD_SPACE t.env.globals["HIDE_API"] = settings.LNBITS_HIDE_API t.env.globals["SITE_TITLE"] = settings.LNBITS_SITE_TITLE diff --git a/lnbits/settings.py b/lnbits/settings.py index 73b0d6c9e..0f4064d5f 100644 --- a/lnbits/settings.py +++ b/lnbits/settings.py @@ -18,8 +18,6 @@ DEBUG = env.bool("DEBUG", default=False) HOST = env.str("HOST", default="127.0.0.1") PORT = env.int("PORT", default=5000) -FORWARDED_ALLOW_IPS = env.str("FORWARDED_ALLOW_IPS", default="127.0.0.1") - LNBITS_PATH = path.dirname(path.realpath(__file__)) LNBITS_DATA_FOLDER = env.str( "LNBITS_DATA_FOLDER", default=path.join(LNBITS_PATH, "data") @@ -40,6 +38,7 @@ LNBITS_DISABLED_EXTENSIONS: List[str] = [ for x in env.list("LNBITS_DISABLED_EXTENSIONS", default=[], subcast=str) ] +LNBITS_AD_SPACE_TITLE = env.str("LNBITS_AD_SPACE_TITLE", default="Optional Advert Space") LNBITS_AD_SPACE = [x.strip(" ") for x in env.list("LNBITS_AD_SPACE", default=[])] LNBITS_HIDE_API = env.bool("LNBITS_HIDE_API", default=False) LNBITS_SITE_TITLE = env.str("LNBITS_SITE_TITLE", default="LNbits") diff --git a/lnbits/static/images/lnbits-shop-dark.png b/lnbits/static/images/lnbits-shop-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..3dd677dc9a7564eecb173f7d6f281cd3fae11bf2 GIT binary patch literal 12184 zcmeIXWl)^W5;hDZxVr{-TNd|Vi@STWEDJ2MxDzY^0>K@EyF+jYkRZWbf&_ObXb1`9 z-Q;0R8MZD5X2dJkV0C_U5%W`l&}vs9c8bAyQCz4~=Y;{G@k zTZT5mL1FEA>{GfNYpund{q)RKRW&Io_@DyghRehKJnpZ}1V325zQd9MQ{1$g)=L0S z7wwjBnsLszJ@C%GMwcbNZx=cXFI4*S=!3?y+zZ!xsr4;Aw6#M3antn!IPg9{?c2|j zFA4|O2``i$UVLCXJd1SmyQe?H>_0Nr@o#t*$2W0wDfK{#X4$=_`lJ11?ZH{W+352S zM>e55Crzq$!5AVEQ9e6(0J^FI$C3Sx~Y}dpFSFdzT_y-O4T~+yyCUCH5j5=n&o%304vRP&0iYZNHwdqe1CEyA+6)zd-vrMUpq;}{y=uv zxlwDj)&2$;)|#b1fb&t89c6QuKxThC{S#|3v(h;5jZ^}u(7U0-bSKw7nK~Mk>tS>+ zhE4*{?FT}5_b~bL^shJOF8dDzZELPSFq=;NT4?($P4;DDGLGLb)mrZu7q9r-l)uf0 zuPygAX>GPmdf|QkeXBXO8MgssNiriY96?o06Dl{0e>oK82G`ojF^#*ChS?Bs-aMHP6$gQT*oNRgsIr8p1fziWpZ@tqAwCu8YZ;F^nMi_OEQcVLR;l zoOi12g?n=V$JX+-;>S&;Vgqg9O7cg9`RQMTA!x|5H~WT4c@WT?M)zcQrJ?Xk$V%^N zKk4$3bl$A?3Xi!qsqkP%+cVQ#E-fj&t3mU^ECVyfsyDORR#``F!u%gA&kqX(qLC{O zZt&9h^_cs(hy+ig$Wz)0dtzq4)1#o0mrhUyY}qF+_Lxt#w&w$hzj+roOKd0 zZt_F6(s?a2owJNdO{pX91DGV@XXqVPwr{0?V|>`dg6N=xt2z}f?Z%B!0CA+ z2Apf^eb#K!&mTJQJkh=8%bqJCdlhl)I9$xMH{U{5Mf)q()1i#J*93Q-pvChK5OS~|XVa5f&Zb;`4RJf$wcC&1G zE+**r0=jM=As9L>;kQ~rzn%O>)U;57qjeD|HmhzlB9z6G;%Is(8r9ep+vPO>BPElNltTS0F}_26gBFdX*un+ zgo_SM$pIav5rP-w2}$f_ObK(QOVVjYeeJJpw;g%&{E<21b=a-Z94+TucR%h`d1=q9 z?2f+1qbnIEZsh`jU0W-UEsefWfs{r0476ZHw`B2&Y<8t$n6O$tx9SQ#s!t%w$mZP_ zu0kf}M+XBEnsQt^?nWOv+*p>l$)({vPjEzxe8Qv>H-`tiwo9cI$&Ae-wk=!HwgZ_A z_NsQe^5gBM-6@KCWDh%0^tN(IXrLS4LlS!nZ&owP+Ma$aUZ;vjv-|Qj0oO8Bb=UwK zB}-0bcoEzGQ5)|I8b1#*vU9Mit}p++`BnC9f7;hccjp!b z*s~R-3)xzST0mI?+S-G{RH}Wi`(x}BO!wC_6Pvx?laEXyVGx5kDTryFc;?azH>GGx z$io%@{e=c+nejp9Jki|QsRUzd`U>HKI0rZ3v~-aO zAm&-d*@B{M^qf-j(Ty)P+WayD`$L2z5pJa4W0rz;(j-kIxjIq-SG#kSI+b0=Z~Y`H z#{x;ZcN6x?WY^efmada6da(hwWKqay)b`>u>k<6HA?Uf|NMAyaiYL=Tmo+6XSc~bI z^XcXnKTj*ubKCaB`MLLpDjX6S6D>>=tFsTdHfu|mmDpR|+Y}J@ zU~rt5^e%lSk}kq$z@xc z-apfE!qRz3lk2cK23H`xN{R#(58kq`(y8JYb?bHu2|bk9@#^KjrQjF8ffvOR4N!UD zRkzK1k4yEg1dR`zO@~@JA{9#(!c=n;HQJ|+n4OP?FgfE%Y_zk`$F7IwrKmZ&*lXrh z9?y}Dt`U!trA)lC>=WW@CnxrHuWa@0mb7|ZF-6Id-SCCB3hlcgp2(I1R$JMXz6S@r z7$Ft*0s;5ZAcdZnkn&@8XuXRrg}^Xfc;34H;YT@w4$aCHF+ua9%asyGDt};Tv`0Yb zK{i%^DCfy71{KFo%a`Ap7N0YnklHQDh*!6gvhHpw=AuQQEVg{!4x+uZ!8as6djr#g zZwy&4-Mk}{tGe2WZp-;_oZ2oQQs}EF8V$j)Xr3JC93_0X-dcx;MATkOixI_qpJL5~ zbf;=_S+QmS!-!|YsjHvXLDwu6SEPQT&k$S&`5IOZBF^m0FnM`x6?yr89MKU6^Q`Rn z530S|B>h3<1)Co}ZEDl-?;E=Slhh0_Lgk`Kt2AMWR=`LG6^^bD=K}m0S%QGabTZwG zXNu_P4L%!R??tmNUwpH)TU1F;y?h^UW3X}8*}bzqY#9Iv6Fxeg#O&ce^IgS^*}Ehi z*;kwQ5t_L7B`avfDHbpw+XbP1?pnw&Yy*>?eCY~e4Wlj1z zFtcnUG|oG&@vJFq1X${`fRn+;nqR;*HY?Tx);iQBaM4m>*LXem*1lv@QGa-7M`o7% zKp59ITYN%qSeq8&oAF9Q*Edsg^jBc*i>$e~pLe&2|2Xg7Q_{Z4dYM0a5Bu!4M^lv4*-h#My}#Z0&3X<@IrLL6kg5NRm%| zT)+?qs0Y0j)D{MpVmy2Qfsr0&EyZXgq`{}*A`i8LDf_uW_53vTA$|@JF>A)B(pZu{ z;s^jIs0Wzd$H@`yF76}6_y<=U(f-{HV5I*e;^830Xsn@4FYoLIr5EHC{5h{2rV}lA}hg;|L)aqC~E|ipa58qUr5*rp=%?+ zBM7mw=0P+BdB8SeV%B1!Ho`(e;6G5-5OGCkHzzP+I$=&=TPVNd|%td)Ocpq!`s%r81k19cd!@K`i~)m-d{ryJ22c9 zidf%&C)7XsVgHxO0tyL>itvjG@K{+}A!z1o@SwVTMM67@af~^I>V6p#1cXzh& z@CLg?^7yVxXnY$BttGQyFNNcmJ0 zWc7WPPO^QUCx7}r@U%fpIasDgLxuq3v4Sj-mcsCqHa26ZkA6onSxTmUeseG?Koa(n zhV)(V>!?ur!GkdN!3j6wVTR{|%S!Z*6XP9n*XS0j{72va=z2@sF!7KyDj^^taV8+J zc6KQ#Q24mBh`By9{FWR{%cSd$soM6sV*4zKYPweVkq~}9KCr}oVc;l{Tz@jpJUL1e z5>6@Yo^shSI6g#lJeX&m6}1|6!>alvW1vUhzmEE)?h1=Owz=ca)FoC`=iQXdkZ}W1 zTn<*fsF$3VT)G|w-(w={Gt}dAS7v2~mfCmh_?OB+|5#kd>mAVTH)`&(xn$<>jcf zFel$&f|g`D9!@_JZ}H@dGQ6i! zC*oQa1XSXOT{5Z4#U1b1($|4SF}Fr+;^!EX*|=!FymRUCLGkWFa#IEtceg@&Hhh+v zhC~*${f0t?SW~XR4*}l!5gTnBm#-a#`#%jBwwz_qn#^ z>XQ4!#H85hM_c1aC0Eo-i;rSORP5CSW5XwU?35(W`(_G=0;Hr&Y)!_%PiKd#tgAzGR4D6jV)Ebb~sJQ%M@(U~l?uduIvM2DG1m3b3Y+_fBQFv8&>I(GY z-c4&IWlmTbCMlxraWH4vWzM9)&9{2$1I8wW&{};s+IgY_(VDM`7C#=9lUI~g^JEO( zb9O3L+=*%|+0$;m9{E)&`YBM=T&kL4@cCVysEncZR434nd;WItMb^1nE0)=pY!Qm_ zcNgXA9E_0+nHW)G6R>)Yntj*GG$2An2ERqW#Ai)2R@3)_lz8>ZH&bJy-wJnB?g=Qo{kW96WMcmv?}mZA z8Q$Gc;#lW`Ad7_iG7}7ykk&Jn^fAdvMi1e!Wy*F#m=Y}dqU;BQ(yDqpCJNB;YGzpO z)TOdp(P))L@2yChQ-=(BPoEuiA5|^C?Qpk!PM3Ci~F2T*zm!2<<{i1~2yrI&n(sT;$ZeLf$-Jz=A`;VTzR#G)3spYz!JlL%UWD2MR}he>L>$5gzU ziP4uXasIyKt&j22_@k8Iq;zZ%7sR-mi_>zk@o3@N64tg;Cp3uETIOdj{+2Sj27mL` z{C<4a8J@RFpS|}Y+&{uif_hGnlu%m&GN)_kmffr_^0~6RfAN@9q90JP|Ajpto4>DIS%pMDsy;Wh3OEI6&qHbQBhXD5qQ zYY&MwwL9K>cU49KGFn;aDU_DvU`W+j1~ibCU?_HAK5(C+!ZH zvv@Q0LLncUj{ifHu<^oq^UXJCGL`KUo&x1fgUm-D$2~~b2E8x);bb^-IKkd+3E9si z$)-L6k-dg=p4e+By(jW*B*4PT>iFlr6_4L4AwI+w{p=i9X%L+e)=&B~mA2375pNxZ z1;JOACEa+*)7-pJDP=ZNpLyK{6+a869`SKcDkqu%(xL~kGp5# z>C2Jpp4}2%IN2fqyp}Xz@)tdrt08z86u$0)qH8*!5o2dr^EZg@${A13nc5`u+|MHC zaR4q0m-1U)EAtXR0W=ATh?2bEic<->X~N%7MT*K8@ZmQ<9Mz`wO%n}w12~zCGrn`+ z%aC4R%sl8A=KTEi3G6XZd_taz8qnZ^0Rl1-Ufq=)acWBdO4{aU$Gxp+;$iX~Gn+gcPFc63bQ&0W?t7!3nqW9&ZWz3VrLI_^!ZMRjOj5)iT`<{8F=kYCejD&fpoGtO z5lT%gsOCol@axO{kw)Q|wabyJn%}K{?`+Akc7BGGILu&Ek9>!`QgwrlTl3J^Js>N3w(^xH#z}FdT90!nDT9}Ffs+=0l0y^FH4XO4-_Qc zFlQ3VI?!&gIpr7@E3EGFOHhFFzu2h@)M~LNF<0u6SQz)=bP$?9%h5HA$jlZov8VaM z`(53ZmnFUo4__i!eX&ZR*pue6>EZRtR~RriW0yWsav(7Etu_RLI=qv+EW>1<^zjFp zZ{r5Ef(u}ms5Pa8HZp+NGGN9BPNy`=mTr>W{1QQ7^zShWv6G_N5N8+hDRrVrV|?5}^;`-^RI4yA*D?Cy;{IYTxmmYh;Pm;YrN zw{6uBy&rnnAxzSFu}d(KRJzxXxUu}%j1gX2u{tpQx^oBbq|v4Jc&_U084NeATBErk zUZO)RG@vjHz_UzZ0h*k+iXE0K;TLHtN-!nAsbXB>||$Q)^QNYDhUFR2iD{kV3mPHNM>) z&{Y!VExL8QGjBZ9a41d+F!vDCU=>{$48Y?)JklK$vBp!;kOFjida;;E7WtGEr0B1mT!>B9C_bo)Mo$a+(92} z_eo=2^R{Z_kr+iHdP^D4)yE!aFrZp*@tZ_CYOl1ogsQ#Bj%XGG5-j=w%1>4RM*ZA9 zjVv>5{-W^EiY?e|Q zP@cP`o_iEkD%tC?Qr*oh+u*q4mADgmj;qAmr}QH6=#MP+uPnIG^&nC9TYKu$QkIe3bcfaFIa1U3#{N2scI{dk+$-f-A{(ZI zJhK<(BvRKXBSF52j(Wc)c~RJWO@$3khT0ep(ffg4u(g@_KEL`gTr?&hIK;6qQo2H; zTYE|Sf?`xi&>g0N;Y2Y+P*Q%7`jbeG3Z^daO8Sj&nO=@%T9EW!5NA>ua~SiL#hLp#j{H59feS+NcK2-wT6-R@#h#Byp*YcG7Wj~ix%yt!`3gd4SjnA zS$nOT{fj-Pz=3o}wpu*sz!}YF5kQc=I-3J7$%~?b_q*{~j5hoNP4V{hx`Q66k4fTI zrh^~*CS{V1Z@g#@h$!D4g497OSy0v6j)a${U-F5!(I)SlfDWNsUObkEz(hk``*F?k8TQ zj4_KUcV@wj&%s%louR8OK3?6C3+V=(#g%qGK}d8Xsf6{>esKB#)k)kosv zkVt{1a(8nC!%D56UAK3EUKvmoostI#eEd+T80OOO=nVUaCn)0jS^b-Lv9gttHdh1b zyEJYO)^&y~0vftgFVOb7-eym|X_C=d`yek^!?NL78{l_VJ$1^O?Qlq~B9J)+X`N#_ z!GRb*yN7cmqLf^ggNkZe$1qi+>)DsY_U6<->;L57XLR&dTy2|~qV|ctADv}1)#B=B z*Eme%ADb@Yi*eOa0!{UIJ9O4oSRNQ+h?wyH5-?iL`^#DBt>g+(wz(V%1M_7 zCSH-5Th{NAD;WxWWQ}zU1jJG$(|ru0`H^MLGC)uBS(3EVdr=iImo37ws#x%Y-q_MY#4TqWMZE&(O_qlWk@?;=~iG)0b-0) zx58h$l#&qp1RE!i6Lj_1^Lm+nl7XhM)KTy@=g0ThFGA(c<+L@1&U3H58*OJhxPJ+$ zWXJ-QSlTRc@@qDUaVg1YJwf;RwENYy=(gGMrZI6@BsyFfqoPTQ@}e4ozz)R((~6Zf zlL#fs9lkP5H4UURN!x&a76pH$I}Q-Ql0GzUmiqYf4`~C87IFRdg|VZweV_+P_I}?Z z)}SK}OQ4U{!()p}c`M+rS)3~`M?FA8bnh%Xev?UplWru%)u@Ziy@Y+ zZQuaB+&jX``+k^pB?Kbj@+Q-uUboD2*310L4Rd1pu}?a)wEpE{FY0`EA&Do&umIj` zm*AAZGEDn2IF-t#V2Mf%pKKsx15>nyw?RGW>tf-iW!Rq$c%@2v|d+c+(}|`3^9=6Dg{jPueFZggp@}_*(>=({yH^pES_dN)AZl@fmjz^6)1=IC_^l}_G#*rP zq@FMp$?V9&1ii5dVAzKdla^~C-n`SnU1U0YIB06@hnCu%7aF9hL)gZxDL?b*%lEGC zE^Y506EXD~wqfikWXszDb4j=C*Np8Tia-{L{9Q2ma3xd56Hs-t2(rluhqu!zkga^XF^m-_@g54wu=@vTp@)-tL1W3Z4uo(m~KG zjR!EDt!u=^3r;RfY8D;Cbp`i$;rToX3qw}qZ%l?bM3!KMghnn*n2jaK8?Ut0@st+( zIlHzzV3s>D^&`!vcP=q&j~2Wxkamu)n;DbOBPy|~|DB#u&+^V7^M>afh=SDD6&fTm0p~m0+A}i-XP<^y&3Lq{Devs z`ruA|Y7@D}#FEJ#jy|?}Ko2XS;k#keFyUYl>X&vHG++`~xzMF}Rh~W@$2T=wRc$9d zxT0$;W&oxBWuCqos3q;>LGSHWa*YpGM$h{ce{LP^&;rmtsmrf&TzwumTa|q*3zn)j z=cCqSnKZns=T9JPxtKRD+JQ|`IaXUXW_GG`$>FU%a zd}OOqZbJ7LVgF#si6uM^{NR^0Pn4XePvR2t3*GkPTp$|%5e?!x6-fo8sZb;LJoNtn DL?vxi literal 0 HcmV?d00001 diff --git a/lnbits/static/images/lnbits-shop-light.png b/lnbits/static/images/lnbits-shop-light.png new file mode 100644 index 0000000000000000000000000000000000000000..96607cb44fdc82d96a08009f56b2094b6ced263f GIT binary patch literal 14426 zcmeHtWmH_v((d5y4oT3U!3K95T!IFdVHjX=7~I|6-3bta1Pg9KLvRZcAb4;M0TQ?* z?|aU7&br^9v(~-;&a5@FdUsbnRrPdr@7=X0N?lDJ2a^&L007`9Du6Tr00h^^wg@`% z<8Lof>l^?;tmmz*=c)w1n9~X|pT5aYDErVFZG!l^ zr|t=M5ZoKB^JiCrW|}edp+#gnIaP%a+1wLpZ|LFTHcD?hOq?{zexRlwO?P} z)nw^>(!_B4#j!s`xaOEEPeS^oO+uwQd{6=s`MnFZR!zrI>1*gy(%Pr;Dy0X5gfDZ? z_wW(X<@yZ?y3<4RM2=~jsaGT>WL~5^Dao^2s!5djz8>{%{uryw7MVI zzh86Sop|dvbDOasF>LVDlD#u)I_k)3UT|qCfwp+PKb40NH3kG+O+~~MX0a+7(o6=H z=Y}QiVJfRkr#29!aRc>48Qag~kMl1_DuCAk+efhNjE=GgK6rxWH6G9PLdP%T`FLyV zZi+kCqF_qk7mv-3pr|p+?P=VS{yCT2gLql!(9=&HFnqP$70V0D!6v?g&qIE%@c6Dx z8g`wlO;E*3jK|p~SF$~1sU}R=y%*)<1SCtI$lLN2;3;jra}bR)^KuN`IyDe$Ue@X^Zh*sX$Q`?OyZoWDZ!m2YX*J~5!oX=ug zS!v5AtGrg5jJy3-dp*m%Ixcn9uc-;sT5S)*3~bzncn!0~sSdd+>p;yNS9YbdOM;)Q zR@G)5BrG`I>nR2#z~K{mx~fFn4IVp|WwAIzXX!r7)|vCV%Tee$IrG-1vT3iqqd&gO zzff;0qt}l$kKB}0g|r)f2U~r|dMU{F)%BMm=27v{A!C&fe!{Cx(^VP;NHF`$%yf&l zM(@iAF=Xq-zbze?y8>~hot+~@l?3I68$FzMqBMiZPo{4*cj*xofsk{ZVDlH z=%G~;Cg*Q9$~MaG;6Y_VCx`Y!D7(CjD9jw?vswNGE7gr`x&A;6Qy=_ajXsBLO{37>YR;dH+q0Sc(nJ zhJ9_8BGtG4P}S#3DJmKoC@V0?nMZD+9s%4pva+T5Uy1a+@7k~P>mz9h@7pyD~{gL=fW=z zxN0vH@+7isgybncr75Dm74a0eKe_XC5{ykWG4P(k2j`j7Yjo~5A`=Y~7(LaYQ)t1R ztDp1m8`b;K6{(hexws3Etz(Qu#@Et>eg)uYi+pht4rg;V%^d1IMtmjj@g|{_mi&BF zkaO1iWogU-@dj27)#UmO3XWdJ4$7d4PC}W8oIO3!$1X{;@`SHM;7Pd4>*aIxl%&Ik zOv6z19<3ceNz~7A4l6JX8KlxTc{KDLQWY_*$mLSf>ETa2EGGtV`=+0CM91nIbX*z!13 zQxYX|`oA0pPj%MeBcOa8#!^9y^|V!$XVIvYqy)!#&r>3a(;{N!$=JSt#K)yAgBn+o z)nsDj24%Daub5O1d5^LXw@REs9%lKJnQWGCt1yzYjh3=%f;TDOA55@W?eX369&)TH z!Pm@#KIgfyOeMXohObsfXCz>$>SH&y@o`ZO2kWy9qFLUEMr{xuQ-4cpt$#)dgmdvrhQP@Jax zNk(mM%DV1S!p;o&X!J5geaFgjEGz^Zzj=`;zX1uRbgcy&!fuf#pB78#x2Pu{NI}rOvUdv|A6#YbA6s?F~3$@LQxZUUk>D-8m)Y>-_3;AJnZFbwo8fBh0VI z@e(`Z%-pZN_MT1i<+m5%6)sigpPDx`qP`GIp?Aj~Q=y(wOWB?ZYD9-AN$>_bupI+z zTH%T$m_f&?dj)18zf5GSw90Vo3dy)R%+QJrX$0S3yagZ)f2xc8uI`VEID>q80l?#B z(jnZZ9z;}4=iUAh3&IV=;xz}5S5EnV{SYHgiI@F~kj!F;!g(c#++lz<={Vy-4WX|> z-6<z4?9(@hqT#=5^NKU4(pgP21 zW|gZM4o%CevgmN8bc#alU66qzA`N!Wb1Tnw zB3v-`iT2xwe`2ghp?g+n&AH^^69kgr@WzH=BmB5QCM z-nTF9B!7G0nYeWnvR3XZ3kbS!nnq=t5PnWegXWn@9r*d}CnSP`lr5CT=xVuSGbb~g z02;LP`O25kXzXgY3eN)5(XdKhn8jvRw6u6gbxXA-BBIBK=7wg~Bkg(w?CGV;mI)_& zN*U4FSGwb#AYB!yHM@JJ*jpkNk17&CZ=)CbPMRn9FF%WQglD)(js?1>-2?#xe_bI-DoHE9ichz9m7@5Zm9NN`)i@GULVL()~gSG>^?fP=snK6CRC zNh5)#7)u0pPXg+jF}4JFe@Y?4xt|t2#fo9q$n@cut>h;~I;`_VijA&t1fluf6+R;% zSm&D;FB=t<*&(|dr$t|%uTN6{kl=tKP7}k^3kp+Q>2puE^Z_9phurR|JX`j#PH8z+ zc^-j$H4xlZNr*>DzoD;Z8{A;66&>v&gRNz%&ax1^_=NU@YCF!H^>lPYuV77hY091} z_6j9k#0TTO?DUH>-Ur0Lj2Z^>TC+3*^aIb~HoM{@Bt0X18G~rU>i>6TphwL~2(5F0dkK zc3i!rd_OHcWP;XlVH0l|U&jXS{aW@l!&~Vrj$5)lIq;buNj-x6t%fMU0k>{O+M0$- zN8EiMiaD|A$J=~@l<)amUM01YbGKAQeSU@g22U`siYmc)}I{87b1*?j}wAh2j-_Hds+cd=>v<6)$ zuB&%&3YSOMa4wkuytkbq+{q-}(`1kFs>|fH_IMD@JJFKSd#gPf60_;7xTvO$650Xc zdT0;EnCDTXMv?;7k{S|sX?>|2HB(7)f)=xwT;T&NS#$#rU2g~*H1*X7M#p}LFNL&K zM(Vn6-&zau2`XSUG5lnjDHi6-3h~g-r1!nY_5Lx)Tp-%<6Oh6;T%|}+YDF)yP7cFQ zyi>R-R?;vx;FL|VUM7{g4OgeDV|FIgMb%F%-qXn;wKcav-1}Ioao2?+>&5x_5E?mh zv@{y*B^B3-^jxk7F3DJUki}G7);HcipGhFvcMI*A{ESe79Br>tT8^U6R&KPdd`^Q* zvLhV>`Jty=^r5W-leBne3>g1CrPg+Ag(45*Jv#}{A1&U`_lL%vQvuAh|^Nttmki@r6g*NSAaF6V!YF*6ELK7 zl#qHF%?{`CMW1KX6&J#*)dA~)rR!}Qd#C{HQ0gGdP;-ZziL$7>r%O6=;p}cLcv$E@ zMN@^IXs1-Yi6y^4!ZOP|m0(R|31(|^1PzJRQhhVTALLPK1Ybj!D@tEPU}Qo#vb@9W zo`THYa5Cd&U;p>^QPeq$Y?;w{y%QbBo?d5iR-=e2o72T| z6^S!nhngbosz=6}{y<7IN7aVy8oj~rQL+z=jsFEA;x&LRq725k!xk{HHbEd#6)fa> zWHIK#FpDR3+uE)@(!Cx1FWWilcPkLS1_vA9*zGSRAc7iAlb-S1cqMx$K|QG36x#Po zFakg}8w5Xha@2-f`62V|JprL6opI7V1ELS=9FM52LTy`9-FcKD)GGXGC>W z5QlcId$ul{^ftZcuJA>miY`BX^?nc0<@wtd!qQ)_=eh8`k*5eWxT8ZV3@jGsUz>F- zS{a<~l+lGiGVA=DEE2cyRM zrv$Adr0X6@n66p3iDrcdGt5Ut1YfQ!FdZh3k(I7_=$BZf#U@jbUro5AFHBY!6wzN^ z2@ycijJtPQih~ssS+{2i;BuSF3*VflD(VHuY3wYA-AQzSvse)q(2rn%Wrn^>FD zUOg3pVOchR|H}HgD?bp@Z-4;suG5_pq_W#zOFW=>Iw#nlIp-lSHNnW@Im|YWNP(He zkn(mh*`e`;FxA&$KX^YvW9ySO1GU+ib;HX->b zE)~YKx(kV?{67$e_L{1n;@}2ODDh6aj$`iOs?bYbtk(&w&RrJvO1a01=(YfTy2D)7 z!yJ$te8(nYy#sH>n_4*p7jqV|>*%HZskrt{qts0!Lb_#Kq{53|@??@HS_v}eCA&^e3;tdT z?Qaxwe0#FUE_a!|iy0A=qzM;=>rE>3@rgF*e_eeUKRiSDG%^?(9N$dS6V4^B)SB61 zzK%smb7}Mbx{{mOGqSuH>&b31g!An>#vL?$Lg%}K^oKkA9etfuzgK35yrOvHYnOGX zKXX*+7S+zY>J6YE9A%=C-)L`$8ox1GJ)>mN;gAz}Onhm#n6 zz!R@kjJVwklF>co1y8<-UtXleE!br|I;16wH<-@c zQ{}?PY6=)rPKRbzEcwPc##K$5!bZ8vJwIb-aWNJZvyIIP^?_gRYvMb-RAg3-oXfF! zy&7#jXBf`<{(CQ(%wx+1G5mL)8$j;QgxDnTEi5)U7%XtYT6KQ zTZoVaorE~1sHgBFfIZX|Oyg;9=KvS>6r=ltEBx60-OWiy^GC$hR*X(hRh>r0(FIDw z%fZXR#V+d!a|hCiW73GaSXc^cg5>^&c)Sv$vvzfL66WOe@bKX9;Nfs|vEt+w5)$I% z0&)U@?2i)ca4!c}uqV3%oc=e&Ul<@L9O43Va)miM(EP>(n>)I>iqX+Mj??_ZKYJ%t z)qlb}!2f39kq=H!uoEXY2N$QkJ?Fn_z+GkCA3^?h=zrCKYd@B@IW?hhM>iJ;RMs8p z;7b3m5EhVs>N~l)*!>B|0>TNkgW5le!XK@2|C>p9MOF2GYW$|a3TE&0N9&R7f0J~D zS^f`M|K{88kw4-5t0Rx<|HS<_>3_ujNBB`nRaF?|2yy%Eo+3z$?zeqm3r7gdLikS; z4CWFP;IZIg=j9U+WaqWygRq0aP%yioAeV(87g&fF$j$#RP>K$4SFi&F`WxyIoCEfV z1LWhi1PTH9*|`Ov5O!V&n2Q}OB*@KfVJ^VS0}+5)LV)J~0`bxX_L!AmyMOiSHg`&d+1c&knYD#N)NF;AJ<5@K~~QLAV42z!riK3tp~2P!!0 zPA3PeKLfuB7nV|26r%%j{3ZIQN8JwWYWb)jMyCREaP#~hQEiw#RLd3on@w(henBBV zJ|H&_KOYw#@UO7{XupEGz#lX5Hzqe12hU%)zo$j`F_=eU!N2qL5#S$D3d^`a!LE)j z+K!HPVsyVDXnt${NpBj_za~Wi27i?B`knEA=e!ow`LCWPU1fje_0$@QfyCo3F%g!sv3uG7M;W1|y zfSU6|EucW5e@xat(czAkt{z|)sFc-Xq>s@&CeWW~Xqf*{$@1^McvwS!^ThSIwz;|4 zfn3_$yu!R(!rVM;TwKCjTy&g&2h90iyOCxV=2?R-FIb zuKwoiH;w-vKY!1~|3?dt(El~^AMyKNy8cVof5gClB>dm(`Y&Do5d;5`@PD)G{~2AF z|8wAhIy^oFc|0CxG7ofw9*;tZ=F0LQz(YjBr|!oq3?~JBH~@e}^!tkd$j&8y>_l@_ zRFy^B!6L?G#)-o>x&r`6xD`QC+MY{Cd0u8Z16M;5yHHvLL<|ursrf)=^cFhJbZPcT z^x~!sj;4ynQp_fl7wf@n_K9Vzr1%;d_{jQS@S!*Q?$Y|mpbuTheaVu|9{vGa+h^&m zCtt1+8HPn}cA>|4t?*s{-A~uKLOk?(3IR-pGx*X$<>6- z7j3!mycQr1r9!Q|uJi@bZDP)PSfLyxkdBOL(s1&#oCDKLX4ZZzF9h_l4MY_c6Jn~h zDtFA+;R36J$Ca^$Stx;#f!#EPDZ{mPTVocXKMzsR&bk$)i}_v?9;SiwwAk9(kK`7K zQHR6Yu*<|+eM>jDKv~~><646F8;en+v>D@Pwi3tufuG0J=2JNMQxpBw$h!N#pMNPs zxU?)q9@FnZ?z#l;3QXcT_KaDYC|p$z@`%ehkwS*+l6bOu89d8MdGdV=QDH`?Jq@7< zt{YxKUFeB@EKixr)aDvlug_`heUsTV2`XMLo10fI|A>G7A}Is`)7GA*^nep1PF${$ zJ}r3XXSQ>tmpBZ^Gm^PBm0AYb8?hT6bZ*z6JKa58StvwwBgWUENqWwB0|2$!Y@=7j z?N9d3`Heb@oU9iy@kPI>sh>!EPS(S`V154yy@10W8o*aVkr33JmPT4;40fV@pkd;~ zD72Lorj|T}j(~7Va4CY|gy(!XKI29e&Nzssd?CUCIq|HzU~Y z8zx6@$>5mei|3GPIkYsX2q@BDQN^AsXJ}6?^p|{4gJKG4c!yWaZ+)mUd&WAM=9Yo# zRw-Wxxc)LBjUTB?GJ)PwB?%s$I z_4;uLc1CBJ-g0w?lmu=rJv&Q(3W&~`*d@9oxA4^0gN}qX5d<~YP=n`g=HlL~bVlR) zM~$``pTDSlg}O;m8|M}LBa+1i(c8A*8|BN9U7RlVIR#m?_dvafG|?A&5SW~Rzbq0f zQAoceo7S=(4#gZ8 z{e@de0}k{1n)A-gG!G}13O<9BI}R<5yPOD)=+@CT_TDo|I}BR+kSFF(;h9Xd3A;<7 z@r^r5`|4?)p-+G#X7p_O3`65V=hov#jU_C6kxV%SH~Cq<&(!@&Wy?CVUZ)4ZXM$h! zPx>@Tc0#Qq(;N!h`RZ~f@8-bX#$tQ$UBtKx7PvLRR^z+)Ilui&HWA&0{Y`@}3s$uW zEyrWCuK?MlRl&1B)06M4y+!O-Vq?6kIVA^IDE39%>DBf9oD=VoC)oB#!rScN#_e)e zH-5@Gb4N?up-i*W;9HrVSGRhGXzXPUf!?cc*y5hoUa>Dw0q0s5&%Gpo!6i^LY$Y?n z>JJZ}C{;Zy&l#FsJ zd`r?~YIbY&LwTIq{&Rm_|eu{WGC7;z`1r?eqB)N zR!PyOmTc3Rc#9`J6qXQ7#I6;+hzVD8EhUTUMsDxsbQI$#^(ZC^$~s8-*>0kZ3sM1$ ziKVW^yPCFIyd)Aw)8@s=H=P0Yt;+XrOC|-lSg(l7=naJqb!(aLd%SYjU(!(s zej;ad?t%PRD^tz_vEpeW1ZH=9N@$x>!Doojs7WwL$T5~Q9U@}9P!C%*LXxDNAy*5R z&!T9HzP1KYAD1IsWI=uD;dQcfM4mci??OpRBS_9I&4((RUBu0CT-{D_@gj^e49WZ8 zw6hnAhGqO_fZ7|RFRYki8F-P3wl+TiKAIB`^?NGe+#?C!bj$?}UF{=PuGCnOC`y4Z zed%z@5|4y4k75h0$?f~_pOtNWX&3!sZ08{+?XBx|>gD4!(C@G^+x z?Y&Ra21G>da?D8BmK0r!NS$Xlx&48wTJJw6dU#r+RWZAw%~ft+XN>Ft;10X9u-+G| zeFeR4J20H4Dj~0w)_J7PEnrY3F+n7z=sq3r`2`_KhBM9N4|=t#D$U{DX8S~b(IMQt z+Fr07PT`aLkumKO(dwI?jb{+gtmZ8gnR5bRMa~=0cZHfKiC(T>RUuiOGW&_`*6ax% zGhEbNp35*!hqDjf3I9M8^CWI7KYV<>$~n80lnZW@!UJ8%d)r!9g*S6?4}(UXO}?Tn zoa9K`q?jcWHqV@UNq=3J7Pzm1@bSMWtYwhRPbW!cDTn4=Zi``UL(Z*Ld0YckmPQDv z+tO{YTOG>Inh#oIa-b!;mGa-Htq+}hEn+9f=evw#U6KiWy`=KuBFI1DhWwHUPN$v3 zf?C#9xNEp`k6zKH>}i{yC(E9-ETqJLl`@|861RAm29R2};;U->2p_K>VuQX7o4?Lz zkF)vezi3G=uqGhPaj^K-O5Eda8U4IEscZHOv2Ac_?tAn{-$8D^rgiBy6OjIp0+N>F zrx;ptHvJda$CU(37sf9Mm%=HKj)k0Ro!gIB!GVmnZ5ica%^d6AuotCVTFK;0H1N!T9KZ693yYnl;$zWn8O3j_W9zrVn-``f$mpi* z;NOn(ZxQoPJhTB#I>qdsysJY!;=1%Lc@7|t`z4)FJcNE^AAZG#MXvckUPj{*zK|uI zPpx$_fyBSd?P2Dqo4)A~r_+S2*0S-=nuXKp^HHx&uli0yV8)fdeG$o_7X3{!@$I=E zIv%I|HNG#0VWxuu-&7Pe_U49I_}#0>x%xwLEG4^g84moaA37;IE`3OQl=1>k1jX*( zS_lQiPweR{6#-llr9OS<31z+Li1WjWzKj%m{7cKc;I`rm=V~~`DE-^>%;Va=IBZMI z0-lijrOys6L0h9}F7#J>6XpDy@kgY2_UnQGbi>&7TyLLUOPwbCS^(U&jJwjM6_~nOCO22P?5EaW3T~8_C z2QQtf(3xlTN~qJH%u|YynxjTB={?P{IX+19|0rwXa=r&_mPcv&!K(6u_#x2(Eo$io z0KeSH`8q{41fs0W?3WbyBUXrTbSsP2SaQSbfi|>_+`^fYqQ3J+J1{Vykj>+il4`}6 zKRv=z3G(5EKnMbj1J;n3B1kMo zJ+2{FnBy3beA7Pm8TSSA)U>s#uQkFYZxL0K-xzUz`VsWt2dM@rMW#1bCFpvch>vo> zo};Vw1>OxsQTK>tc$;vwr>(1>^pLG_4$2i!N)u?GUA)Zx-S2(X6jmH)YNe|aM@#wR zLGwQBc+xCC`}WmzHLo|J$B)vd5cJW}RTkOgA!Ko^q)IH0HpM8CPhsH>o!KMF7u_+j z%v38$9;-WhW1_vdc@<;9?&Fr&K!ypHq;xq5_PA^c3#PoCI9j!K2XUYB&gjG8_Iu{0 zn0F-!5_dBmZ#IOf?{2Vb&lNF9r>-WKnvX}VIu6m_9YTJFq~dR4QC-OUy>dZXN$SV< zK)$I5-~yM6ad{OyM&Pyj?5CU4+?OQBqOIv238%R;@53A7qer{wTCJWRM3YNvd(iUcav4K4N&l*f$bAuu9;Y7_-5~ zODelStT|S3@$nLk|2Tz=7gLO5PhM?!lYg?x+P{GmeXQJfNwcA=D+;2sXM{Ya$yv3-89>`)9*gqJm zMej=wa(#L|gCC!)Kv=6$2#-4uVLKHJF~a48*5GWoEIlo77K*x0@@I8jN7?wHw`LaO zb*xp=@&Vgsvd27Z*$ht3tp*!H{^qhb$n-+`d^4cM)nS>2ODm6)w>f(Fy0 zJB&YhU}H^2gE_nl9-mJrvP(61H&~A06I>44&|qqJw_szAXUn0>ZkkgHMcd3L!h72; za+*k332;q{^lFtbIh7C1UOqz|dEf{xaf!+Fh8td6a;1#S7O{S43DIv$ z{jx=)U5a4*O;N@pVsV1Ut{EJ;^Dfc>gybCCQxr3@>2jOgUoadUeqf|UFD-_8L9=#I zR%0cxC>T|Q$^K2oDg(}uA<((ep)_~f`mNs?N-tP87)0~?P59o7*5X@JGasjyQv`3!P+LfomY$Y&SSG1mnvd&;)&$uY zIW#WaC#WpBV{anFJxzTc_NkEizzI)3l=wR; zt)K5cY7{Us(57y(7zF3;$Q+yTwttCNFQUsxl7>@ijNx3Q#BQJDTj9VEbV*!Tf)kjIR`gE18wS#4-@S5t6O2r>B1}f_p>E8f>(6H^!n%I z2NVGm$onySAE*xbeyqdw#{jpdaldea9&ak9={G7_Tkjf%b(qx_NATOup4g5wb6Iz9 z5`=rdJRVl8+1bXQuy+9_4W2vn_>4!e7#Qtl?2Sno@)`HCpX>D?1;jPH2c{t)Y$~qp z8Z6ql&jYyRE)f_Bkp#2)Of^3UQ|nVraer!9#MEQHlVY3tU?qG5z_UgZ=CtwPiA{-)21_Hj#x?@==WpBXCEPuEKR4W8Bx0;HM9E;-Kz_7zFf)@*u1+o*l?46hW9Qu z(4!YvjX2Xfwyo(a=*F25SfL)zz}k+BIJ^N;90%&q2H7yEOOj@786XOzD{0f^Tb~Ol zk}kUEzu9h$x8yCta8slSiUv6+6XjaqQGM<)cxd`w_PHK+X*z12mmv$YKXFL$`x!lz z-na)s`9ZXDOG?)LlEE?j{f6V-h#N0WkaT=q+Q|*zFJZ{<=8YxUdMx={5g%AM*U?+~!0NP46n{?v-F&8Q(hrx^7ib2luG1oaP3 zPJFm2$DMRpkyZI-r%ap_X@tI^2{O)}jE7=B^?WhiM{qNMC^pt>|HLZs=ZhrN_+d`H z65U!1v UjA_otdMZFsRt;1mZ5I500Kbg9&Hw-a literal 0 HcmV?d00001 diff --git a/lnbits/static/images/lnbits-shop.png b/lnbits/static/images/lnbits-shop.png new file mode 100644 index 0000000000000000000000000000000000000000..b2320f3b663aea9728cd5c56e692cdc74f596cfa GIT binary patch literal 14426 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 TGaN7VRDhzaDzHZSUC{pl*T1#i literal 0 HcmV?d00001 From 304812060916dc2646d35cf74e53417cbb213720 Mon Sep 17 00:00:00 2001 From: ben Date: Sun, 20 Nov 2022 17:36:00 +0000 Subject: [PATCH 74/83] img not needed --- lnbits/static/images/lnbits-shop.png | Bin 14426 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 lnbits/static/images/lnbits-shop.png diff --git a/lnbits/static/images/lnbits-shop.png b/lnbits/static/images/lnbits-shop.png deleted file mode 100644 index b2320f3b663aea9728cd5c56e692cdc74f596cfa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14426 zcmeHtWmH_v((d5y?(XjHg9Zy0JQ;?;-QC^Y-3dVh1PSiJJ$Qn<6Ce<{B=39VTlf2O z*1GrKnKiT5-d$BsS3OUwGEx@dshDIJ{b%`9yolrEkQ5K4%Lr5OO=v0R#^m$t=^E&JRWWei=`T}O%<=Rp!HSvJiA9}tzdw7h_pV9P+YBH9u4$SBNqL9oX=Hs{fKrZ9C zv5~LSxv^P0l>fPtfDRoZezmt~ERlaPba4hJA-=Vp{mZhTv&&z%>j{){cK7R3;LIM4 zwcJm?PMFv;Ng>}S%r2O*$p&e%j$fWgqZ0WWM-rfK8^xby{BwW2^|J?_5#Ek4dBzEy z=Uur&>pjmTGx$e*b`HP+v-?c8UKl(5M3<9%Vpo;$hv#X_vbtYM_8a*!Y2O85@il*b z%&Si7EZ^P;GW7R*I=Nt2w)Y>FILm+X*_-Lwn5iA|j=tb2-YBZ|zs>X8;QJV*$6Q#m zA^S^r^C9-CqPNK4HoS6v>dqW>dVTTReC44EQ%+sqX46(gq|2J_W+c!0{@Gq!HdETR znw5{DW%(odacgO!+tYUZo6nUyiE5|Yu3eT4*%Eu$8!K^j`L}ktBKgCWOx(I!Mvt?L zS85zBZ>l8&9zOZ5KhFI6BBMq4aa|}jrvCx$eFxOj#m`^zp5vxdxR9n{%DN+-{)RgQ z>}`SROq|$BHH<;GP8dvTJ6q+j3C6?^12*-8QyN9Ih^7ou$(7}XGt@BCtYq|=N)xH8 z*ChtdiqU74BiP{-aWH14y-uZl!bDlLRk+1|`Ui7UjWz>g@A;1SZ59k)HR)SdK@TiB zv8a92F|h84<@Y`P-LrN zmyOsfczXWq)K?-g*l$K1Yeeu<$=o@w%A^EyowLWYi53?=fGKYE#O7AL$Mc4oyoj!2 z+=OZ+ovqjLY(>4B_8}B}>ws7%(&~91amK`MA%B*y_k6`wdSv&wOdn9U{yI!Hfv+~)26Pkq!)YXa^Yj5hV>R_zNg6R_FoCD zt0r{6#3shYz(#y3{bTEy*{R(8q(cU$g#{q}x3&z_TDJPdJp|fWhfK^vUK270X>q1p zQB-j-e6c5XOX0ao9HQUnLS}Cmm>Q#-KW2Y8l@isz@$(F(j72H}z0*&scUntRqQxEg zSz_Iu-ryx50?UYL3ng7RHKxe41QVky;DMhYeg4x^b8+6vv3ZTYitzezL=u&4d@R!< zo|dCV+?+fh#r$x7u->4eSjbKg_8GIw+A;C0`KYK`fQObc;hO$fYmN%-lm@d#+VcL#z;1P>|L(C*bRO1uSW_DLLEzv5 zccMr^cNZ4X#_3rfl|Phsve1!fOrS|BT?mHE&vMMtpg15Msy|$fu#2h>`VC-W?H%xO^gYlK}cCJ9n#VN4E^U;B{oaw$N*>hQEm7>EhScWt&OBXmH9b<*yV zvcN%yq@x?<`qwZu(WT>PvdJ`fgj9w~KE-nTeLR)6f+!`&{oX@S%vt6=k`YhyXFPM8R8~w4h2d2{aalYdtm*d!kt4LD=#s5fitmQK8|K*htbQbx z$X=rv!C_-38N5fp`_3qffRIO9EbWxADOQ>B0Xi^OJWMS_YH}pgZd67^u3^%|4oezJ zE%O$N=$$~DW4SCETEcs`pqO*`LiYEVIq*n?W3Vgw?Hue?7fPiteE1d-JRy}CX|h+oGJXWHqNFd7#z z5r)e5xqROG*+z5Zg!o>xC(T9H+zQ*HT6zU5Crk4-O|sv z$HeZOI?X4Nzy~0!^p^_F?seuD9iJgUh@i)>+`s?^e5k{onb09=q`LOS3= z=zdC4x;7?fqE4ZQbd=_?v%>OT>z&d5z;60#9-LL^Xm zAed%?B|LOd;(ePZ=V` z{TaK3-U^Ezr(xm&R^?v3(c?43b=S&qU%7aBe3eC1(&Q0ls7siBO##}fTVN`7Cg`*o zVcP@>{e#ecc;i*8rt;SX8uzyZkVV)9eygCbgGQy~>7!njxfeoI#_67f5uM7>QmpVN zMB&w&N!jAT76PzOML@kPk$VWm;P`1FYN4-am_TOU?}%X1f>#A>d;25;hgdA#1F=Fs zImZswhtaDzEPkMjK+r8Rz~+QQ?x{_}xg)3D4R93ab0J=Hh)r2 zI6SQk>lyR?lkubW`-=2<9a{_I80d4QzKa{c6pTBsEl$QqJ<7;6MJ2NY+d6@Q3c^-u z938isq>DkzZXpePLDaEK+j;v|j6oZk5-gPv3Z6(K!+-?LVXR@=v$2L$hqA$JiZ65( zY86Ks=L`W1)ZYqKwMSj0fdC!eDNcND*l&9{3O<8jf@rOna`y7;k8)$BrS?hc#v)?x z`!yMj>nKK)%5hr)dg10K$zkxbz*ARPcE|P)K?_;u)f~k`eUV65f&3GUL$D)2Q|Ej= zPk2TZ10R>&)H*A+z9=GYqh<4+Dl{s!6po($iF?VnlKU2LRzO}J{OF;P?_M!UFqDH~ z_gJfCijilMfSAEo1^zL2DefJ_T1(+%57JZQ@)OW5JdII?#14(uD z%f*?<8wC$&JOTRTtT7D%TqZ@Eo9l4D;CG~vDFv~eu+6@p=WP5c1nc3a9x80YIYu^? zE(?9emvJy^zt>qC!wMZg(>9=xqlfXM zvyiWId>mP(PuQ3`N5C2za0zi^Wo-t6PFvN>mvvEJo?Ov5nTtBH$j(oKy@0@gMcs!K z_AS)Rx5pyklmP~#a?)rLZFqM9tP`*}c=V1aD~eesSa2;Ehs8XeHXDU1o4q`#q}X!= zD2HWAq82d`=Ade%i6Rvy<}YYm%Dz&ihA3vvA*cc;{946|EEDisEyPKxMYCKE))A!W z?uFL+;AW`FQ9@p!ju@E)p*%{MEI!I4L|7A(xRy{mT=w~))zeqg@-vRCC?@g>r4z%C z`<~E%x>iFKDMtrY7*4PAEvYA@E~wzSJfS^fB!_C)PYU69h7h`hjPCvvUkTh@EZIm* zIx0(KW{i374K%u`S3!uBtixd4@lTa)4vPtBA+O3Q&kP@yw0g^8Uq^pC0IWD9EMG2X z&K^{Gq3}Qfpc-Uysc{pqBzc-iZS*jClAa3ZsO)n{xedLc92Uhi&9L)F3*a?GWMcE) zztKk*5C3cwFJU92RXKi;iJzHNhYV@ke_KEjI&iB!3{QF>e*ye3WN4)0CqHt*{}Y8E z;Gs zO!O?IP*VLpV6Cq5mjy2Zsc#wVewxt=VulvZdpApS7>ci$eZwhn{&WfjSmO+VG8diu zIm~UH7T!?%seNS2Mt~)4{8ov^G;)=~NyLa7as_JGPwV5-R#7=UHVV#Sr_gur$R6F9 zh8gr7pwp75Hbn-JgGJPP;u;l0wB5=07*LtyK{0^_iZ+IT7T zsQCNbH%hj-r1N~`=)*Zv^mPa*?)+Y4|2s*s&*k|gjPe3yEj=V5FZMV9Tp}fTO0yHq zEE{RrfvZwvYXEydA|2UX)URkrWGWR^^u|{ILu4gV0ZW(M$pb#_PRE$c0X6+6YYvoM zIKEx<6hf#;sLX&G^Sp>OWDy(#u-rM~Q96_i7$F9mu~|DY58t#p$0?O#Bp6dG1BET_ zJD4pL{pgZeHzG@5RB&0Xvxd*v+=YI%S*vA#C`m7Dhf7k(;Ut5iF~Rwx23!qPp%0Q< zFcIF0n?{Nv%FdKji@Vr$vapu2b+Zz)oLrAPJild@rH<~dG5P7E9G&hT<|7Y zw>_*(+z*@sRNKjtFh#7#f`Ujm;4hD4vp}S8U|Joy5FESWqy|#@cX6$zhjryOC%KOWlm`wlq8C{uLJYElF08WkFkW|* zx~SVA9^m#=R2$j6H^^!XwqB0t)N4nVp0m2b%iyo2NrNC1Hm-7;eo!e0hnD3;D^T%9 zkWC{WS&(>s2&|f&f)D+Qj!Wu3is>o!>%u^_3QhyTH2g zhAi_G@iRL@xElV4ce)Z!j6h0Ntw z)>afUz0~^@P5CjRSPrA|A=%>IBu=_iLSw#ciEY!`Aa8-XxX;k8u+Q4pTqP3fWb1du zIMeO}L|oUZ9|TN``Jb>5EXWdMDeD;CjiP4Yd|o&sB_i&{;M@?OSO<@G+P!mHRiO=inF?!gcI(biTdkJN3 zJe6O(ADIQqh@@zGH0)JqCZ!w^f4%4~@^J`(lYs;WS$H`JK+=21xMQ*z7096wFjcj- zUOrgxjVf=M-67{yTt{6H!*RNv_?xA6B(yV`40CPITfM;g*>h1r|Jgp`b9<+9olB~E zsiqaO4Ye8Joj}E;NIG+`^%`?r3vS575d(6BP7!5!Fm}H(2Wh$6t5|ZNqNs5xC}T3g zpM&fmGJ;el2sM0angb>y00@WX6#@fQ^7SHW+Ss3zR%-ByDYf!i6YG0A#1(D$AE8HL#%1#22DPw1uSNNXu0qpm0;^N$+iOJy-9 zH=#?ZPaSvAzp`kvYhY8IlzU&-fh+lyHe!%;4BiJ-%On%7NGe69&OrMjj9Dp6A6N>> zo~1K61cZ+s-_L&u=3M#S8e1$WW~5!UCzxq}|Jl*A^X-eV4>*+n=y(dLm;20f9VvG2 z3U74()uIRA&3}t7d!?>=P<)n?gsq%00fKW^&RO7O{-a3H5^14mB_x)D#(2BIdKL$~NV+zKrZh z&Ji5&qj}~EPilTqCkK0GhKOi*W{HkH`_=m9%x5p`vSLIP*o{}}7h`>v=v@Zz=Yj6q zsH_ieSBTAWyms^LAEBYo)t&ax?w($1wZxV$HCbI1Wnr+rEj!56-UPz#Ve9ZxvjqS| zB|IEJU~7mAr3u8`(oT%}ti6kx($Z9n`VF57r;39N#KKa+%L$_CrK$z?vIYy8QcH*< zi+TvZ0N6rYK$IS~Hg?X!9%9sgaD`vae>ZbbQ~ptLu@aYYXIf`hIqLWqqcByaS-OHYT>N)QrhOwfH>Q`I)NdwZV)>cntz8d z1^?6D!PUv;PdKJv4u}oJ_C?kCrB|;1(WShiiuyk-ep6s>Y3uOE>V@q8q3L32_Aj#j zhi|_nf5Q29M_$bTiTgja{}KBi8( z#l^iAYH;1TZ4DP-~<~ zvqc~lHEpstRWz0$H^H%f3u3WNC}qaSeEk{|R&NaxaxAu1l5BSO^WWaN zNNYV?yM?A57P;SpoaVMV@A>VG-R21K(C8}Yli+Knek)Qg_P0XEic}!N4~H8o-UlXC zV>e&5<;3xt0@;-cG;=%C7Dab(IT|br(y3fnVByB$3g< zZ#CEDPWe7NS=KqnmNJK$DuH0RyC@5ihih%N$4x^XkKqt5x)i00_{y-4Q$e|!EN$&4 za!a`I!=Y`crDClsUHv~U z*Gi$T%}QX$^}1m@uR(hPQyBK$<7UPRH2LcCY399adfPS!BEK7wv;7D97wU^ za*Z^pLA#Gxj+LI`mS`RkjI}8gGO%9IUCx1*HXq;2bPZP)2;tm|@qO07zofqh09&ng z5UXMjr+VgnM;%4Zz7;a?MZK?Sm`tD}=w@8Bcp5{@XSap;^A!`t2R5gs;+GnM9H^ct z890y%tYw9%q%I+xhUjl8om)AMuB$anheC6F-Ne`5)r{~aLEQzF8?GJt^nMniaE4T5 zezozej-9@21Ab9Cl|3bZ071a51+V+$JKgnlR2(r*?uds@R?Y_EqL@$=xIa$C$DMH77NS$T_wdC#I z{)i#Px6@$M^o~;9mFCY<66iTJY)t*hKx#)^r>Nqbf^#2tYCPryAjIUgs&md(4*HXF zM-;kWj`OHkgdysh7uEl{^V&bH+n29ffAv^y*FVlxy-M2)xv?H@D&EI)8 zh_!#pyGgPGViA%0vQdMtE@$dt9^_>tw(q<4pCA={1EIPZFP@zD*OZ6Q}$bwfYLWPQ>k%RXLMn~k$k zyPWyG?bAmQ^!zpwNy<-?ALR#6OQJBW$k=&VIyp zo`4!@pk&uqWT*=>&R8zMdb@9L)8UNg8*C&>!MQ4u)vjB*6^*Mge51V3%DOEF&eLIC zG+vOjmx757-#N!V(i{yV`kFvcNyNYHH?-0y3D|*cS1`vRGW8DlgR6 z{e2vt;#8TMy;@!QctGoBMvZMOshA{g+a=cQE6c!89DjR%bNGY0sU>P@0^?GC^=^3a z?*?wp#D&l|2h#S$t$AAE{!aRPx|h3#W*-;$IZF@1vOSjkBMc0gM+{I*kb3Ybs*XzCAra6V6?+Pg%C47jw zF2qPEuDX}dX?WQ=L9caFf&W8ferCC0Lpocn)Ls`NUTi-KmCST_X&=e}5v@6 z+wf3*0;UJo4-g1l!|Ym$9o<@0#ecH7g5YPvHf zk6vh4&D-cD^PUQ12nmgz`LyjPga9u`bF0a>nd4MO)st2*1~+ZZKzj(@#?MB$F^N)) zbR2nGuk+La5mB4$cX%wziY|rtj&oaFe%$MtpS~uzdsrY;F}fhkSMJ=VkL&}S?e^v@ zdsx?d^Lt!(Ezz2)ggld57hpQJxdSV4u_BN~52?B7uCVda9Vw^oXjH4JG=}$@Z4>xK zhtP9tdq6g51*A_S<66a{)%V?-_oV$Q-8=Rj15%tAqkc+SBn{=BoP;W>9 zM$>*Qnu?G`j}`T_5{u!=NDX^Aj0omb$f4G;{d64^KyOXR@&-c75t>u^kqehKfvGLL z{gE_nH*{VE&C;K*WIQEw@Ubeka^5DZ$bQrc#d-or)=}|FEFEPGeKhwqF;>i`DZM>O z*g3mssasFWC?|8qc-N+_DDm=Y21kOvM>_aa$1gTCW{!l9NvmZPv#pM$-yCB>m!QSdhe{h4*rDm+NYQfKp6W=I=*NK@x(Ulh6ROCsHdDop-E8lslHto;vI7rqE4#vvMUqC3A6kdLhO6c3syEOe&Zp< z-RG%Y6*5cSpaefNW|CY4(;PX9OygmK%HAiG%ZLDv#9gwXDhuQ%Yvebw$N6ev}5zS3oV+ajy2ig!ea|&k93VSabZ9v@q1uX98#3ZXm z{AuAHO5i?LfnX?nKl*mbw_qtl6Ewg?y{v4rffuh8A>U6EgPTTHyxF9LrUC1W#{gr@ zR}>Q11!G_>D}IP<10nf>TOnG7%~2=tu-y-m7e7E>q``==!}2s}@0p`gqe>zpQG?Px z-#XMys9HC(FkAhqV$e(|Gs#uzn3;%lKf?p2Pa%7GVt$1hvWKVSilE(FIQ zHJ}@ChT4yF6K>hYkaJxzPS04V_*g()^A?gc`Hth}rJX>I?(kpZ6J>aDRswIo;qVa; z*s^!lvSQp56?To7g|!J+dsw^pN)K5ZWy9TYOKEW1W)-cl{qX%%HH{JroL=qhK+}Bn z<*514@^tE5Ue-^YnQC4yZ1=koGBD!k=sJ^Z(h#gTN@697dz)e;-dJduT}ReP(p6V< z3?s>EqWk*p{oacetKHG(MR5V4fUDE|u4Wu+}2 zZxy28Yp~+!)zL(JMtoc0srO_(YYGpFa=Q>El&;;;4CeYEdOGs6gU?HhV(6J5MuDx* zKsD-6dXRIhY!)*vNddd|b%As2kqFDVV6Y)NAEX9t(`lJ3-%%*?DbbJF0BN5!6Fe{ciaH(&O}zpEoHP>$X{5Y(R; z-KBrzu^ewQ9L(ljbpLurlvVPYca!PVd6Ls^2NFc#<{D(gPQDVd;;J#NP`JZ*CcMAn zB&Px6k;3j%GQ0GJXmX-h8t&)$hiK|!Q_xi5N{y(^liS_^uB_ie>ou=o#YorPn{Kbu zUAx)d!2oN0%?#}A69LXCksi%r28Z&YxodLxk!SXxVyEZ~FK2^WGtT6ZxkBc?mSDZM zl(lV2tr94s14SA4@TEx}n`ThNZheFu5XLd4yD)lW%jsuQfBtY(*pZ4e|}Li`ZW7s{sGK1dOKMg|#f(1%ypSz7Aw+cSzC-S#U;fiNaEG%Ca$42 zd<4P(Z+OUEn+&+YU**N;6=~z=g;kODx&cpvse*t)`cJdLHVwmN0Zz0@`%lnt%8;b= z6U?V_aw;0O+NE-uakTC=8`qLzo9RIO!P+L9U7aOc$ML!Gjm^M->@xi1=F^6u4M7%q z_Se^LlO$$bG53`OBj4*cO~t_{WGQr^V+9mP4$#ujH!VqKhPzN#hMnJ~#Oq034I77P zKGuJEolj3om9oX8AC$8zbNY_AeJxJCkUBk4+L`$EINDWm%+6V!IhrMOY_C-ujwmi* zw-B)Q^k_L9-7%1$p7UCHTliH*_R)RdK%2V#^CVlt`gSN|n(*r3(_Hbr;0?7fjou~U z5s^O;>|ykNAIUM_-8W~walp^>*k5RYFE^F9Y4^&R+w~uZwHZ~HMljnhNUcYjIW4-j zu)@65PKOn1c6Tr*ZJoFi2QTfqy(hw%^bPmY_s69S_>6kkE_J(M{9`|U;!cHv+EU!u z(_gZ3TL5s%T|?1h!w6>fzSZaxrqCmq<{JCBgsjW>AjLA>XD)mXK%uK>)+rRv_4#nN z=EELp45>+SwR_6!t#&D(imb6M#;8k_W!*}U;8`rIv1m8k&2C22DCEC&5J8I=QpC^B z9G8ys$jn85@5uLQD$7fYDvc3yEyuOB%s>jVmKc_vlWkirF~nayYT;S!wS_I`BI zFH$1Haf|s^E!E}VWxs}d%@@=XiG`00OFmzKdc-9uUSXjVDncLB!hc|(W6WrQVfmXEYlK7e1`p^PtN?O!;7MDVb z_)Bhi?{`|`%ye(F-I_zGy9WB1-#9e@E*h-@EZB~R+ z*so&=^U_?zPHOEGLv$RcfSm2Rlu`nfQDMDZbS)G$=o$Lg`1Op9&}0BhbT19OuS1kG znj9lrb<`SV+c^}%n*CPRP9(jGa_8ExyI4%glJ058kDB4u={2~QM5EpWZU#jW!2aQ> z$-et?^eLxRS>*$pSGb80hKQRQK%=awI0!142kT5P*8Kpq*m#dEsd>U9Ya)EyFo$mO zn?3rc!K^?m8eZxyT}@ol#$8SP5@DKZlEk+)Ovvb}+#NQ@i`a<~IUJkN&lqwFxK)@) TGaN7VRDhzaDzHZSUC{pl*T1#i From 3f475bf1ea18bf2180896362159f9c0e5d5a5464 Mon Sep 17 00:00:00 2001 From: ben Date: Sun, 20 Nov 2022 17:41:57 +0000 Subject: [PATCH 75/83] Defaulted to null in env.example --- .env.example | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index f90c10a64..de9cb3f7e 100644 --- a/.env.example +++ b/.env.example @@ -13,9 +13,9 @@ LNBITS_ADMIN_EXTENSIONS="ngrok" LNBITS_DEFAULT_WALLET_NAME="LNbits wallet" # Ad space description -LNBITS_AD_SPACE_TITE"" +# LNBITS_AD_SPACE_TITLE="Supported by" # csv ad space, format ";;, ;;", extensions can choose to honor -LNBITS_AD_SPACE="" +# LNBITS_AD_SPACE="" # Hides wallet api, extensions can choose to honor LNBITS_HIDE_API=false From 0836ba6c77a02ed229bf63505296d5967cb9d77f Mon Sep 17 00:00:00 2001 From: ben Date: Sun, 20 Nov 2022 17:59:43 +0000 Subject: [PATCH 76/83] Added to homescreen --- lnbits/core/templates/core/index.html | 15 +++++++++++++++ lnbits/core/templates/core/wallet.html | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lnbits/core/templates/core/index.html b/lnbits/core/templates/core/index.html index 68a7b7ede..63d8668e5 100644 --- a/lnbits/core/templates/core/index.html +++ b/lnbits/core/templates/core/index.html @@ -183,6 +183,21 @@
 
+ + {% if AD_SPACE %} {% for ADS in AD_SPACE %} {% set AD = ADS.split(';') %} +
+ {{ AD_TITLE }} + + + + + +
+ {% endfor %} {% endif %}
diff --git a/lnbits/core/templates/core/wallet.html b/lnbits/core/templates/core/wallet.html index 813ae7678..fb392c32f 100644 --- a/lnbits/core/templates/core/wallet.html +++ b/lnbits/core/templates/core/wallet.html @@ -394,7 +394,7 @@ - + Date: Sun, 20 Nov 2022 18:06:29 +0000 Subject: [PATCH 77/83] slight ui tweak for mobile --- lnbits/core/templates/core/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lnbits/core/templates/core/index.html b/lnbits/core/templates/core/index.html index 63d8668e5..8c3c5b0fe 100644 --- a/lnbits/core/templates/core/index.html +++ b/lnbits/core/templates/core/index.html @@ -192,9 +192,9 @@ - +
{% endfor %} {% endif %} From f458fc416c974b95328b1f7a721b1d94639d4737 Mon Sep 17 00:00:00 2001 From: ben Date: Sun, 20 Nov 2022 18:23:18 +0000 Subject: [PATCH 78/83] black --- lnbits/settings.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lnbits/settings.py b/lnbits/settings.py index 0f4064d5f..c50e0a517 100644 --- a/lnbits/settings.py +++ b/lnbits/settings.py @@ -38,7 +38,9 @@ LNBITS_DISABLED_EXTENSIONS: List[str] = [ for x in env.list("LNBITS_DISABLED_EXTENSIONS", default=[], subcast=str) ] -LNBITS_AD_SPACE_TITLE = env.str("LNBITS_AD_SPACE_TITLE", default="Optional Advert Space") +LNBITS_AD_SPACE_TITLE = env.str( + "LNBITS_AD_SPACE_TITLE", default="Optional Advert Space" +) LNBITS_AD_SPACE = [x.strip(" ") for x in env.list("LNBITS_AD_SPACE", default=[])] LNBITS_HIDE_API = env.bool("LNBITS_HIDE_API", default=False) LNBITS_SITE_TITLE = env.str("LNBITS_SITE_TITLE", default="LNbits") From d9a153d43d5aca6a3d62962c1c4184e81801186a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Tue, 22 Nov 2022 10:37:13 +0100 Subject: [PATCH 79/83] fix tests to low balance --- tests/conftest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 1e719c76a..458ce2b9c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -60,7 +60,7 @@ async def from_wallet(from_user): wallet = await create_wallet(user_id=user.id, wallet_name="test_wallet_from") await credit_wallet( wallet_id=wallet.id, - amount=99999999, + amount=999999999, ) yield wallet @@ -77,7 +77,7 @@ async def to_wallet(to_user): wallet = await create_wallet(user_id=user.id, wallet_name="test_wallet_to") await credit_wallet( wallet_id=wallet.id, - amount=99999999, + amount=999999999, ) yield wallet From 50dc6f9c556dd57c09063767548d0586eb226fff Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Wed, 23 Nov 2022 13:43:04 +0000 Subject: [PATCH 80/83] add select users wallet --- .../splitpayments/templates/splitpayments/index.html | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lnbits/extensions/splitpayments/templates/splitpayments/index.html b/lnbits/extensions/splitpayments/templates/splitpayments/index.html index 5862abc16..1cceb7bab 100644 --- a/lnbits/extensions/splitpayments/templates/splitpayments/index.html +++ b/lnbits/extensions/splitpayments/templates/splitpayments/index.html @@ -31,14 +31,20 @@ style="flex-wrap: nowrap" v-for="(target, t) in targets" > - + option-label="name" + style="width: 1000px" + new-value-mode="add-unique" + use-input + input-debounce="0" + emit-value + > Date: Wed, 23 Nov 2022 13:48:36 +0000 Subject: [PATCH 81/83] fix typo in events --- lnbits/extensions/events/templates/events/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lnbits/extensions/events/templates/events/index.html b/lnbits/extensions/events/templates/events/index.html index 7f34a3e2d..212589301 100644 --- a/lnbits/extensions/events/templates/events/index.html +++ b/lnbits/extensions/events/templates/events/index.html @@ -260,7 +260,7 @@ dense v-model.number="formDialog.data.price_per_ticket" type="number" - label="Price per ticket " + label="Sats per ticket " >
From 390d74eaf6d128c5c24b339902646d6ec4b5fa17 Mon Sep 17 00:00:00 2001 From: ben Date: Wed, 23 Nov 2022 16:57:27 +0000 Subject: [PATCH 82/83] prettier --- lnbits/core/templates/core/index.html | 8 +++++--- lnbits/core/templates/core/wallet.html | 4 +--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lnbits/core/templates/core/index.html b/lnbits/core/templates/core/index.html index 8c3c5b0fe..5f26cb038 100644 --- a/lnbits/core/templates/core/index.html +++ b/lnbits/core/templates/core/index.html @@ -186,15 +186,17 @@ {% if AD_SPACE %} {% for ADS in AD_SPACE %} {% set AD = ADS.split(';') %}
- {{ AD_TITLE }} + {{ AD_TITLE }} - +
{% endfor %} {% endif %} diff --git a/lnbits/core/templates/core/wallet.html b/lnbits/core/templates/core/wallet.html index fb392c32f..22fbd05de 100644 --- a/lnbits/core/templates/core/wallet.html +++ b/lnbits/core/templates/core/wallet.html @@ -389,9 +389,7 @@ ADS.split(';') %} -
- {{ AD_TITLE }} -
+
{{ AD_TITLE }}
From 71d105b5d57d4214412fe85200ed0efde4461107 Mon Sep 17 00:00:00 2001 From: ben Date: Wed, 23 Nov 2022 17:06:45 +0000 Subject: [PATCH 83/83] Accidental delete --- lnbits/settings.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lnbits/settings.py b/lnbits/settings.py index c50e0a517..17fce293c 100644 --- a/lnbits/settings.py +++ b/lnbits/settings.py @@ -18,6 +18,8 @@ DEBUG = env.bool("DEBUG", default=False) HOST = env.str("HOST", default="127.0.0.1") PORT = env.int("PORT", default=5000) +FORWARDED_ALLOW_IPS = env.str("FORWARDED_ALLOW_IPS", default="127.0.0.1") + LNBITS_PATH = path.dirname(path.realpath(__file__)) LNBITS_DATA_FOLDER = env.str( "LNBITS_DATA_FOLDER", default=path.join(LNBITS_PATH, "data")