diff --git a/.gitignore b/.gitignore
index c5f1498ce..07ee15b86 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,3 +33,4 @@ __bundle__
node_modules
lnbits/static/bundle.*
+docker
diff --git a/Makefile b/Makefile
index 63f7eb239..b9418df54 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
all: format check requirements.txt
-format: prettier black
+format: black
check: mypy checkprettier checkblack
diff --git a/lnbits/extensions/copilot/templates/copilot/_api_docs.html b/lnbits/extensions/copilot/templates/copilot/_api_docs.html
index 64acba148..f0002611a 100644
--- a/lnbits/extensions/copilot/templates/copilot/_api_docs.html
+++ b/lnbits/extensions/copilot/templates/copilot/_api_docs.html
@@ -31,7 +31,7 @@
[<copilot_object>, ...]
curl -X POST {{ request.base_url }}api/v1/copilot -d '{"title":
+ >curl -X POST {{ request.base_url }}copilot/api/v1/copilot -d '{"title":
<string>, "animation": <string>,
"show_message":<string>, "amount": <integer>,
"lnurl_title": <string>}' -H "Content-type: application/json"
@@ -59,7 +59,7 @@
Curl example
curl -X POST {{ request.base_url
- }}api/v1/copilot/<copilot_id> -d '{"title": <string>,
+ }}copilot/api/v1/copilot/<copilot_id> -d '{"title": <string>,
"animation": <string>, "show_message":<string>,
"amount": <integer>, "lnurl_title": <string>}' -H
"Content-type: application/json" -H "X-Api-Key:
@@ -87,7 +87,7 @@
[<copilot_object>, ...]
Curl example
curl -X GET {{ request.base_url }}api/v1/copilot/<copilot_id>
+ >curl -X GET {{ request.base_url }}copilot/api/v1/copilot/<copilot_id>
-H "X-Api-Key: {{ user.wallets[0].inkey }}"
@@ -110,7 +110,7 @@
[<copilot_object>, ...]
Curl example
curl -X GET {{ request.base_url }}api/v1/copilots -H "X-Api-Key: {{
+ >curl -X GET {{ request.base_url }}copilot/api/v1/copilots -H "X-Api-Key: {{
user.wallets[0].inkey }}"
@@ -136,7 +136,7 @@
Curl example
curl -X DELETE {{ request.base_url
- }}api/v1/copilot/<copilot_id> -H "X-Api-Key: {{
+ }}copilot/api/v1/copilot/<copilot_id> -H "X-Api-Key: {{
user.wallets[0].adminkey }}"
@@ -161,7 +161,7 @@
Curl example
curl -X GET {{ request.base_url }}/api/v1/copilot/ws/<string,
+ >curl -X GET {{ request.base_url }}copilot/api/v1/copilot/ws/<string,
copilot_id>/<string, comment>/<string, gif name> -H
"X-Api-Key: {{ user.wallets[0].adminkey }}"
diff --git a/lnbits/extensions/jukebox/templates/jukebox/_api_docs.html b/lnbits/extensions/jukebox/templates/jukebox/_api_docs.html
index 791a55e71..2a00da008 100644
--- a/lnbits/extensions/jukebox/templates/jukebox/_api_docs.html
+++ b/lnbits/extensions/jukebox/templates/jukebox/_api_docs.html
@@ -37,7 +37,7 @@
[<jukebox_object>, ...]
Curl example
curl -X GET {{ request.base_url }}api/v1/jukebox -H "X-Api-Key: {{
+ >curl -X GET {{ request.base_url }}jukebox/api/v1/jukebox -H "X-Api-Key: {{
user.wallets[0].adminkey }}"
@@ -59,7 +59,7 @@
<jukebox_object>
Curl example
curl -X GET {{ request.base_url }}api/v1/jukebox/<juke_id> -H
+ >curl -X GET {{ request.base_url }}jukebox/api/v1/jukebox/<juke_id> -H
"X-Api-Key: {{ user.wallets[0].adminkey }}"
@@ -86,7 +86,7 @@
<jukbox_object>
Curl example
curl -X POST {{ request.base_url }}api/v1/jukebox/ -d '{"user":
+ >curl -X POST {{ request.base_url }}jukebox/api/v1/jukebox/ -d '{"user":
<string, user_id>, "title": <string>,
"wallet":<string>, "sp_user": <string,
spotify_user_account>, "sp_secret": <string,
@@ -116,7 +116,7 @@
<jukebox_object>
Curl example
curl -X DELETE {{ request.base_url }}api/v1/jukebox/<juke_id>
+ >curl -X DELETE {{ request.base_url }}jukebox/api/v1/jukebox/<juke_id>
-H "X-Api-Key: {{ user.wallets[0].adminkey }}"
diff --git a/lnbits/extensions/livestream/templates/livestream/_api_docs.html b/lnbits/extensions/livestream/templates/livestream/_api_docs.html
index 4c497d7f9..629e5d9cf 100644
--- a/lnbits/extensions/livestream/templates/livestream/_api_docs.html
+++ b/lnbits/extensions/livestream/templates/livestream/_api_docs.html
@@ -38,7 +38,7 @@
[<livestream_object>, ...]
Curl example
curl -X GET {{ request.url_root }}api/v1/livestream -H "X-Api-Key: {{
+ >curl -X GET {{ request.base_url }}livestream/api/v1/livestream -H "X-Api-Key: {{
user.wallets[0].inkey }}"
@@ -59,8 +59,8 @@
Curl example
curl -X PUT {{ request.url_root
- }}api/v1/livestream/track/<track_id> -H "X-Api-Key: {{
+ >curl -X PUT {{ request.base_url }}
+ livestream/api/v1/livestream/track/<track_id> -H "X-Api-Key: {{
user.wallets[0].inkey }}"
@@ -81,8 +81,8 @@
Curl example
curl -X PUT {{ request.url_root
- }}api/v1/livestream/fee/<fee_pct> -H "X-Api-Key: {{
+ >curl -X PUT {{ request.base_url }}
+ livestream/api/v1/livestream/fee/<fee_pct> -H "X-Api-Key: {{
user.wallets[0].inkey }}"
@@ -109,7 +109,8 @@
Curl example
curl -X POST {{ request.url_root }}api/v1/livestream/tracks -d
+ >curl -X POST {{ request.base_url }}
+ livestream/api/v1/livestream/tracks -d
'{"name": <string>, "download_url": <string>,
"price_msat": <integer>, "producer_id": <integer>,
"producer_name": <string>}' -H "Content-type: application/json"
@@ -123,6 +124,7 @@
dense
expand-separator
label="Delete a withdraw link"
+ class="q-pb-md"
>
@@ -136,8 +138,8 @@
Curl example
curl -X DELETE {{ request.url_root
- }}api/v1/livestream/tracks/<track_id> -H "X-Api-Key: {{
+ >curl -X DELETE {{ request.base_url }}
+ livestream/api/v1/livestream/tracks/<track_id> -H "X-Api-Key: {{
user.wallets[0].inkey }}"
diff --git a/lnbits/extensions/lnaddress/templates/lnaddress/_api_docs.html b/lnbits/extensions/lnaddress/templates/lnaddress/_api_docs.html
index ab7ab4bd3..dbaa84695 100644
--- a/lnbits/extensions/lnaddress/templates/lnaddress/_api_docs.html
+++ b/lnbits/extensions/lnaddress/templates/lnaddress/_api_docs.html
@@ -45,7 +45,7 @@
JSON list of users
Curl example
curl -X GET {{ request.url_root }}lnaddress/api/v1/domains -H
+ >curl -X GET {{ request.base_url }}lnaddress/api/v1/domains -H
"X-Api-Key: {{ user.wallets[0].inkey }}"
@@ -81,7 +81,7 @@
>
Curl example
curl -X POST {{ request.url_root }}lnaddress/api/v1/domains -d
+ >curl -X POST {{ request.base_url }}lnaddress/api/v1/domains -d
'{"wallet": "{{ user.wallets[0].id }}", "domain": <string>,
"cf_token": <string>,"cf_zone_id": <string>,"webhook":
<Optional string> ,"cost": <integer>}' -H "X-Api-Key: {{
@@ -101,7 +101,7 @@
{"X-Api-Key": <string>}
Curl example
curl -X DELETE {{ request.url_root
+ >curl -X DELETE {{ request.base_url
}}lnaddress/api/v1/domains/<domain_id> -H "X-Api-Key: {{
user.wallets[0].inkey }}"
@@ -122,7 +122,7 @@
JSON list of addresses
Curl example
curl -X GET {{ request.url_root }}lnaddress/api/v1/addresses -H
+ >curl -X GET {{ request.base_url }}lnaddress/api/v1/addresses -H
"X-Api-Key: {{ user.wallets[0].inkey }}"
@@ -142,14 +142,14 @@
JSON list of addresses
Curl example
curl -X GET {{ request.url_root
+ >curl -X GET {{ request.base_url
}}lnaddress/api/v1/address/<domain>/<username>/<wallet_key>
-H "X-Api-Key: {{ user.wallets[0].inkey }}"
-
+
{"X-Api-Key": <string>}
Curl example
curl -X POST {{ request.url_root
+ >curl -X POST {{ request.base_url
}}lnaddress/api/v1/address/<domain_id> -d '{"domain":
<string>, "username": <string>,"email": <Optional
string>, "wallet_endpoint": <string>, "wallet_key":
diff --git a/lnbits/extensions/lnurldevice/templates/lnurldevice/_api_docs.html b/lnbits/extensions/lnurldevice/templates/lnurldevice/_api_docs.html
index af69b76e3..e255d4a02 100644
--- a/lnbits/extensions/lnurldevice/templates/lnurldevice/_api_docs.html
+++ b/lnbits/extensions/lnurldevice/templates/lnurldevice/_api_docs.html
@@ -39,7 +39,7 @@
[<lnurldevice_object>, ...]
Curl example
curl -X POST {{ request.base_url }}api/v1/lnurldevice -d '{"title":
+ >curl -X POST {{ request.base_url }}lnurldevice/api/v1/lnurlpos -d '{"title":
<string>, "message":<string>, "currency":
<integer>}' -H "Content-type: application/json" -H "X-Api-Key:
{{user.wallets[0].adminkey }}"
@@ -71,7 +71,7 @@
Curl example
curl -X POST {{ request.base_url
- }}api/v1/lnurlpos/<lnurldevice_id> -d ''{"title":
+ }}lnurldevice/api/v1/lnurlpos/<lnurldevice_id> -d ''{"title":
<string>, "message":<string>, "currency":
<integer>} -H "Content-type: application/json" -H "X-Api-Key:
{{user.wallets[0].adminkey }}"
@@ -104,7 +104,7 @@
Curl example
curl -X GET {{ request.base_url
- }}api/v1/lnurlpos/<lnurldevice_id> -H "X-Api-Key: {{
+ }}lnurldevice/api/v1/lnurlpos/<lnurldevice_id> -H "X-Api-Key: {{
user.wallets[0].inkey }}"
@@ -133,7 +133,7 @@
[<lnurldevice_object>, ...]
Curl example
curl -X GET {{ request.base_url }}api/v1/lnurldevices -H
+ >curl -X GET {{ request.base_url }}lnurldevice/api/v1/lnurlpos -H
"X-Api-Key: {{ user.wallets[0].inkey }}"
@@ -159,7 +159,7 @@
Curl example
curl -X DELETE {{ request.base_url
- }}api/v1/lnurlpos/<lnurldevice_id> -H "X-Api-Key: {{
+ }}lnurldevice/api/v1/lnurlpos/<lnurldevice_id> -H "X-Api-Key: {{
user.wallets[0].adminkey }}"
diff --git a/lnbits/extensions/lnurlp/templates/lnurlp/_api_docs.html b/lnbits/extensions/lnurlp/templates/lnurlp/_api_docs.html
index 80d1478d2..bf920558b 100644
--- a/lnbits/extensions/lnurlp/templates/lnurlp/_api_docs.html
+++ b/lnbits/extensions/lnurlp/templates/lnurlp/_api_docs.html
@@ -17,7 +17,7 @@
[<pay_link_object>, ...]
Curl example
curl -X GET {{ request.base_url }}api/v1/links -H "X-Api-Key: {{
+ >curl -X GET {{ request.base_url }}lnurlp/api/v1/links -H "X-Api-Key: {{
user.wallets[0].inkey }}"
@@ -39,7 +39,7 @@
{"lnurl": <string>}
Curl example
curl -X GET {{ request.base_url }}api/v1/links/<pay_id> -H
+ >curl -X GET {{ request.base_url }}lnurlp/api/v1/links/<pay_id> -H
"X-Api-Key: {{ user.wallets[0].inkey }}"
@@ -68,7 +68,7 @@
{"lnurl": <string>}
Curl example
curl -X POST {{ request.base_url }}api/v1/links -d '{"description":
+ >curl -X POST {{ request.base_url }}lnurlp/api/v1/links -d '{"description":
<string>, "amount": <integer>, "max": <integer>,
"min": <integer>, "comment_chars": <integer>}' -H
"Content-type: application/json" -H "X-Api-Key: {{
@@ -99,7 +99,7 @@
{"lnurl": <string>}
Curl example
curl -X PUT {{ request.base_url }}api/v1/links/<pay_id> -d
+ >curl -X PUT {{ request.base_url }}lnurlp/api/v1/links/<pay_id> -d
'{"description": <string>, "amount": <integer>}' -H
"Content-type: application/json" -H "X-Api-Key: {{
user.wallets[0].adminkey }}"
@@ -126,7 +126,7 @@
Curl example
curl -X DELETE {{ request.base_url }}api/v1/links/<pay_id> -H
+ >curl -X DELETE {{ request.base_url }}lnurlp/api/v1/links/<pay_id> -H
"X-Api-Key: {{ user.wallets[0].adminkey }}"
diff --git a/lnbits/extensions/offlineshop/templates/offlineshop/_api_docs.html b/lnbits/extensions/offlineshop/templates/offlineshop/_api_docs.html
index ac655697b..bd68b629e 100644
--- a/lnbits/extensions/offlineshop/templates/offlineshop/_api_docs.html
+++ b/lnbits/extensions/offlineshop/templates/offlineshop/_api_docs.html
@@ -63,7 +63,7 @@
Curl example
curl -X GET {{ request.base_url
- }}/offlineshop/api/v1/offlineshop/items -H "Content-Type:
+ }}offlineshop/api/v1/offlineshop/items -H "Content-Type:
application/json" -H "X-Api-Key: {{ user.wallets[0].inkey }}" -d
'{"name": <string>, "description": <string>, "image":
<data-uri string>, "price": <integer>, "unit": <"sat"
@@ -96,7 +96,7 @@
>
Curl example
curl -X GET {{ request.base_url }}/offlineshop/api/v1/offlineshop -H
+ >curl -X GET {{ request.base_url }}offlineshop/api/v1/offlineshop -H
"X-Api-Key: {{ user.wallets[0].inkey }}"
@@ -118,7 +118,7 @@
Curl example
curl -X GET {{ request.base_url
- }}/offlineshop/api/v1/offlineshop/items/<item_id> -H
+ }}offlineshop/api/v1/offlineshop/items/<item_id> -H
"Content-Type: application/json" -H "X-Api-Key: {{
user.wallets[0].inkey }}" -d '{"name": <string>, "description":
<string>, "image": <data-uri string>, "price":
@@ -127,7 +127,7 @@
-
+
DELETE
@@ -138,7 +138,7 @@
Curl example
curl -X GET {{ request.base_url
- }}/offlineshop/api/v1/offlineshop/items/<item_id> -H "X-Api-Key:
+ }}offlineshop/api/v1/offlineshop/items/<item_id> -H "X-Api-Key:
{{ user.wallets[0].inkey }}"
diff --git a/lnbits/extensions/paywall/templates/paywall/_api_docs.html b/lnbits/extensions/paywall/templates/paywall/_api_docs.html
index ceadf2f08..664cda0f1 100644
--- a/lnbits/extensions/paywall/templates/paywall/_api_docs.html
+++ b/lnbits/extensions/paywall/templates/paywall/_api_docs.html
@@ -17,7 +17,7 @@
[<paywall_object>, ...]
Curl example
curl -X GET {{ request.url_root }}api/v1/paywalls -H "X-Api-Key: {{
+ >curl -X GET {{ request.base_url }}paywall/api/v1/paywalls -H "X-Api-Key: {{
user.wallets[0].inkey }}"
@@ -48,7 +48,7 @@
>
Curl example
curl -X POST {{ request.url_root }}api/v1/paywalls -d '{"url":
+ >curl -X POST {{ request.base_url }}paywall/api/v1/paywalls -d '{"url":
<string>, "memo": <string>, "description": <string>,
"amount": <integer>, "remembers": <boolean>}' -H
"Content-type: application/json" -H "X-Api-Key: {{
@@ -80,8 +80,8 @@
>
Curl example
curl -X POST {{ request.url_root
- }}api/v1/paywalls/<paywall_id>/invoice -d '{"amount":
+ >curl -X POST {{ request.base_url
+ }}paywall/api/v1/paywalls/<paywall_id>/invoice -d '{"amount":
<integer>}' -H "Content-type: application/json"
@@ -111,8 +111,8 @@
>
Curl example
curl -X POST {{ request.url_root
- }}api/v1/paywalls/<paywall_id>/check_invoice -d
+ >curl -X POST {{ request.base_url
+ }}paywall/api/v1/paywalls/<paywall_id>/check_invoice -d
'{"payment_hash": <string>}' -H "Content-type: application/json"
@@ -137,8 +137,8 @@
Curl example
curl -X DELETE {{ request.url_root
- }}api/v1/paywalls/<paywall_id> -H "X-Api-Key: {{
+ >curl -X DELETE {{ request.base_url
+ }}paywall/api/v1/paywalls/<paywall_id> -H "X-Api-Key: {{
user.wallets[0].adminkey }}"
diff --git a/lnbits/extensions/satsdice/templates/satsdice/_api_docs.html b/lnbits/extensions/satsdice/templates/satsdice/_api_docs.html
index fb43b90dc..644bcdfef 100644
--- a/lnbits/extensions/satsdice/templates/satsdice/_api_docs.html
+++ b/lnbits/extensions/satsdice/templates/satsdice/_api_docs.html
@@ -17,7 +17,7 @@
[<satsdice_link_object>, ...]
Curl example
curl -X GET {{ request.base_url }}api/v1/links -H "X-Api-Key: {{
+ >curl -X GET {{ request.base_url }}satsdice/api/v1/links -H "X-Api-Key: {{
user.wallets[0].inkey }}"
@@ -44,7 +44,7 @@
{"lnurl": <string>}
Curl example
curl -X GET {{ request.base_url }}api/v1/links/<satsdice_id> -H
+ >curl -X GET {{ request.base_url }}satsdice/api/v1/links/<satsdice_id> -H
"X-Api-Key: {{ user.wallets[0].inkey }}"
@@ -73,7 +73,7 @@
{"lnurl": <string>}
Curl example
curl -X POST {{ request.base_url }}api/v1/links -d '{"title":
+ >curl -X POST {{ request.base_url }}satsdice/api/v1/links -d '{"title":
<string>, "min_satsdiceable": <integer>,
"max_satsdiceable": <integer>, "uses": <integer>,
"wait_time": <integer>, "is_unique": <boolean>}' -H
@@ -109,7 +109,7 @@
{"lnurl": <string>}
Curl example
curl -X PUT {{ request.base_url }}api/v1/links/<satsdice_id> -d
+ >curl -X PUT {{ request.base_url }}satsdice/api/v1/links/<satsdice_id> -d
'{"title": <string>, "min_satsdiceable": <integer>,
"max_satsdiceable": <integer>, "uses": <integer>,
"wait_time": <integer>, "is_unique": <boolean>}' -H
@@ -137,7 +137,7 @@
Curl example
curl -X DELETE {{ request.base_url }}api/v1/links/<satsdice_id>
+ >curl -X DELETE {{ request.base_url }}satsdice/api/v1/links/<satsdice_id>
-H "X-Api-Key: {{ user.wallets[0].adminkey }}"
@@ -165,7 +165,7 @@
Curl example
curl -X GET {{ request.base_url
- }}api/v1/links/<the_hash>/<lnurl_id> -H "X-Api-Key: {{
+ }}satsdice/api/v1/links/<the_hash>/<lnurl_id> -H "X-Api-Key: {{
user.wallets[0].inkey }}"
@@ -186,7 +186,7 @@
>
Curl example
curl -X GET {{ request.base_url }}/satsdice/img/<lnurl_id>"
+ >curl -X GET {{ request.base_url }}satsdice/img/<lnurl_id>"
diff --git a/lnbits/extensions/satspay/templates/satspay/_api_docs.html b/lnbits/extensions/satspay/templates/satspay/_api_docs.html
index d834db200..89380de00 100644
--- a/lnbits/extensions/satspay/templates/satspay/_api_docs.html
+++ b/lnbits/extensions/satspay/templates/satspay/_api_docs.html
@@ -32,7 +32,7 @@
[<charge_object>, ...]
Curl example
curl -X POST {{ request.base_url }}api/v1/charge -d
+ >curl -X POST {{ request.base_url }}satspay/api/v1/charge -d
'{"onchainwallet": <string, watchonly_wallet_id>,
"description": <string>, "webhook":<string>, "time":
<integer>, "amount": <integer>, "lnbitswallet":
@@ -60,7 +60,7 @@
[<charge_object>, ...]
Curl example
curl -X POST {{ request.base_url }}api/v1/charge/<charge_id>
+ >curl -X POST {{ request.base_url }}satspay/api/v1/charge/<charge_id>
-d '{"onchainwallet": <string, watchonly_wallet_id>,
"description": <string>, "webhook":<string>, "time":
<integer>, "amount": <integer>, "lnbitswallet":
@@ -89,7 +89,7 @@
[<charge_object>, ...]
Curl example
curl -X GET {{ request.base_url }}api/v1/charge/<charge_id>
+ >curl -X GET {{ request.base_url }}satspay/api/v1/charge/<charge_id>
-H "X-Api-Key: {{ user.wallets[0].inkey }}"
@@ -112,7 +112,7 @@
[<charge_object>, ...]
Curl example
curl -X GET {{ request.base_url }}api/v1/charges -H "X-Api-Key: {{
+ >curl -X GET {{ request.base_url }}satspay/api/v1/charges -H "X-Api-Key: {{
user.wallets[0].inkey }}"
@@ -123,7 +123,6 @@
dense
expand-separator
label="Delete a pay link"
- class="q-pb-md"
>
@@ -138,13 +137,18 @@
Curl example
curl -X DELETE {{ request.base_url
- }}api/v1/charge/<charge_id> -H "X-Api-Key: {{
+ }}satspay/api/v1/charge/<charge_id> -H "X-Api-Key: {{
user.wallets[0].adminkey }}"
-
+
Curl example
curl -X GET {{ request.base_url
- }}api/v1/charges/balance/<charge_id> -H "X-Api-Key: {{
+ }}satspay/api/v1/charges/balance/<charge_id> -H "X-Api-Key: {{
user.wallets[0].inkey }}"
diff --git a/lnbits/extensions/splitpayments/templates/splitpayments/_api_docs.html b/lnbits/extensions/splitpayments/templates/splitpayments/_api_docs.html
index 78b5362cd..7a8a6d07e 100644
--- a/lnbits/extensions/splitpayments/templates/splitpayments/_api_docs.html
+++ b/lnbits/extensions/splitpayments/templates/splitpayments/_api_docs.html
@@ -52,7 +52,7 @@
>
Curl example
curl -X GET {{ request.base_url }}api/v1/livestream -H "X-Api-Key: {{
+ >curl -X GET {{ request.base_url }}splitpayments/api/v1/targets -H "X-Api-Key: {{
user.wallets[0].inkey }}"
@@ -63,6 +63,7 @@
dense
expand-separator
label="Set Target Wallets"
+ class="q-pb-md"
>
@@ -78,7 +79,7 @@
Curl example
curl -X PUT {{ request.base_url }}api/v1/splitpayments/targets -H
+ >curl -X PUT {{ request.base_url }}splitpayments/api/v1/targets -H
"X-Api-Key: {{ user.wallets[0].adminkey }}" -H 'Content-Type:
application/json' -d '{"targets": [{"wallet": <wallet id or invoice
key>, "alias": <name to identify this>, "percent": <number
diff --git a/lnbits/extensions/tpos/__init__.py b/lnbits/extensions/tpos/__init__.py
index c62981d72..1aed95bac 100644
--- a/lnbits/extensions/tpos/__init__.py
+++ b/lnbits/extensions/tpos/__init__.py
@@ -1,7 +1,10 @@
+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_tpos")
@@ -12,5 +15,11 @@ def tpos_renderer():
return template_renderer(["lnbits/extensions/tpos/templates"])
+from .tasks import wait_for_paid_invoices
from .views_api import * # noqa
from .views import * # noqa
+
+
+def tpos_start():
+ loop = asyncio.get_event_loop()
+ loop.create_task(catch_everything_and_restart(wait_for_paid_invoices))
diff --git a/lnbits/extensions/tpos/config.json b/lnbits/extensions/tpos/config.json
index c5789afb7..3bd1a71a4 100644
--- a/lnbits/extensions/tpos/config.json
+++ b/lnbits/extensions/tpos/config.json
@@ -2,5 +2,5 @@
"name": "TPoS",
"short_description": "A shareable PoS terminal!",
"icon": "dialpad",
- "contributors": ["talvasconcelos", "arcbtc"]
+ "contributors": ["talvasconcelos", "arcbtc", "leesalminen"]
}
diff --git a/lnbits/extensions/tpos/crud.py b/lnbits/extensions/tpos/crud.py
index 1a1987696..8f071d8cc 100644
--- a/lnbits/extensions/tpos/crud.py
+++ b/lnbits/extensions/tpos/crud.py
@@ -10,10 +10,17 @@ async def create_tpos(wallet_id: str, data: CreateTposData) -> TPoS:
tpos_id = urlsafe_short_hash()
await db.execute(
"""
- INSERT INTO tpos.tposs (id, wallet, name, currency)
- VALUES (?, ?, ?, ?)
+ INSERT INTO tpos.tposs (id, wallet, name, currency, tip_options, tip_wallet)
+ VALUES (?, ?, ?, ?, ?, ?)
""",
- (tpos_id, wallet_id, data.name, data.currency),
+ (
+ tpos_id,
+ wallet_id,
+ data.name,
+ data.currency,
+ data.tip_options,
+ data.tip_wallet,
+ ),
)
tpos = await get_tpos(tpos_id)
diff --git a/lnbits/extensions/tpos/migrations.py b/lnbits/extensions/tpos/migrations.py
index 7a7fff0d5..565c05abf 100644
--- a/lnbits/extensions/tpos/migrations.py
+++ b/lnbits/extensions/tpos/migrations.py
@@ -12,3 +12,25 @@ async def m001_initial(db):
);
"""
)
+
+
+async def m002_addtip_wallet(db):
+ """
+ Add tips to tposs table
+ """
+ await db.execute(
+ """
+ ALTER TABLE tpos.tposs ADD tip_wallet TEXT NULL;
+ """
+ )
+
+
+async def m003_addtip_options(db):
+ """
+ Add tips to tposs table
+ """
+ await db.execute(
+ """
+ ALTER TABLE tpos.tposs ADD tip_options TEXT NULL;
+ """
+ )
diff --git a/lnbits/extensions/tpos/models.py b/lnbits/extensions/tpos/models.py
index 653a055ca..6a2ff1d2c 100644
--- a/lnbits/extensions/tpos/models.py
+++ b/lnbits/extensions/tpos/models.py
@@ -6,6 +6,8 @@ from pydantic import BaseModel
class CreateTposData(BaseModel):
name: str
currency: str
+ tip_options: str
+ tip_wallet: str
class TPoS(BaseModel):
@@ -13,6 +15,8 @@ class TPoS(BaseModel):
wallet: str
name: str
currency: str
+ tip_options: str
+ tip_wallet: str
@classmethod
def from_row(cls, row: Row) -> "TPoS":
diff --git a/lnbits/extensions/tpos/tasks.py b/lnbits/extensions/tpos/tasks.py
new file mode 100644
index 000000000..0bb8dff92
--- /dev/null
+++ b/lnbits/extensions/tpos/tasks.py
@@ -0,0 +1,70 @@
+import asyncio
+import json
+
+from lnbits.core import db as core_db
+from lnbits.core.crud import create_payment
+from lnbits.core.models import Payment
+from lnbits.helpers import urlsafe_short_hash
+from lnbits.tasks import internal_invoice_queue, register_invoice_listener
+
+from .crud import get_tpos
+
+
+async def wait_for_paid_invoices():
+ invoice_queue = asyncio.Queue()
+ register_invoice_listener(invoice_queue)
+
+ while True:
+ payment = await invoice_queue.get()
+ await on_invoice_paid(payment)
+
+
+async def on_invoice_paid(payment: Payment) -> None:
+ if "tpos" == payment.extra.get("tag") and payment.extra.get("tipSplitted"):
+ # already splitted, ignore
+ return
+
+ # now we make some special internal transfers (from no one to the receiver)
+ tpos = await get_tpos(payment.extra.get("tposId"))
+
+ tipAmount = payment.extra.get("tipAmount")
+
+ if tipAmount is None:
+ # no tip amount
+ return
+
+ tipAmount = tipAmount * 1000
+
+ # mark the original payment with one extra key, "splitted"
+ # (this prevents us from doing this process again and it's informative)
+ # and reduce it by the amount we're going to send to the producer
+ await core_db.execute(
+ """
+ UPDATE apipayments
+ SET extra = ?, amount = amount - ?
+ WHERE hash = ?
+ AND checking_id NOT LIKE 'internal_%'
+ """,
+ (
+ json.dumps(dict(**payment.extra, tipSplitted=True)),
+ tipAmount,
+ payment.payment_hash,
+ ),
+ )
+
+ # perform the internal transfer using the same payment_hash
+ internal_checking_id = f"internal_{urlsafe_short_hash()}"
+ await create_payment(
+ wallet_id=tpos.tip_wallet,
+ checking_id=internal_checking_id,
+ payment_request="",
+ payment_hash=payment.payment_hash,
+ amount=tipAmount,
+ memo=payment.memo,
+ pending=False,
+ extra={"tipSplitted": True},
+ )
+
+ # manually send this for now
+ await internal_invoice_queue.put(internal_checking_id)
+ return
diff --git a/lnbits/extensions/tpos/templates/tpos/_api_docs.html b/lnbits/extensions/tpos/templates/tpos/_api_docs.html
index 7897383d0..42160cce2 100644
--- a/lnbits/extensions/tpos/templates/tpos/_api_docs.html
+++ b/lnbits/extensions/tpos/templates/tpos/_api_docs.html
@@ -17,7 +17,7 @@
[<tpos_object>, ...]
Curl example
curl -X GET {{ request.base_url }}api/v1/tposs -H "X-Api-Key:
+ >curl -X GET {{ request.base_url }}tpos/api/v1/tposs -H "X-Api-Key:
<invoice_key>"
@@ -42,7 +42,7 @@
>
Curl example
curl -X POST {{ request.base_url }}api/v1/tposs -d '{"name":
+ >curl -X POST {{ request.base_url }}tpos/api/v1/tposs -d '{"name":
<string>, "currency": <string>}' -H "Content-type:
application/json" -H "X-Api-Key: <admin_key>"
@@ -69,7 +69,7 @@
Curl example
curl -X DELETE {{ request.base_url }}api/v1/tposs/<tpos_id> -H
+ >curl -X DELETE {{ request.base_url }}tpos/api/v1/tposs/<tpos_id> -H
"X-Api-Key: <admin_key>"
diff --git a/lnbits/extensions/tpos/templates/tpos/index.html b/lnbits/extensions/tpos/templates/tpos/index.html
index a8971211a..af3b0573f 100644
--- a/lnbits/extensions/tpos/templates/tpos/index.html
+++ b/lnbits/extensions/tpos/templates/tpos/index.html
@@ -54,7 +54,7 @@
>
- {{ col.value }}
+ {{ (col.name == 'tip_options' ? JSON.parse(col.value).join(", ") : col.value) }}
+
+
parseInt(str))) : JSON.stringify([])),
+ tip_wallet: this.formDialog.data.tip_wallet || "",
}
var self = this
diff --git a/lnbits/extensions/tpos/templates/tpos/tpos.html b/lnbits/extensions/tpos/templates/tpos/tpos.html
index 49d88140f..e4ea14992 100644
--- a/lnbits/extensions/tpos/templates/tpos/tpos.html
+++ b/lnbits/extensions/tpos/templates/tpos/tpos.html
@@ -1,5 +1,17 @@
-{% extends "public.html" %} {% block toolbar_title %}{{ tpos.name }}{% endblock
-%} {% block footer %}{% endblock %} {% block page_container %}
+
+{% extends "public.html" %}
+{% block toolbar_title %}
+{{ tpos.name }}
+
+{% endblock %}
+{% block footer %}{% endblock %} {% block page_container %}
@@ -43,16 +55,6 @@
color="primary"
>3
- C
9
- OK
# C
+ OK
@@ -176,6 +179,38 @@
+
+
+
+
+ Would you like to leave a tip?
+
+
+ {% raw %}{{ tip }}{% endraw %}%
+
+
+
+
+
+ Close
+
+
+
+
@@ -214,6 +249,10 @@
{% endblock %} {% block styles %}
{% endblock %} {% block scripts %}
@@ -241,14 +279,19 @@
return {
tposId: '{{ tpos.id }}',
currency: '{{ tpos.currency }}',
+ tip_options: JSON.parse('{{ tpos.tip_options }}'),
exchangeRate: null,
stack: [],
+ tipAmount: 0.00,
invoiceDialog: {
show: false,
data: null,
dismissMsg: null,
paymentChecker: null
},
+ tipDialog: {
+ show: false,
+ },
urlDialog: {
show: false
},
@@ -269,6 +312,10 @@
if (!this.exchangeRate) return 0
return Math.ceil((this.amount / this.exchangeRate) * 100000000)
},
+ tipAmountSat: function () {
+ if (!this.exchangeRate) return 0
+ return Math.ceil((this.tipAmount / this.exchangeRate) * 100000000)
+ },
fsat: function () {
console.log('sat', this.sat, LNbits.utils.formatSat(this.sat))
return LNbits.utils.formatSat(this.sat)
@@ -277,12 +324,46 @@
methods: {
closeInvoiceDialog: function () {
this.stack = []
+ this.tipAmount = 0.00
var dialog = this.invoiceDialog
setTimeout(function () {
clearInterval(dialog.paymentChecker)
dialog.dismissMsg()
}, 3000)
},
+ 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()
+
+ this.stack = []
+ for (var i = 0; i < totalString.length; i++) {
+ const char = totalString[i]
+
+ if(char !== ".") {
+ this.stack.push(char)
+ }
+ }
+
+ this.tipAmount = tipAmount
+ }
+
+ this.showInvoice()
+ },
+ submitForm: function() {
+ if(this.tip_options.length) {
+ this.showTipModal()
+ } else {
+ this.showInvoice()
+ }
+ },
+ showTipModal: function() {
+ this.tipDialog.show = true
+ },
showInvoice: function () {
var self = this
var dialog = this.invoiceDialog
@@ -290,7 +371,8 @@
axios
.post('/tpos/api/v1/tposs/' + this.tposId + '/invoices', null, {
params: {
- amount: this.sat
+ amount: this.sat,
+ tipAmount: this.tipAmountSat,
}
})
.then(function (response) {
diff --git a/lnbits/extensions/tpos/views.py b/lnbits/extensions/tpos/views.py
index 2d78ecce1..a94564d57 100644
--- a/lnbits/extensions/tpos/views.py
+++ b/lnbits/extensions/tpos/views.py
@@ -8,6 +8,10 @@ from starlette.responses import HTMLResponse
from lnbits.core.models import User
from lnbits.decorators import check_user_exists
+from lnbits.settings import (
+ LNBITS_CUSTOM_LOGO,
+ LNBITS_SITE_TITLE,
+)
from . import tpos_ext, tpos_renderer
from .crud import get_tpos
@@ -33,3 +37,40 @@ async def tpos(request: Request, tpos_id):
return tpos_renderer().TemplateResponse(
"tpos/tpos.html", {"request": request, "tpos": tpos}
)
+
+
+@tpos_ext.get("/manifest/{tpos_id}.webmanifest")
+async def manifest(tpos_id: str):
+ tpos = await get_tpos(tpos_id)
+ if not tpos:
+ raise HTTPException(
+ status_code=HTTPStatus.NOT_FOUND, detail="TPoS does not exist."
+ )
+
+ return {
+ "short_name": LNBITS_SITE_TITLE,
+ "name": tpos.name + " - " + LNBITS_SITE_TITLE,
+ "icons": [
+ {
+ "src": LNBITS_CUSTOM_LOGO
+ if LNBITS_CUSTOM_LOGO
+ else "https://cdn.jsdelivr.net/gh/lnbits/lnbits@0.3.0/docs/logos/lnbits.png",
+ "type": "image/png",
+ "sizes": "900x900",
+ }
+ ],
+ "start_url": "/tpos/" + tpos_id,
+ "background_color": "#1F2234",
+ "description": "Bitcoin Lightning tPOS",
+ "display": "standalone",
+ "scope": "/tpos/" + tpos_id,
+ "theme_color": "#1F2234",
+ "shortcuts": [
+ {
+ "name": tpos.name + " - " + LNBITS_SITE_TITLE,
+ "short_name": tpos.name,
+ "description": tpos.name + " - " + LNBITS_SITE_TITLE,
+ "url": "/tpos/" + tpos_id,
+ }
+ ],
+ }
diff --git a/lnbits/extensions/tpos/views_api.py b/lnbits/extensions/tpos/views_api.py
index ae457b61a..fb4bd0ab1 100644
--- a/lnbits/extensions/tpos/views_api.py
+++ b/lnbits/extensions/tpos/views_api.py
@@ -52,7 +52,9 @@ async def api_tpos_delete(
@tpos_ext.post("/api/v1/tposs/{tpos_id}/invoices", status_code=HTTPStatus.CREATED)
-async def api_tpos_create_invoice(amount: int = Query(..., ge=1), tpos_id: str = None):
+async def api_tpos_create_invoice(
+ amount: int = Query(..., ge=1), tipAmount: int = None, tpos_id: str = None
+):
tpos = await get_tpos(tpos_id)
if not tpos:
@@ -65,7 +67,7 @@ async def api_tpos_create_invoice(amount: int = Query(..., ge=1), tpos_id: str =
wallet_id=tpos.wallet,
amount=amount,
memo=f"{tpos.name}",
- extra={"tag": "tpos"},
+ extra={"tag": "tpos", "tipAmount": tipAmount, "tposId": tpos_id},
)
except Exception as e:
raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(e))
@@ -84,6 +86,7 @@ async def api_tpos_check_invoice(tpos_id: str, payment_hash: str):
)
try:
status = await api_payment(payment_hash)
+
except Exception as exc:
print(exc)
return {"paid": False}
diff --git a/lnbits/extensions/watchonly/templates/watchonly/_api_docs.html b/lnbits/extensions/watchonly/templates/watchonly/_api_docs.html
index e82171920..bff663833 100644
--- a/lnbits/extensions/watchonly/templates/watchonly/_api_docs.html
+++ b/lnbits/extensions/watchonly/templates/watchonly/_api_docs.html
@@ -37,7 +37,7 @@
[<wallets_object>, ...]
Curl example
curl -X GET {{ request.base_url }}api/v1/wallet -H "X-Api-Key: {{
+ >curl -X GET {{ request.base_url }}watchonly/api/v1/wallet -H "X-Api-Key: {{
user.wallets[0].inkey }}"
@@ -66,7 +66,7 @@
[<wallet_object>, ...]
Curl example
curl -X GET {{ request.base_url }}api/v1/wallet/<wallet_id>
+ >curl -X GET {{ request.base_url }}watchonly/api/v1/wallet/<wallet_id>
-H "X-Api-Key: {{ user.wallets[0].inkey }}"
@@ -89,7 +89,7 @@
[<wallet_object>, ...]
Curl example
curl -X POST {{ request.base_url }}api/v1/wallet -d '{"title":
+ >curl -X POST {{ request.base_url }}watchonly/api/v1/wallet -d '{"title":
<string>, "masterpub": <string>}' -H "Content-type:
application/json" -H "X-Api-Key: {{ user.wallets[0].adminkey }}"
@@ -116,7 +116,7 @@
Curl example
curl -X DELETE {{ request.base_url
- }}api/v1/wallet/<wallet_id> -H "X-Api-Key: {{
+ }}watchonly/api/v1/wallet/<wallet_id> -H "X-Api-Key: {{
user.wallets[0].adminkey }}"
@@ -142,7 +142,7 @@
Curl example
curl -X GET {{ request.base_url
- }}api/v1/addresses/<wallet_id> -H "X-Api-Key: {{
+ }}watchonly/api/v1/addresses/<wallet_id> -H "X-Api-Key: {{
user.wallets[0].inkey }}"
@@ -173,7 +173,7 @@
[<address_object>, ...]
Curl example
curl -X GET {{ request.base_url }}api/v1/address/<wallet_id>
+ >curl -X GET {{ request.base_url }}watchonly/api/v1/address/<wallet_id>
-H "X-Api-Key: {{ user.wallets[0].inkey }}"
@@ -202,7 +202,7 @@
[<mempool_object>, ...]
Curl example
curl -X GET {{ request.base_url }}api/v1/mempool -H "X-Api-Key: {{
+ >curl -X GET {{ request.base_url }}watchonly/api/v1/mempool -H "X-Api-Key: {{
user.wallets[0].adminkey }}"
@@ -233,7 +233,7 @@
[<mempool_object>, ...]
Curl example
curl -X PUT {{ request.base_url }}api/v1/mempool -d '{"endpoint":
+ >curl -X PUT {{ request.base_url }}watchonly/api/v1/mempool -d '{"endpoint":
<string>}' -H "Content-type: application/json" -H "X-Api-Key:
{{ user.wallets[0].adminkey }}"
diff --git a/lnbits/static/scss/base.scss b/lnbits/static/scss/base.scss
index 3668e7736..672a85b61 100644
--- a/lnbits/static/scss/base.scss
+++ b/lnbits/static/scss/base.scss
@@ -140,4 +140,10 @@ video {
// text-wrap
.text-wrap {
word-break: break-word;
+}
+
+.q-card {
+ code {
+ overflow-wrap: break-word;
+ }
}
\ No newline at end of file