From f01028eac74c4aa0e31aee732b75e229a8f5568c Mon Sep 17 00:00:00 2001 From: fiatjaf Date: Sun, 13 Sep 2020 21:31:05 -0300 Subject: [PATCH] migrate from flask to quart. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit also remove all flaskiness from static file serving. and reference all vendored scripts on the base tempĺate for simplicity. --- Makefile | 8 +- Pipfile | 10 +- Pipfile.lock | 223 +++++++++++------- app.json | 4 +- docs/devs/installation.md | 8 +- lnbits/app.py | 60 ++--- lnbits/commands.py | 2 +- lnbits/core/__init__.py | 6 +- lnbits/core/crud.py | 2 +- lnbits/core/services.py | 2 +- lnbits/core/templates/core/extensions.html | 7 +- lnbits/core/templates/core/index.html | 7 +- lnbits/core/templates/core/wallet.html | 20 +- lnbits/core/views/api.py | 16 +- lnbits/core/views/generic.py | 22 +- lnbits/core/views/lnurl.py | 4 +- lnbits/decorators.py | 21 +- lnbits/ext.py | 6 - lnbits/extensions/amilk/__init__.py | 2 +- lnbits/extensions/amilk/views.py | 11 +- lnbits/extensions/amilk/views_api.py | 10 +- lnbits/extensions/diagonalley/__init__.py | 2 +- lnbits/extensions/diagonalley/views.py | 10 +- lnbits/extensions/diagonalley/views_api.py | 34 +-- lnbits/extensions/events/__init__.py | 2 +- .../events/templates/events/display.html | 1 - .../events/templates/events/register.html | 17 -- .../events/templates/events/ticket.html | 1 - lnbits/extensions/events/views.py | 28 ++- lnbits/extensions/events/views_api.py | 20 +- lnbits/extensions/example/__init__.py | 2 +- lnbits/extensions/example/views.py | 6 +- lnbits/extensions/example/views_api.py | 4 +- lnbits/extensions/lndhub/__init__.py | 2 +- lnbits/extensions/lndhub/decorators.py | 6 +- .../lndhub/templates/lndhub/index.html | 35 +-- lnbits/extensions/lndhub/views.py | 6 +- lnbits/extensions/lndhub/views_api.py | 24 +- lnbits/extensions/lnticket/__init__.py | 2 +- .../lnticket/templates/lnticket/display.html | 1 - lnbits/extensions/lnticket/views.py | 10 +- lnbits/extensions/lnticket/views_api.py | 16 +- lnbits/extensions/lnurlp/__init__.py | 2 +- lnbits/extensions/lnurlp/models.py | 2 +- .../lnurlp/templates/lnurlp/display.html | 1 - .../lnurlp/templates/lnurlp/index.html | 1 - .../lnurlp/templates/lnurlp/print_qr.html | 1 - lnbits/extensions/lnurlp/views.py | 16 +- lnbits/extensions/lnurlp/views_api.py | 14 +- lnbits/extensions/paywall/__init__.py | 2 +- .../paywall/templates/paywall/display.html | 1 - lnbits/extensions/paywall/views.py | 11 +- lnbits/extensions/paywall/views_api.py | 12 +- lnbits/extensions/tpos/__init__.py | 2 +- .../extensions/tpos/templates/tpos/tpos.html | 1 - lnbits/extensions/tpos/views.py | 10 +- lnbits/extensions/tpos/views_api.py | 12 +- lnbits/extensions/usermanager/__init__.py | 2 +- lnbits/extensions/usermanager/views.py | 9 +- lnbits/extensions/usermanager/views_api.py | 29 +-- lnbits/extensions/withdraw/__init__.py | 6 +- lnbits/extensions/withdraw/models.py | 2 +- .../withdraw/templates/withdraw/display.html | 2 - .../withdraw/templates/withdraw/index.html | 9 +- .../withdraw/templates/withdraw/print_qr.html | 12 +- lnbits/extensions/withdraw/views.py | 16 +- lnbits/extensions/withdraw/views_api.py | 16 +- lnbits/settings.py | 3 - lnbits/static/css/base.css | 78 +----- lnbits/templates/base.html | 44 ++-- lnbits/templates/print.html | 15 +- requirements.txt | 44 ++-- 72 files changed, 473 insertions(+), 582 deletions(-) delete mode 100644 lnbits/ext.py diff --git a/Makefile b/Makefile index a95fde2..a48fa1a 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -all: format check +all: format check lnbits/static/css/base.css requirements.txt format: prettier black @@ -18,3 +18,9 @@ checkprettier: $(shell find lnbits -name "*.js" -name ".html") checkblack: $(shell find lnbits -name "*.py") ./venv/bin/black --check lnbits + +lnbits/static/css/base.css: lnbits/static/scss/base.scss + ./venv/bin/pyscss -o lnbits/static/css/base.css lnbits/static/scss/base.scss + +requirements.txt: Pipfile.lock + cat Pipfile.lock | jq -r '.default | map_values(.version) | to_entries | map("\(.key)\(.value)") | join("\n")' > requirements.txt diff --git a/Pipfile b/Pipfile index 0962b5d..1e81675 100644 --- a/Pipfile +++ b/Pipfile @@ -11,15 +11,15 @@ bitstring = "*" cerberus = "*" ecdsa = "*" environs = "*" -flask = "*" -flask-assets = "*" -flask-compress = "*" -flask-cors = "*" -flask-talisman = "*" lnurl = "*" pyscss = "*" requests = "*" shortuuid = "*" +quart = "*" +quart-cors = "*" +quart-compress = "*" +secure = "*" +typing-extensions = "*" [dev-packages] black = "==20.8b1" diff --git a/Pipfile.lock b/Pipfile.lock index f2e187a..93ae73b 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "2270f2525e54e976b09491e458033d25ec5bbdea9e74d417e787df33031c6948" + "sha256": "2c716474f9f263d8e1310ca44c2f50996f3516273b483a40e2b2ad68b8071dd6" }, "pipfile-spec": 6, "requires": { @@ -16,6 +16,13 @@ ] }, "default": { + "aiofiles": { + "hashes": [ + "sha256:377fdf7815cc611870c59cbd07b68b180841d2a2b79812d8c218be02448c2acb", + "sha256:98e6bcfd1b50f97db4980e182ddd509b7cc35909e903a8fe50d8849e02d815af" + ], + "version": "==0.5.0" + }, "bech32": { "hashes": [ "sha256:7d6db8214603bd7871fcfa6c0826ef68b85b0abd90fa21c285a9c5e21d2bd899", @@ -31,6 +38,12 @@ "index": "pypi", "version": "==3.1.7" }, + "blinker": { + "hashes": [ + "sha256:471aee25f3992bd325afa3772f1063dbdbbca947a041b8b89466dc00d606f8b6" + ], + "version": "==1.4" + }, "brotli": { "hashes": [ "sha256:160c78292e98d21e73a4cc7f76a234390e516afcd982fa17e1422f7c6a9ce9c8", @@ -108,44 +121,41 @@ "index": "pypi", "version": "==8.0.0" }, - "flask": { + "h11": { "hashes": [ - "sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060", - "sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557" + "sha256:311dc5478c2568cc07262e0381cdfc5b9c6ba19775905736c87e81ae6662b9fd", + "sha256:9eecfbafc980976dbff26a01dd3487644dd5d00f8038584451fc64a660f7c502" ], - "index": "pypi", - "version": "==1.1.2" + "version": "==0.10.0" }, - "flask-assets": { + "h2": { "hashes": [ - "sha256:1dfdea35e40744d46aada72831f7613d67bf38e8b20ccaaa9e91fdc37aa3b8c2", - "sha256:2845bd3b479be9db8556801e7ebc2746ce2d9edb4e7b64a1c786ecbfc1e5867b" + "sha256:61e0f6601fa709f35cdb730863b4e5ec7ad449792add80d1410d4174ed139af5", + "sha256:875f41ebd6f2c44781259005b157faed1a5031df3ae5aa7bcb4628a6c0782f14" ], - "index": "pypi", - "version": "==2.0" + "version": "==3.2.0" }, - "flask-compress": { + "hpack": { "hashes": [ - "sha256:f367b2b46003dd62be34f7fb1379938032656dca56377a9bc90e7188e4289a7c" + "sha256:0edd79eda27a53ba5be2dfabf3b15780928a0dff6eb0c60a3d6767720e970c89", + "sha256:8eec9c1f4bfae3408a3f30500261f7e6a65912dc138526ea054f9ad98892e9d2" ], - "index": "pypi", - "version": "==1.5.0" + "version": "==3.0.0" }, - "flask-cors": { + "hypercorn": { "hashes": [ - "sha256:6bcfc100288c5d1bcb1dbb854babd59beee622ffd321e444b05f24d6d58466b8", - "sha256:cee4480aaee421ed029eaa788f4049e3e26d15b5affb6a880dade6bafad38324" + "sha256:19f32e7267225c8108ad585b2c5deddf1fe75950797a0e87a682a3a00ef1af95", + "sha256:809d77f3bf9fa0794a598d8dfa0f8d889e7e1c2f927581cd33068803169dc474" ], - "index": "pypi", - "version": "==3.0.9" + "markers": "python_version >= '3.7'", + "version": "==0.10.2" }, - "flask-talisman": { + "hyperframe": { "hashes": [ - "sha256:468131464a249274ed226efc21b372518f442487e58918ccab8357eaa638fd1f", - "sha256:eaa754f4b771dfbe473843391d69643b79e3a38c865790011ac5e4179c68e3ec" + "sha256:5187962cb16dcc078f23cb5a4b110098d546c3f41ff2d4038a9896893bbd0b40", + "sha256:a9f5c17f2cc3c719b917c4f33ed1c61bd1f8dfac4b1bd23b7c80b3400971b41f" ], - "index": "pypi", - "version": "==0.7.0" + "version": "==5.2.0" }, "idna": { "hashes": [ @@ -225,6 +235,13 @@ "markers": "python_version >= '3.5'", "version": "==3.7.1" }, + "priority": { + "hashes": [ + "sha256:6bc1961a6d7fcacbfc337769f1a382c8e746566aaa365e78047abe9f66b2ffbe", + "sha256:be4fcb94b5e37cdeb40af5533afe6dd603bd665fe9c8b3052610fc1001d5d1eb" + ], + "version": "==1.3.0" + }, "pydantic": { "hashes": [ "sha256:1783c1d927f9e1366e0e0609ae324039b2479a1a282a98ed6a6836c9ed02002c", @@ -262,6 +279,30 @@ ], "version": "==0.14.0" }, + "quart": { + "hashes": [ + "sha256:9c634e4c1e4b21b824003c676de1583581258c72b0ac4d2ba747db846e97ff56", + "sha256:d885d782edd9d5dcfd2c4a56e020db3b82493d4c3950f91c221b7d88d239ac93" + ], + "index": "pypi", + "version": "==0.13.1" + }, + "quart-compress": { + "hashes": [ + "sha256:41cd0cc8d26905a45025ddda7022461a71b9d1d950b21b006dc106a1c41c75ef", + "sha256:63af5e6370aa7850fb219d22e1db89965aeb13b8f27bc83e7f9a44118faa3c54" + ], + "index": "pypi", + "version": "==0.2.1" + }, + "quart-cors": { + "hashes": [ + "sha256:020a17d504264db86cada3c1335ef174af28b33f57cee321ddc46d69c33d5c8e", + "sha256:c08bdb326219b6c186d19ed6a97a7fd02de8fe36c7856af889494c69b525c53c" + ], + "index": "pypi", + "version": "==0.3.0" + }, "requests": { "hashes": [ "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b", @@ -270,6 +311,14 @@ "index": "pypi", "version": "==2.24.0" }, + "secure": { + "hashes": [ + "sha256:4dc8dd4b548831c3ad7f94079332c41d67c781eccc32215ff5a8a49582c1a447", + "sha256:b3bf1e39ebf40040fc3248392343a5052aa14cb45fc87ec91b0bd11f19cc46bd" + ], + "index": "pypi", + "version": "==0.2.1" + }, "shortuuid": { "hashes": [ "sha256:3c11d2007b915c43bee3e10625f068d8a349e04f0d81f08f5fa08507427ebf1f", @@ -286,13 +335,20 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.15.0" }, + "toml": { + "hashes": [ + "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f", + "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88" + ], + "version": "==0.10.1" + }, "typing-extensions": { "hashes": [ "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918", "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c", "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f" ], - "markers": "python_version < '3.8'", + "index": "pypi", "version": "==3.7.4.3" }, "urllib3": { @@ -303,13 +359,6 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", "version": "==1.25.10" }, - "webassets": { - "hashes": [ - "sha256:167132337677c8cedc9705090f6d48da3fb262c8e0b2773b29f3352f050181cd", - "sha256:a31a55147752ba1b3dc07dee0ad8c8efff274464e08bbdb88c1fd59ffd552724" - ], - "version": "==2.0" - }, "werkzeug": { "hashes": [ "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43", @@ -317,6 +366,14 @@ ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==1.0.1" + }, + "wsproto": { + "hashes": [ + "sha256:614798c30e5dc2b3f65acc03d2d50842b97621487350ce79a80a711229edfa9d", + "sha256:e3d190a11d9307112ba23bbe60055604949b172143969c8f641318476a9b6f1d" + ], + "markers": "python_full_version >= '3.6.1'", + "version": "==0.15.0" } }, "develop": { @@ -329,11 +386,11 @@ }, "attrs": { "hashes": [ - "sha256:0ef97238856430dcf9228e07f316aefc17e8939fc8507e18c6501b761ef1a42a", - "sha256:2867b7b9f8326499ab5b0e2d12801fa5c98842d2cbd22b35112ae04bf85b4dff" + "sha256:26b54ddbbb9ee1d34d5d3668dd37d6cf74990ab23c828c2888dccdceee395594", + "sha256:fce7fc47dfc976152e82d53ff92fa0407700c21acd20886a13777a0d20e655dc" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==20.1.0" + "version": "==20.2.0" }, "black": { "hashes": [ @@ -353,43 +410,43 @@ }, "coverage": { "hashes": [ - "sha256:098a703d913be6fbd146a8c50cc76513d726b022d170e5e98dc56d958fd592fb", - "sha256:16042dc7f8e632e0dcd5206a5095ebd18cb1d005f4c89694f7f8aafd96dd43a3", - "sha256:1adb6be0dcef0cf9434619d3b892772fdb48e793300f9d762e480e043bd8e716", - "sha256:27ca5a2bc04d68f0776f2cdcb8bbd508bbe430a7bf9c02315cd05fb1d86d0034", - "sha256:28f42dc5172ebdc32622a2c3f7ead1b836cdbf253569ae5673f499e35db0bac3", - "sha256:2fcc8b58953d74d199a1a4d633df8146f0ac36c4e720b4a1997e9b6327af43a8", - "sha256:304fbe451698373dc6653772c72c5d5e883a4aadaf20343592a7abb2e643dae0", - "sha256:30bc103587e0d3df9e52cd9da1dd915265a22fad0b72afe54daf840c984b564f", - "sha256:40f70f81be4d34f8d491e55936904db5c527b0711b2a46513641a5729783c2e4", - "sha256:4186fc95c9febeab5681bc3248553d5ec8c2999b8424d4fc3a39c9cba5796962", - "sha256:46794c815e56f1431c66d81943fa90721bb858375fb36e5903697d5eef88627d", - "sha256:4869ab1c1ed33953bb2433ce7b894a28d724b7aa76c19b11e2878034a4e4680b", - "sha256:4f6428b55d2916a69f8d6453e48a505c07b2245653b0aa9f0dee38785939f5e4", - "sha256:52f185ffd3291196dc1aae506b42e178a592b0b60a8610b108e6ad892cfc1bb3", - "sha256:538f2fd5eb64366f37c97fdb3077d665fa946d2b6d95447622292f38407f9258", - "sha256:64c4f340338c68c463f1b56e3f2f0423f7b17ba6c3febae80b81f0e093077f59", - "sha256:675192fca634f0df69af3493a48224f211f8db4e84452b08d5fcebb9167adb01", - "sha256:700997b77cfab016533b3e7dbc03b71d33ee4df1d79f2463a318ca0263fc29dd", - "sha256:8505e614c983834239f865da2dd336dcf9d72776b951d5dfa5ac36b987726e1b", - "sha256:962c44070c281d86398aeb8f64e1bf37816a4dfc6f4c0f114756b14fc575621d", - "sha256:9e536783a5acee79a9b308be97d3952b662748c4037b6a24cbb339dc7ed8eb89", - "sha256:9ea749fd447ce7fb1ac71f7616371f04054d969d412d37611716721931e36efd", - "sha256:a34cb28e0747ea15e82d13e14de606747e9e484fb28d63c999483f5d5188e89b", - "sha256:a3ee9c793ffefe2944d3a2bd928a0e436cd0ac2d9e3723152d6fd5398838ce7d", - "sha256:aab75d99f3f2874733946a7648ce87a50019eb90baef931698f96b76b6769a46", - "sha256:b1ed2bdb27b4c9fc87058a1cb751c4df8752002143ed393899edb82b131e0546", - "sha256:b360d8fd88d2bad01cb953d81fd2edd4be539df7bfec41e8753fe9f4456a5082", - "sha256:b8f58c7db64d8f27078cbf2a4391af6aa4e4767cc08b37555c4ae064b8558d9b", - "sha256:c1bbb628ed5192124889b51204de27c575b3ffc05a5a91307e7640eff1d48da4", - "sha256:c2ff24df02a125b7b346c4c9078c8936da06964cc2d276292c357d64378158f8", - "sha256:c890728a93fffd0407d7d37c1e6083ff3f9f211c83b4316fae3778417eab9811", - "sha256:c96472b8ca5dc135fb0aa62f79b033f02aa434fb03a8b190600a5ae4102df1fd", - "sha256:ce7866f29d3025b5b34c2e944e66ebef0d92e4a4f2463f7266daa03a1332a651", - "sha256:e26c993bd4b220429d4ec8c1468eca445a4064a61c74ca08da7429af9bc53bb0" + "sha256:0203acd33d2298e19b57451ebb0bed0ab0c602e5cf5a818591b4918b1f97d516", + "sha256:0f313707cdecd5cd3e217fc68c78a960b616604b559e9ea60cc16795c4304259", + "sha256:1c6703094c81fa55b816f5ae542c6ffc625fec769f22b053adb42ad712d086c9", + "sha256:1d44bb3a652fed01f1f2c10d5477956116e9b391320c94d36c6bf13b088a1097", + "sha256:280baa8ec489c4f542f8940f9c4c2181f0306a8ee1a54eceba071a449fb870a0", + "sha256:29a6272fec10623fcbe158fdf9abc7a5fa032048ac1d8631f14b50fbfc10d17f", + "sha256:2b31f46bf7b31e6aa690d4c7a3d51bb262438c6dcb0d528adde446531d0d3bb7", + "sha256:2d43af2be93ffbad25dd959899b5b809618a496926146ce98ee0b23683f8c51c", + "sha256:381ead10b9b9af5f64646cd27107fb27b614ee7040bb1226f9c07ba96625cbb5", + "sha256:47a11bdbd8ada9b7ee628596f9d97fbd3851bd9999d398e9436bd67376dbece7", + "sha256:4d6a42744139a7fa5b46a264874a781e8694bb32f1d76d8137b68138686f1729", + "sha256:50691e744714856f03a86df3e2bff847c2acede4c191f9a1da38f088df342978", + "sha256:530cc8aaf11cc2ac7430f3614b04645662ef20c348dce4167c22d99bec3480e9", + "sha256:582ddfbe712025448206a5bc45855d16c2e491c2dd102ee9a2841418ac1c629f", + "sha256:63808c30b41f3bbf65e29f7280bf793c79f54fb807057de7e5238ffc7cc4d7b9", + "sha256:71b69bd716698fa62cd97137d6f2fdf49f534decb23a2c6fc80813e8b7be6822", + "sha256:7858847f2d84bf6e64c7f66498e851c54de8ea06a6f96a32a1d192d846734418", + "sha256:78e93cc3571fd928a39c0b26767c986188a4118edc67bc0695bc7a284da22e82", + "sha256:7f43286f13d91a34fadf61ae252a51a130223c52bfefb50310d5b2deb062cf0f", + "sha256:86e9f8cd4b0cdd57b4ae71a9c186717daa4c5a99f3238a8723f416256e0b064d", + "sha256:8f264ba2701b8c9f815b272ad568d555ef98dfe1576802ab3149c3629a9f2221", + "sha256:9342dd70a1e151684727c9c91ea003b2fb33523bf19385d4554f7897ca0141d4", + "sha256:9361de40701666b034c59ad9e317bae95c973b9ff92513dd0eced11c6adf2e21", + "sha256:9669179786254a2e7e57f0ecf224e978471491d660aaca833f845b72a2df3709", + "sha256:aac1ba0a253e17889550ddb1b60a2063f7474155465577caa2a3b131224cfd54", + "sha256:aef72eae10b5e3116bac6957de1df4d75909fc76d1499a53fb6387434b6bcd8d", + "sha256:bd3166bb3b111e76a4f8e2980fa1addf2920a4ca9b2b8ca36a3bc3dedc618270", + "sha256:c1b78fb9700fc961f53386ad2fd86d87091e06ede5d118b8a50dea285a071c24", + "sha256:c3888a051226e676e383de03bf49eb633cd39fc829516e5334e69b8d81aae751", + "sha256:c5f17ad25d2c1286436761b462e22b5020d83316f8e8fcb5deb2b3151f8f1d3a", + "sha256:c851b35fc078389bc16b915a0a7c1d5923e12e2c5aeec58c52f4aa8085ac8237", + "sha256:cb7df71de0af56000115eafd000b867d1261f786b5eebd88a0ca6360cccfaca7", + "sha256:cedb2f9e1f990918ea061f28a0f0077a07702e3819602d3507e2ff98c8d20636", + "sha256:e8caf961e1b1a945db76f1b5fa9c91498d15f545ac0ababbe575cfab185d3bd8" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", - "version": "==5.2.1" + "version": "==5.3" }, "flake8": { "hashes": [ @@ -407,14 +464,6 @@ "index": "pypi", "version": "==17.8.0" }, - "importlib-metadata": { - "hashes": [ - "sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83", - "sha256:dc15b2969b4ce36305c51eebe62d418ac7791e9a157911d58bfb1f9ccd8e2070" - ], - "markers": "python_version < '3.8'", - "version": "==1.7.0" - }, "iniconfig": { "hashes": [ "sha256:80cf40c597eb564e86346103f609d74efce0f6b4d4f30ec8ce9e2c26411ba437", @@ -521,11 +570,11 @@ }, "pytest": { "hashes": [ - "sha256:85228d75db9f45e06e57ef9bf4429267f81ac7c0d742cc9ed63d09886a9fe6f4", - "sha256:8b6007800c53fdacd5a5c192203f4e531eb2a1540ad9c752e052ec0f7143dbad" + "sha256:0e37f61339c4578776e090c3b8f6b16ce4db333889d65d0efb305243ec544b40", + "sha256:c8f57c2a30983f469bf03e68cdfa74dc474ce56b8f280ddcb080dfd91df01043" ], "index": "pypi", - "version": "==6.0.1" + "version": "==6.0.2" }, "pytest-cov": { "hashes": [ @@ -608,16 +657,8 @@ "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c", "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f" ], - "markers": "python_version < '3.8'", + "index": "pypi", "version": "==3.7.4.3" - }, - "zipp": { - "hashes": [ - "sha256:aa36550ff0c0b7ef7fa639055d797116ee891440eac1a56f378e2d3179e0320b", - "sha256:c599e4d75c98f6798c509911d08a22e6c021d074469042177c8c86fb92eefd96" - ], - "markers": "python_version >= '3.6'", - "version": "==3.1.0" } } } diff --git a/app.json b/app.json index 96a3f11..a08f9f3 100644 --- a/app.json +++ b/app.json @@ -1,7 +1,5 @@ { "scripts": { - "dokku": { - "predeploy": "flask migrate" - } + "dokku": {} } } diff --git a/docs/devs/installation.md b/docs/devs/installation.md index c4aad25..da53cc3 100644 --- a/docs/devs/installation.md +++ b/docs/devs/installation.md @@ -42,23 +42,19 @@ Take a look at [Polar][polar] for an excellent way of spinning up a Lightning Ne Running the server ------------------ -LNbits uses [Flask][flask] as an application server. +LNbits uses [Quart][quart] as an application server. ```sh $ pipenv run python -m lnbits ``` -There is an environment variable called `FLASK_ENV` that has to be set to `development` -if you want to run Flask in debug mode with autoreload - - Frontend -------- The frontend uses [Vue.js and Quasar][quasar]. -[flask]: http://flask.pocoo.org/ +[quart]: https://pgjones.gitlab.io/ [pipenv]: https://pipenv.pypa.io/ [polar]: https://lightningpolar.com/ [quasar]: https://quasar.dev/start/how-to-use-vue diff --git a/lnbits/app.py b/lnbits/app.py index bf866b5..31edcc1 100644 --- a/lnbits/app.py +++ b/lnbits/app.py @@ -1,27 +1,28 @@ import importlib -from flask import Flask, g -from flask_assets import Bundle # type: ignore -from flask_cors import CORS # type: ignore -from flask_talisman import Talisman # type: ignore -from werkzeug.middleware.proxy_fix import ProxyFix +from quart import Quart, g +from quart_cors import cors # type: ignore +from quart_compress import Compress # type: ignore +from secure import SecureHeaders # type: ignore -from .commands import flask_migrate +from .commands import db_migrate from .core import core_app from .db import open_db -from .ext import assets, compress from .helpers import get_valid_extensions +secure_headers = SecureHeaders(hsts=False) -def create_app(config_object="lnbits.settings") -> Flask: - """Create application factory, as explained here: http://flask.pocoo.org/docs/patterns/appfactories/. + +def create_app(config_object="lnbits.settings") -> Quart: + """Create application factory. :param config_object: The configuration object to use. """ - app = Flask(__name__, static_folder="static") - app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1, x_host=1) # type: ignore + app = Quart(__name__, static_folder="static") app.config.from_object(config_object) - register_flask_extensions(app) + cors(app) + Compress(app) + register_blueprints(app) register_filters(app) register_commands(app) @@ -44,35 +45,11 @@ def register_blueprints(app) -> None: def register_commands(app): """Register Click commands.""" - app.cli.add_command(flask_migrate) - - -def register_flask_extensions(app): - """Register Flask extensions.""" - """If possible we use the .init_app() option so that Blueprints can also use extensions.""" - CORS(app) - Talisman( - app, - force_https=app.config["FORCE_HTTPS"], - content_security_policy={ - "default-src": [ - "'self'", - "'unsafe-eval'", - "'unsafe-inline'", - "blob:", - "api.opennode.co", - ] - }, - ) - - assets.init_app(app) - assets.register("base_css", Bundle("scss/base.scss", filters="pyscss", output="css/base.css")) - compress.init_app(app) + app.cli.add_command(db_migrate) def register_filters(app): """Jinja filters.""" - app.jinja_env.globals["DEBUG"] = app.config["DEBUG"] app.jinja_env.globals["EXTENSIONS"] = get_valid_extensions() app.jinja_env.globals["SITE_TITLE"] = app.config["LNBITS_SITE_TITLE"] @@ -81,9 +58,14 @@ def register_request_hooks(app): """Open the core db for each request so everything happens in a big transaction""" @app.before_request - def before_request(): + async def before_request(): g.db = open_db() + @app.after_request + async def set_secure_headers(response): + secure_headers.quart(response) + return response + @app.teardown_request - def after_request(exc): + async def after_request(exc): g.db.__exit__(type(exc), exc, None) diff --git a/lnbits/commands.py b/lnbits/commands.py index b6be6f3..60170a9 100644 --- a/lnbits/commands.py +++ b/lnbits/commands.py @@ -9,7 +9,7 @@ from .helpers import get_valid_extensions @click.command("migrate") -def flask_migrate(): +def db_migrate(): migrate_databases() diff --git a/lnbits/core/__init__.py b/lnbits/core/__init__.py index 5af72f9..e35d66d 100644 --- a/lnbits/core/__init__.py +++ b/lnbits/core/__init__.py @@ -1,7 +1,9 @@ -from flask import Blueprint +from quart import Blueprint -core_app: Blueprint = Blueprint("core", __name__, template_folder="templates", static_folder="static") +core_app: Blueprint = Blueprint( + "core", __name__, template_folder="templates", static_folder="static", static_url_path="/core/static" +) from .views.api import * # noqa diff --git a/lnbits/core/crud.py b/lnbits/core/crud.py index 35f1019..6d19c90 100644 --- a/lnbits/core/crud.py +++ b/lnbits/core/crud.py @@ -2,7 +2,7 @@ import json import datetime from uuid import uuid4 from typing import List, Optional, Dict -from flask import g +from quart import g from lnbits import bolt11 from lnbits.settings import DEFAULT_WALLET_NAME diff --git a/lnbits/core/services.py b/lnbits/core/services.py index fd42aa6..e16b2f2 100644 --- a/lnbits/core/services.py +++ b/lnbits/core/services.py @@ -1,5 +1,5 @@ from typing import Optional, Tuple, Dict -from flask import g +from quart import g try: from typing import TypedDict # type: ignore diff --git a/lnbits/core/templates/core/extensions.html b/lnbits/core/templates/core/extensions.html index 8c63c49..8f7e92b 100644 --- a/lnbits/core/templates/core/extensions.html +++ b/lnbits/core/templates/core/extensions.html @@ -1,8 +1,7 @@ {% extends "base.html" %} {% from "macros.jinja" import window_vars with context -%} {% block scripts %} {{ window_vars(user) }} {% assets filters='rjsmin', -output='__bundle__/core/extensions.js', 'core/js/extensions.js' %} - -{% endassets %} {% endblock %} {% block page %} +%} {% block scripts %} {{ window_vars(user) }} + +{% endblock %} {% block page %}
-{% endassets %} {% endblock %} {% block page %} +{% extends "public.html" %} {% block scripts %} + +{% endblock %} {% block page %}
diff --git a/lnbits/core/templates/core/wallet.html b/lnbits/core/templates/core/wallet.html index b3370bc..5c286ba 100644 --- a/lnbits/core/templates/core/wallet.html +++ b/lnbits/core/templates/core/wallet.html @@ -1,21 +1,7 @@ {% extends "base.html" %} {% from "macros.jinja" import window_vars with context -%} {% block styles %} - -{% endblock %} {% block scripts %} {{ window_vars(user, wallet) }} - -{% assets filters='rjsmin', output='__bundle__/core/chart.js', -'vendor/moment@2.27.0/moment.min.js', 'vendor/chart.js@2.9.3/chart.min.js' %} - -{% endassets %} {% assets filters='rjsmin', output='__bundle__/core/wallet.js', -'vendor/bolt11/utils.js', 'vendor/bolt11/decoder.js', -'vendor/vue-qrcode-reader@2.2.0/vue-qrcode-reader.min.js', 'core/js/wallet.js' -%} - -{% endassets %} {% endblock %} {% block page %} +%} {% block scripts %} {{ window_vars(user, wallet) }} + +{% endblock %} {% block page %}
diff --git a/lnbits/core/views/api.py b/lnbits/core/views/api.py index e4cb4fa..3ca6eff 100644 --- a/lnbits/core/views/api.py +++ b/lnbits/core/views/api.py @@ -1,4 +1,4 @@ -from flask import g, jsonify, request +from quart import g, jsonify, request from http import HTTPStatus from binascii import unhexlify @@ -12,7 +12,7 @@ from lnbits.settings import WALLET @core_app.route("/api/v1/payments", methods=["GET"]) @api_check_wallet_key("invoice") -def api_payments(): +async def api_payments(): if "check_pending" in request.args: delete_expired_invoices() @@ -33,7 +33,7 @@ def api_payments(): "description_hash": {"type": "string", "empty": False, "required": True, "excludes": "memo"}, } ) -def api_payments_create_invoice(): +async def api_payments_create_invoice(): if "description_hash" in g.data: description_hash = unhexlify(g.data["description_hash"]) memo = "" @@ -65,7 +65,7 @@ def api_payments_create_invoice(): @api_check_wallet_key("admin") @api_validate_post_request(schema={"bolt11": {"type": "string", "empty": False, "required": True}}) -def api_payments_pay_invoice(): +async def api_payments_pay_invoice(): try: payment_hash = pay_invoice(wallet_id=g.wallet.id, payment_request=g.data["bolt11"]) except ValueError as e: @@ -91,15 +91,15 @@ def api_payments_pay_invoice(): @core_app.route("/api/v1/payments", methods=["POST"]) @api_validate_post_request(schema={"out": {"type": "boolean", "required": True}}) -def api_payments_create(): +async def api_payments_create(): if g.data["out"] is True: - return api_payments_pay_invoice() - return api_payments_create_invoice() + return await api_payments_pay_invoice() + return await api_payments_create_invoice() @core_app.route("/api/v1/payments/", methods=["GET"]) @api_check_wallet_key("invoice") -def api_payment(payment_hash): +async def api_payment(payment_hash): payment = g.wallet.get_payment(payment_hash) if not payment: diff --git a/lnbits/core/views/generic.py b/lnbits/core/views/generic.py index 65b1dbf..36720d9 100644 --- a/lnbits/core/views/generic.py +++ b/lnbits/core/views/generic.py @@ -1,4 +1,4 @@ -from flask import g, abort, redirect, request, render_template, send_from_directory, url_for +from quart import g, abort, redirect, request, render_template, send_from_directory, url_for from http import HTTPStatus from os import path @@ -16,19 +16,19 @@ from ..crud import ( @core_app.route("/favicon.ico") -def favicon(): - return send_from_directory(path.join(core_app.root_path, "static"), "favicon.ico") +async def favicon(): + return await send_from_directory(path.join(core_app.root_path, "static"), "favicon.ico") @core_app.route("/") -def home(): - return render_template("core/index.html", lnurl=request.args.get("lightning", None)) +async def home(): + return await render_template("core/index.html", lnurl=request.args.get("lightning", None)) @core_app.route("/extensions") @validate_uuids(["usr"], required=True) @check_user_exists() -def extensions(): +async def extensions(): extension_to_enable = request.args.get("enable", type=str) extension_to_disable = request.args.get("disable", type=str) @@ -40,12 +40,12 @@ def extensions(): elif extension_to_disable: update_user_extension(user_id=g.user.id, extension=extension_to_disable, active=0) - return render_template("core/extensions.html", user=get_user(g.user.id)) + return await render_template("core/extensions.html", user=get_user(g.user.id)) @core_app.route("/wallet") @validate_uuids(["usr", "wal"]) -def wallet(): +async def wallet(): user_id = request.args.get("usr", type=str) wallet_id = request.args.get("wal", type=str) wallet_name = request.args.get("nme", type=str) @@ -76,13 +76,15 @@ def wallet(): if wallet_id not in user.wallet_ids: abort(HTTPStatus.FORBIDDEN, "Not your wallet.") - return render_template("core/wallet.html", user=user, wallet=user.get_wallet(wallet_id), service_fee=service_fee) + return await render_template( + "core/wallet.html", user=user, wallet=user.get_wallet(wallet_id), service_fee=service_fee + ) @core_app.route("/deletewallet") @validate_uuids(["usr", "wal"], required=True) @check_user_exists() -def deletewallet(): +async def deletewallet(): wallet_id = request.args.get("wal", type=str) user_wallet_ids = g.user.wallet_ids diff --git a/lnbits/core/views/lnurl.py b/lnbits/core/views/lnurl.py index 97cbe2c..3ec0fc0 100644 --- a/lnbits/core/views/lnurl.py +++ b/lnbits/core/views/lnurl.py @@ -1,6 +1,6 @@ import requests -from flask import abort, redirect, request, url_for +from quart import abort, redirect, request, url_for from http import HTTPStatus from lnurl import LnurlWithdrawResponse, handle as handle_lnurl # type: ignore from lnurl.exceptions import LnurlException # type: ignore @@ -13,7 +13,7 @@ from ..crud import create_account, get_user, create_wallet, create_payment @core_app.route("/lnurlwallet") -def lnurlwallet(): +async def lnurlwallet(): memo = "LNbits LNURL funding" try: diff --git a/lnbits/decorators.py b/lnbits/decorators.py index 8f09089..ac73e4e 100644 --- a/lnbits/decorators.py +++ b/lnbits/decorators.py @@ -1,5 +1,5 @@ from cerberus import Validator # type: ignore -from flask import g, abort, jsonify, request +from quart import g, abort, jsonify, request from functools import wraps from http import HTTPStatus from typing import List, Union @@ -12,7 +12,7 @@ from lnbits.settings import LNBITS_ALLOWED_USERS def api_check_wallet_key(key_type: str = "invoice"): def wrap(view): @wraps(view) - def wrapped_view(**kwargs): + async def wrapped_view(**kwargs): try: g.wallet = get_wallet_for_key(request.headers["X-Api-Key"], key_type) except KeyError: @@ -24,7 +24,7 @@ def api_check_wallet_key(key_type: str = "invoice"): if not g.wallet: return jsonify({"message": "Wrong keys."}), HTTPStatus.UNAUTHORIZED - return view(**kwargs) + return await view(**kwargs) return wrapped_view @@ -34,7 +34,7 @@ def api_check_wallet_key(key_type: str = "invoice"): def api_validate_post_request(*, schema: dict): def wrap(view): @wraps(view) - def wrapped_view(**kwargs): + async def wrapped_view(**kwargs): if "application/json" not in request.headers["Content-Type"]: return ( jsonify({"message": "Content-Type must be `application/json`."}), @@ -42,7 +42,8 @@ def api_validate_post_request(*, schema: dict): ) v = Validator(schema) - g.data = {key: request.json[key] for key in schema.keys() if key in request.json} + data = await request.get_json() + g.data = {key: data[key] for key in schema.keys() if key in data} if not v.validate(g.data): return ( @@ -50,7 +51,7 @@ def api_validate_post_request(*, schema: dict): HTTPStatus.BAD_REQUEST, ) - return view(**kwargs) + return await view(**kwargs) return wrapped_view @@ -60,13 +61,13 @@ def api_validate_post_request(*, schema: dict): def check_user_exists(param: str = "usr"): def wrap(view): @wraps(view) - def wrapped_view(**kwargs): + async def wrapped_view(**kwargs): g.user = get_user(request.args.get(param, type=str)) or abort(HTTPStatus.NOT_FOUND, "User does not exist.") if LNBITS_ALLOWED_USERS and g.user.id not in LNBITS_ALLOWED_USERS: abort(HTTPStatus.UNAUTHORIZED, "User not authorized.") - return view(**kwargs) + return await view(**kwargs) return wrapped_view @@ -76,7 +77,7 @@ def check_user_exists(param: str = "usr"): def validate_uuids(params: List[str], *, required: Union[bool, List[str]] = False, version: int = 4): def wrap(view): @wraps(view) - def wrapped_view(**kwargs): + async def wrapped_view(**kwargs): query_params = {param: request.args.get(param, type=str) for param in params} for param, value in query_params.items(): @@ -89,7 +90,7 @@ def validate_uuids(params: List[str], *, required: Union[bool, List[str]] = Fals except ValueError: abort(HTTPStatus.BAD_REQUEST, f"`{param}` is not a valid UUID.") - return view(**kwargs) + return await view(**kwargs) return wrapped_view diff --git a/lnbits/ext.py b/lnbits/ext.py deleted file mode 100644 index 74e384b..0000000 --- a/lnbits/ext.py +++ /dev/null @@ -1,6 +0,0 @@ -from flask_assets import Environment # type: ignore -from flask_compress import Compress # type: ignore - - -assets = Environment() -compress = Compress() diff --git a/lnbits/extensions/amilk/__init__.py b/lnbits/extensions/amilk/__init__.py index ea93c98..182f023 100644 --- a/lnbits/extensions/amilk/__init__.py +++ b/lnbits/extensions/amilk/__init__.py @@ -1,4 +1,4 @@ -from flask import Blueprint +from quart import Blueprint amilk_ext: Blueprint = Blueprint("amilk", __name__, static_folder="static", template_folder="templates") diff --git a/lnbits/extensions/amilk/views.py b/lnbits/extensions/amilk/views.py index 11c86f0..fa214e3 100644 --- a/lnbits/extensions/amilk/views.py +++ b/lnbits/extensions/amilk/views.py @@ -1,4 +1,4 @@ -from flask import g, abort, render_template +from quart import g, abort, render_template from http import HTTPStatus from lnbits.decorators import check_user_exists, validate_uuids @@ -10,12 +10,11 @@ from .crud import get_amilk @amilk_ext.route("/") @validate_uuids(["usr"], required=True) @check_user_exists() -def index(): - return render_template("amilk/index.html", user=g.user) +async def index(): + return await render_template("amilk/index.html", user=g.user) @amilk_ext.route("/") -def wall(amilk_id): +async def wall(amilk_id): amilk = get_amilk(amilk_id) or abort(HTTPStatus.NOT_FOUND, "AMilk does not exist.") - - return render_template("amilk/wall.html", amilk=amilk) + return await render_template("amilk/wall.html", amilk=amilk) diff --git a/lnbits/extensions/amilk/views_api.py b/lnbits/extensions/amilk/views_api.py index 816ca99..c61a4fc 100644 --- a/lnbits/extensions/amilk/views_api.py +++ b/lnbits/extensions/amilk/views_api.py @@ -1,5 +1,5 @@ import requests -from flask import g, jsonify, request, abort +from quart import g, jsonify, request, abort from http import HTTPStatus from lnurl import LnurlWithdrawResponse, handle as handle_lnurl from lnurl.exceptions import LnurlException @@ -15,7 +15,7 @@ from .crud import create_amilk, get_amilk, get_amilks, delete_amilk @amilk_ext.route("/api/v1/amilk", methods=["GET"]) @api_check_wallet_key("invoice") -def api_amilks(): +async def api_amilks(): wallet_ids = [g.wallet.id] if "all_wallets" in request.args: @@ -25,7 +25,7 @@ def api_amilks(): @amilk_ext.route("/api/v1/amilk/milk/", methods=["GET"]) -def api_amilkit(amilk_id): +async def api_amilkit(amilk_id): milk = get_amilk(amilk_id) memo = milk.id @@ -66,7 +66,7 @@ def api_amilkit(amilk_id): "amount": {"type": "integer", "min": 0, "required": True}, } ) -def api_amilk_create(): +async def api_amilk_create(): amilk = create_amilk(wallet_id=g.wallet.id, lnurl=g.data["lnurl"], atime=g.data["atime"], amount=g.data["amount"]) return jsonify(amilk._asdict()), HTTPStatus.CREATED @@ -74,7 +74,7 @@ def api_amilk_create(): @amilk_ext.route("/api/v1/amilk/", methods=["DELETE"]) @api_check_wallet_key("invoice") -def api_amilk_delete(amilk_id): +async def api_amilk_delete(amilk_id): amilk = get_amilk(amilk_id) if not amilk: diff --git a/lnbits/extensions/diagonalley/__init__.py b/lnbits/extensions/diagonalley/__init__.py index c3eaf52..41afebb 100644 --- a/lnbits/extensions/diagonalley/__init__.py +++ b/lnbits/extensions/diagonalley/__init__.py @@ -1,4 +1,4 @@ -from flask import Blueprint +from quart import Blueprint diagonalley_ext: Blueprint = Blueprint("diagonalley", __name__, static_folder="static", template_folder="templates") diff --git a/lnbits/extensions/diagonalley/views.py b/lnbits/extensions/diagonalley/views.py index 41a19f5..6781a99 100644 --- a/lnbits/extensions/diagonalley/views.py +++ b/lnbits/extensions/diagonalley/views.py @@ -1,15 +1,11 @@ -import json - -from flask import g, abort, render_template, jsonify +from quart import g, render_template from lnbits.decorators import check_user_exists, validate_uuids from lnbits.extensions.diagonalley import diagonalley_ext -from lnbits.db import open_ext_db @diagonalley_ext.route("/") @validate_uuids(["usr"], required=True) @check_user_exists() -def index(): - - return render_template("diagonalley/index.html", user=g.user) +async def index(): + return await render_template("diagonalley/index.html", user=g.user) diff --git a/lnbits/extensions/diagonalley/views_api.py b/lnbits/extensions/diagonalley/views_api.py index fbdc2a7..9ded7c2 100644 --- a/lnbits/extensions/diagonalley/views_api.py +++ b/lnbits/extensions/diagonalley/views_api.py @@ -1,4 +1,4 @@ -from flask import g, jsonify, request +from quart import g, jsonify, request from http import HTTPStatus from lnbits.core.crud import get_user @@ -18,19 +18,19 @@ from .crud import ( create_diagonalleys_order, get_diagonalleys_order, get_diagonalleys_orders, - delete_diagonalleys_order, + update_diagonalleys_product, ) from lnbits.core.services import create_invoice from base64 import urlsafe_b64encode from uuid import uuid4 from lnbits.db import open_ext_db -###Products +### Products @diagonalley_ext.route("/api/v1/diagonalley/products", methods=["GET"]) @api_check_wallet_key(key_type="invoice") -def api_diagonalley_products(): +async def api_diagonalley_products(): wallet_ids = [g.wallet.id] if "all_wallets" in request.args: @@ -52,7 +52,7 @@ def api_diagonalley_products(): "quantity": {"type": "integer", "min": 0, "required": True}, } ) -def api_diagonalley_product_create(product_id=None): +async def api_diagonalley_product_create(product_id=None): if product_id: product = get_diagonalleys_indexer(product_id) @@ -72,7 +72,7 @@ def api_diagonalley_product_create(product_id=None): @diagonalley_ext.route("/api/v1/diagonalley/products/", methods=["DELETE"]) @api_check_wallet_key(key_type="invoice") -def api_diagonalley_products_delete(product_id): +async def api_diagonalley_products_delete(product_id): product = get_diagonalleys_product(product_id) if not product: @@ -91,7 +91,7 @@ def api_diagonalley_products_delete(product_id): @diagonalley_ext.route("/api/v1/diagonalley/indexers", methods=["GET"]) @api_check_wallet_key(key_type="invoice") -def api_diagonalley_indexers(): +async def api_diagonalley_indexers(): wallet_ids = [g.wallet.id] if "all_wallets" in request.args: @@ -114,7 +114,7 @@ def api_diagonalley_indexers(): "zone2cost": {"type": "integer", "min": 0, "required": True}, } ) -def api_diagonalley_indexer_create(indexer_id=None): +async def api_diagonalley_indexer_create(indexer_id=None): if indexer_id: indexer = get_diagonalleys_indexer(indexer_id) @@ -134,7 +134,7 @@ def api_diagonalley_indexer_create(indexer_id=None): @diagonalley_ext.route("/api/v1/diagonalley/indexers/", methods=["DELETE"]) @api_check_wallet_key(key_type="invoice") -def api_diagonalley_indexer_delete(indexer_id): +async def api_diagonalley_indexer_delete(indexer_id): indexer = get_diagonalleys_indexer(indexer_id) if not indexer: @@ -153,7 +153,7 @@ def api_diagonalley_indexer_delete(indexer_id): @diagonalley_ext.route("/api/v1/diagonalley/orders", methods=["GET"]) @api_check_wallet_key(key_type="invoice") -def api_diagonalley_orders(): +async def api_diagonalley_orders(): wallet_ids = [g.wallet.id] if "all_wallets" in request.args: @@ -173,14 +173,14 @@ def api_diagonalley_orders(): "shippingzone": {"type": "integer", "empty": False, "required": True}, } ) -def api_diagonalley_order_create(): +async def api_diagonalley_order_create(): order = create_diagonalleys_order(wallet_id=g.wallet.id, **g.data) return jsonify(order._asdict()), HTTPStatus.CREATED @diagonalley_ext.route("/api/v1/diagonalley/orders/", methods=["DELETE"]) @api_check_wallet_key(key_type="invoice") -def api_diagonalley_order_delete(order_id): +async def api_diagonalley_order_delete(order_id): order = get_diagonalleys_order(order_id) if not order: @@ -196,7 +196,7 @@ def api_diagonalley_order_delete(order_id): @diagonalley_ext.route("/api/v1/diagonalley/orders/paid/", methods=["GET"]) @api_check_wallet_key(key_type="invoice") -def api_diagonalleys_order_paid(order_id): +async def api_diagonalleys_order_paid(order_id): with open_ext_db("diagonalley") as db: db.execute( "UPDATE orders SET paid = ? WHERE id = ?", @@ -210,7 +210,7 @@ def api_diagonalleys_order_paid(order_id): @diagonalley_ext.route("/api/v1/diagonalley/orders/shipped/", methods=["GET"]) @api_check_wallet_key(key_type="invoice") -def api_diagonalleys_order_shipped(order_id): +async def api_diagonalleys_order_shipped(order_id): with open_ext_db("diagonalley") as db: db.execute( "UPDATE orders SET shipped = ? WHERE id = ?", @@ -228,7 +228,7 @@ def api_diagonalleys_order_shipped(order_id): @diagonalley_ext.route("/api/v1/diagonalley/stall/products/", methods=["GET"]) -def api_diagonalleys_stall_products(indexer_id): +async def api_diagonalleys_stall_products(indexer_id): with open_ext_db("diagonalley") as db: rows = db.fetchone("SELECT * FROM indexers WHERE id = ?", (indexer_id,)) print(rows[1]) @@ -246,7 +246,7 @@ def api_diagonalleys_stall_products(indexer_id): @diagonalley_ext.route("/api/v1/diagonalley/stall/checkshipped/", methods=["GET"]) -def api_diagonalleys_stall_checkshipped(checking_id): +async def api_diagonalleys_stall_checkshipped(checking_id): with open_ext_db("diagonalley") as db: rows = db.fetchone("SELECT * FROM orders WHERE invoiceid = ?", (checking_id,)) @@ -266,7 +266,7 @@ def api_diagonalleys_stall_checkshipped(checking_id): "shippingzone": {"type": "integer", "empty": False, "required": True}, } ) -def api_diagonalley_stall_order(indexer_id): +async def api_diagonalley_stall_order(indexer_id): product = get_diagonalleys_product(g.data["id"]) shipping = get_diagonalleys_indexer(indexer_id) diff --git a/lnbits/extensions/events/__init__.py b/lnbits/extensions/events/__init__.py index 52d499e..abd4895 100644 --- a/lnbits/extensions/events/__init__.py +++ b/lnbits/extensions/events/__init__.py @@ -1,4 +1,4 @@ -from flask import Blueprint +from quart import Blueprint events_ext: Blueprint = Blueprint("events", __name__, static_folder="static", template_folder="templates") diff --git a/lnbits/extensions/events/templates/events/display.html b/lnbits/extensions/events/templates/events/display.html index 542feb9..927c68f 100644 --- a/lnbits/extensions/events/templates/events/display.html +++ b/lnbits/extensions/events/templates/events/display.html @@ -82,7 +82,6 @@
{% endblock %} {% block scripts %} - -{% assets filters='rjsmin', output='__bundle__/core/chart.js', -'vendor/moment@2.27.0/moment.min.js', 'vendor/chart.js@2.9.3/chart.min.js' %} - -{% endassets %} {% assets filters='rjsmin', output='__bundle__/core/wallet.js', -'vendor/bolt11/utils.js', 'vendor/bolt11/decoder.js', -'vendor/vue-qrcode-reader@2.2.0/vue-qrcode-reader.min.js' %} - -{% endassets %} - {% endblock %} diff --git a/lnbits/extensions/lndhub/views.py b/lnbits/extensions/lndhub/views.py index 81e4c69..e9478ff 100644 --- a/lnbits/extensions/lndhub/views.py +++ b/lnbits/extensions/lndhub/views.py @@ -1,4 +1,4 @@ -from flask import render_template, g +from quart import render_template, g from lnbits.decorators import check_user_exists, validate_uuids from lnbits.extensions.lndhub import lndhub_ext @@ -7,5 +7,5 @@ from lnbits.extensions.lndhub import lndhub_ext @lndhub_ext.route("/") @validate_uuids(["usr"], required=True) @check_user_exists() -def lndhub_index(): - return render_template("lndhub/index.html", user=g.user) +async def lndhub_index(): + return await render_template("lndhub/index.html", user=g.user) diff --git a/lnbits/extensions/lndhub/views_api.py b/lnbits/extensions/lndhub/views_api.py index 92fc6e5..c413c46 100644 --- a/lnbits/extensions/lndhub/views_api.py +++ b/lnbits/extensions/lndhub/views_api.py @@ -1,6 +1,6 @@ import time from base64 import urlsafe_b64encode -from flask import jsonify, g, request +from quart import jsonify, g, request from lnbits.core.services import pay_invoice, create_invoice from lnbits.core.crud import delete_expired_invoices @@ -14,7 +14,7 @@ from .utils import to_buffer, decoded_as_lndhub @lndhub_ext.route("/ext/getinfo", methods=["GET"]) -def lndhub_getinfo(): +async def lndhub_getinfo(): return jsonify({"error": True, "code": 1, "message": "bad auth"}) @@ -26,7 +26,7 @@ def lndhub_getinfo(): "refresh_token": {"type": "string", "required": True, "excludes": ["login", "password"]}, } ) -def lndhub_auth(): +async def lndhub_auth(): token = ( g.data["token"] if "token" in g.data and g.data["token"] @@ -44,7 +44,7 @@ def lndhub_auth(): "preimage": {"type": "string", "required": False}, } ) -def lndhub_addinvoice(): +async def lndhub_addinvoice(): try: _, pr = create_invoice( wallet_id=g.wallet.id, @@ -76,7 +76,7 @@ def lndhub_addinvoice(): @lndhub_ext.route("/ext/payinvoice", methods=["POST"]) @check_wallet(requires_admin=True) @api_validate_post_request(schema={"invoice": {"type": "string", "required": True}}) -def lndhub_payinvoice(): +async def lndhub_payinvoice(): try: pay_invoice( wallet_id=g.wallet.id, @@ -112,13 +112,13 @@ def lndhub_payinvoice(): @lndhub_ext.route("/ext/balance", methods=["GET"]) @check_wallet() -def lndhub_balance(): +async def lndhub_balance(): return jsonify({"BTC": {"AvailableBalance": g.wallet.balance}}) @lndhub_ext.route("/ext/gettxs", methods=["GET"]) @check_wallet() -def lndhub_gettxs(): +async def lndhub_gettxs(): for payment in g.wallet.get_payments( complete=False, pending=True, outgoing=True, incoming=False, exclude_uncheckable=True ): @@ -146,7 +146,7 @@ def lndhub_gettxs(): @lndhub_ext.route("/ext/getuserinvoices", methods=["GET"]) @check_wallet() -def lndhub_getuserinvoices(): +async def lndhub_getuserinvoices(): delete_expired_invoices() for invoice in g.wallet.get_payments( complete=False, pending=True, outgoing=False, incoming=True, exclude_uncheckable=True @@ -177,26 +177,26 @@ def lndhub_getuserinvoices(): @lndhub_ext.route("/ext/getbtc", methods=["GET"]) @check_wallet() -def lndhub_getbtc(): +async def lndhub_getbtc(): "load an address for incoming onchain btc" return jsonify([]) @lndhub_ext.route("/ext/getpending", methods=["GET"]) @check_wallet() -def lndhub_getpending(): +async def lndhub_getpending(): "pending onchain transactions" return jsonify([]) @lndhub_ext.route("/ext/decodeinvoice", methods=["GET"]) -def lndhub_decodeinvoice(): +async def lndhub_decodeinvoice(): invoice = request.args.get("invoice") inv = bolt11.decode(invoice) return jsonify(decoded_as_lndhub(inv)) @lndhub_ext.route("/ext/checkrouteinvoice", methods=["GET"]) -def lndhub_checkrouteinvoice(): +async def lndhub_checkrouteinvoice(): "not implemented on canonical lndhub" pass diff --git a/lnbits/extensions/lnticket/__init__.py b/lnbits/extensions/lnticket/__init__.py index 08ca29c..7a91b6b 100644 --- a/lnbits/extensions/lnticket/__init__.py +++ b/lnbits/extensions/lnticket/__init__.py @@ -1,4 +1,4 @@ -from flask import Blueprint +from quart import Blueprint lnticket_ext: Blueprint = Blueprint("lnticket", __name__, static_folder="static", template_folder="templates") diff --git a/lnbits/extensions/lnticket/templates/lnticket/display.html b/lnbits/extensions/lnticket/templates/lnticket/display.html index 4ab829e..59553ab 100644 --- a/lnbits/extensions/lnticket/templates/lnticket/display.html +++ b/lnbits/extensions/lnticket/templates/lnticket/display.html @@ -76,7 +76,6 @@
{% endblock %} {% block scripts %} - -{% assets filters='rjsmin', output='__bundle__/withdraw/index.js', -'withdraw/js/index.js' %} - -{% endassets %} {% endblock %} {% block page %} + +{% endblock %} {% block page %}
@@ -273,7 +270,7 @@ color="deep-purple" :disable=" simpleformDialog.data.wallet == null || - + simpleformDialog.data.max_withdrawable == null || simpleformDialog.data.max_withdrawable < 1 || simpleformDialog.data.uses == null" diff --git a/lnbits/extensions/withdraw/templates/withdraw/print_qr.html b/lnbits/extensions/withdraw/templates/withdraw/print_qr.html index 06744c3..3a47c6b 100644 --- a/lnbits/extensions/withdraw/templates/withdraw/print_qr.html +++ b/lnbits/extensions/withdraw/templates/withdraw/print_qr.html @@ -1,5 +1,4 @@ - -{% block page %} +{% extends "print.html" %} {% block page %}
@@ -50,15 +49,6 @@ } {% endblock %} {% block scripts %} - - - - - - - - - - {% else %} {% assets output='__bundle__/vue.js', - 'vendor/quasar@1.13.2/quasar.ie.polyfills.umd.min.js', - 'vendor/vue@2.6.12/vue.min.js', 'vendor/vue-router@3.4.3/vue-router.min.js', - 'vendor/vuex@3.5.1/vuex.min.js', 'vendor/quasar@1.13.2/quasar.umd.min.js' %} - - {% endassets %} {% endif %} {% assets filters='rjsmin', - output='__bundle__/base.js', 'vendor/axios@0.20.0/axios.min.js', - 'vendor/underscore@1.10.2/underscore.min.js', 'js/base.js', - 'js/components.js' %} - - {% endassets %} {% block scripts %}{% endblock %} + {% block vue_templates %}{% endblock %} + + + + + + + + + + + + + + + {% block scripts %}{% endblock %} diff --git a/lnbits/templates/print.html b/lnbits/templates/print.html index 803e7cf..0af98d9 100644 --- a/lnbits/templates/print.html +++ b/lnbits/templates/print.html @@ -38,13 +38,12 @@ - {% if DEBUG %} - - - {% else %} {% assets output='__bundle__/vue-print.js', - 'vendor/quasar@1.13.2/quasar.ie.polyfills.umd.min.js', - 'vendor/vue@2.6.12/vue.min.js', 'vendor/quasar@1.13.2/quasar.umd.min.js' %} - - {% endassets %} {% endif %} {% block scripts %}{% endblock %} + + + + + + + {% block scripts %}{% endblock %} diff --git a/requirements.txt b/requirements.txt index 52ea1e0..d69fad1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,30 +1,38 @@ -bech32==1.2.0; python_version >= '3.5' +aiofiles==0.5.0 +bech32==1.2.0 bitstring==3.1.7 +blinker==1.4 brotli==1.0.9 cerberus==1.3.2 certifi==2020.6.20 chardet==3.0.4 -click==7.1.2; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' +click==7.1.2 ecdsa==0.16.0 environs==8.0.0 -flask-assets==2.0 -flask-compress==1.5.0 -flask-cors==3.0.9 -flask-talisman==0.7.0 -flask==1.1.2 -idna==2.10; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -itsdangerous==1.1.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -jinja2==2.11.2; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' +h11==0.10.0 +h2==3.2.0 +hpack==3.0.0 +hypercorn==0.10.2 +hyperframe==5.2.0 +idna==2.10 +itsdangerous==1.1.0 +jinja2==2.11.2 lnurl==0.3.5 -markupsafe==1.1.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -marshmallow==3.7.1; python_version >= '3.5' -pydantic==1.6.1; python_version >= '3.6' +markupsafe==1.1.1 +marshmallow==3.7.1 +priority==1.3.0 +pydantic==1.6.1 pyscss==1.3.7 python-dotenv==0.14.0 +quart==0.13.1 +quart-compress==0.2.1 +quart-cors==0.3.0 requests==2.24.0 +secure==0.2.1 shortuuid==1.0.1 -six==1.15.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -typing-extensions==3.7.4.3; python_version < '3.8' -urllib3==1.25.10; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4' -webassets==2.0 -werkzeug==1.0.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' +six==1.15.0 +toml==0.10.1 +typing-extensions==3.7.4.3 +urllib3==1.25.10 +werkzeug==1.0.1 +wsproto==0.15.0