From a57980469b77047f3b4947da0f9fcb6a2585c0ec Mon Sep 17 00:00:00 2001 From: Daniel Krahofer Date: Mon, 11 Jul 2022 13:40:22 +0200 Subject: [PATCH 01/33] addition to dockerignore (#722) * add venv, data, tests to dockerignore * add config files to ignore Co-authored-by: dni --- .dockerignore | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/.dockerignore b/.dockerignore index ebac296af..c8872f9ed 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,21 @@ .git -docs +data docker +docs +tests +venv -# ignore all the markdown *.md +*.log + +.env + +.gitignore +.prettierrc +conv.py +LICENSE +Makefile +mypy.ini +package-lock.json +package.json +pytest.ini From 46462b4f012acba83f361584cd7be8e324d8060c Mon Sep 17 00:00:00 2001 From: Bitkarrot <73979971+bitkarrot@users.noreply.github.com> Date: Mon, 11 Jul 2022 04:40:46 -0700 Subject: [PATCH 02/33] Update extensions.md (#724) suggestion for gsed on macOS, as sed may not work reference: https://apple.stackexchange.com/questions/414568/i-get-an-error-sed-1-12d-invalid-command-code-when-i-use-sed-12d-samp --- docs/devs/extensions.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/devs/extensions.md b/docs/devs/extensions.md index 70e599e9d..8c9a30a40 100644 --- a/docs/devs/extensions.md +++ b/docs/devs/extensions.md @@ -15,6 +15,7 @@ cp lnbits/extensions/example lnbits/extensions/mysuperplugin -r # Let's not use cd lnbits/extensions/mysuperplugin find . -type f -print0 | xargs -0 sed -i 's/example/mysuperplugin/g' # Change all occurrences of 'example' to your plugin name 'mysuperplugin'. ``` +- if you are on macOS and having difficulty with 'sed', consider `brew install gnu-sed` and use 'gsed', without -0 option after xargs. Going over the example extension's structure: * views_api.py: This is where your public API would go. It will be exposed at "$DOMAIN/$PLUGIN/$ROUTE". For example: https://lnbits.com/mysuperplugin/api/v1/tools. From 41dda6fd01d0c7d6a3ad20bcf2b9bbb33744b2c7 Mon Sep 17 00:00:00 2001 From: Arc <33088785+arcbtc@users.noreply.github.com> Date: Mon, 11 Jul 2022 16:18:28 +0100 Subject: [PATCH 03/33] Revert "Fixed psycopg2 error on aarch64" (#729) * Revert "Fixed psycopg2 error on aarch64 (#658)" This reverts commit 8a20b779dfeeba3b3258029542b62cbc29747bca. * remove psycopg from build pipeline Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com> --- .github/workflows/tests.yml | 4 ---- requirements.txt | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2683b45e0..167ec8fd7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -14,8 +14,6 @@ jobs: uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - - name: psycopg2 prerequisites - run: sudo apt-get install python-dev libpq-dev - name: Install dependencies env: VIRTUAL_ENV: ./venv @@ -53,8 +51,6 @@ jobs: uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - - name: psycopg2 prerequisites - run: sudo apt-get install python-dev libpq-dev - name: Install dependencies env: VIRTUAL_ENV: ./venv diff --git a/requirements.txt b/requirements.txt index a31e80708..8359456ff 100644 --- a/requirements.txt +++ b/requirements.txt @@ -25,7 +25,7 @@ loguru==0.6.0 markupsafe==2.0.1 marshmallow==3.13.0 outcome==1.1.0 -psycopg2==2.9.3 +psycopg2-binary==2.9.1 pycryptodomex==3.14.1 pydantic==1.8.2 pypng==0.0.21 From 357860d84935fcc00e144addd16d94e87f8c221d Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Tue, 12 Jul 2022 13:22:55 +0200 Subject: [PATCH 04/33] Spark: increase timeout and improved error handling (#718) * increase timeout and more error handling * more error handling * add timeout exception --- lnbits/wallets/spark.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/lnbits/wallets/spark.py b/lnbits/wallets/spark.py index 49892a821..d12addc4c 100644 --- a/lnbits/wallets/spark.py +++ b/lnbits/wallets/spark.py @@ -48,9 +48,16 @@ class SparkWallet(Wallet): self.url + "/rpc", headers={"X-Access": self.token}, json={"method": key, "params": params}, - timeout=40, + timeout=60 * 60 * 24, ) - except (OSError, httpx.ConnectError, httpx.RequestError) as exc: + r.raise_for_status() + except ( + OSError, + httpx.ConnectError, + httpx.RequestError, + httpx.HTTPError, + httpx.TimeoutException, + ) as exc: raise UnknownError("error connecting to spark: " + str(exc)) try: @@ -203,7 +210,13 @@ class SparkWallet(Wallet): data = json.loads(line[5:]) if "pay_index" in data and data.get("status") == "paid": yield data["label"] - except (OSError, httpx.ReadError, httpx.ConnectError, httpx.ReadTimeout): + except ( + OSError, + httpx.ReadError, + httpx.ConnectError, + httpx.ReadTimeout, + httpx.HTTPError, + ): pass logger.error("lost connection to spark /stream, retrying in 5 seconds") From 1f13bdeb2f935821753ed880d85f7383fef229be Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Wed, 13 Jul 2022 01:15:48 +0200 Subject: [PATCH 05/33] Pipenv/fix install loguru (#732) * update pipfile * pipenv workflow * pipfile jinja * Pipfile installs dev files * python3.8 tests only * version tag yaml * all tests * pipenv with pip * only 3.7 * activate env * test-pipenv * pipenv importlib_metadata * importlib-metadata * 3.8 * 3.7 only oops * merge install guides * install guide in README --- .github/workflows/tests.yml | 51 +- Makefile | 8 + Pipfile | 7 +- Pipfile.lock | 1121 ++++++++++++++++++----------------- README.md | 4 +- docs/devs/installation.md | 44 +- docs/guide/installation.md | 112 +++- 7 files changed, 713 insertions(+), 634 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 167ec8fd7..7b0b38e2e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -44,7 +44,7 @@ jobs: --health-retries 5 strategy: matrix: - python-version: [3.7, 3.8] + python-version: [3.7] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} @@ -68,34 +68,21 @@ jobs: uses: codecov/codecov-action@v3 with: file: ./coverage.xml - # build: - # runs-on: ubuntu-latest - # strategy: - # matrix: - # python-version: [3.7, 3.8] - # steps: - # - uses: actions/checkout@v2 - # - name: Set up Python ${{ matrix.python-version }} - # uses: actions/setup-python@v1 - # with: - # python-version: ${{ matrix.python-version }} - # - name: Install dependencies - # run: | - # python -m pip install --upgrade pip - # pip install -r requirements.txt - # - name: Test with pytest - # env: - # LNBITS_BACKEND_WALLET_CLASS: LNPayWallet - # LNBITS_FORCE_HTTPS: 0 - # LNPAY_API_ENDPOINT: https://api.lnpay.co/v1/ - # LNPAY_API_KEY: sak_gG5pSFZhFgOLHm26a8hcWvXKt98yd - # LNPAY_ADMIN_KEY: waka_HqWfOoNE0TPqmQHSYErbF4n9 - # LNPAY_INVOICE_KEY: waki_ZqFEbhrTyopuPlOZButZUw - # LNPAY_READ_KEY: wakr_6IyTaNrvSeu3jbojSWt4ou6h - # run: | - # pip install pytest pytest-cov - # pytest --cov=lnbits --cov-report=xml - # - name: Upload coverage to Codecov - # uses: codecov/codecov-action@v1 - # with: - # file: ./coverage.xml + pipenv: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.7] + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + pip install pipenv + pipenv install --dev + pipenv install importlib-metadata + - name: Run tests + run: make test-pipenv \ No newline at end of file diff --git a/Makefile b/Makefile index 0ace3da03..37c61b66f 100644 --- a/Makefile +++ b/Makefile @@ -37,5 +37,13 @@ test: PYTHONUNBUFFERED=1 \ ./venv/bin/pytest --durations=1 -s --cov=lnbits --cov-report=xml +test-pipenv: + rm -rf ./tests/data + mkdir -p ./tests/data + FAKE_WALLET_SECRET="ToTheMoon1" \ + LNBITS_DATA_FOLDER="./tests/data" \ + PYTHONUNBUFFERED=1 \ + pipenv run pytest --durations=1 -s --cov=lnbits --cov-report=xml + bak: # LNBITS_DATABASE_URL=postgres://postgres:postgres@0.0.0.0:5432/postgres diff --git a/Pipfile b/Pipfile index 7d6769842..8ef241f12 100644 --- a/Pipfile +++ b/Pipfile @@ -28,7 +28,7 @@ asyncio = "*" fastapi = "*" uvicorn = {extras = ["standard"], version = "*"} sse-starlette = "*" -jinja2 = "3.0.1" +jinja2 = "==3.0.1" pyngrok = "*" secp256k1 = "*" pycryptodomex = "*" @@ -37,4 +37,7 @@ pycryptodomex = "*" black = "==20.8b1" pytest = "*" pytest-cov = "*" -mypy = "latest" +mypy = "*" +pytest-asyncio = "*" +requests = "*" +mock = "*" diff --git a/Pipfile.lock b/Pipfile.lock index e77de500d..6a89abb32 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "3e19364434fd2db3748162ccc1f3b6bddcf7a382473069d15cee6eda5e07eef1" + "sha256": "81bd288eea338c3bf1b70b8d30c1185b84c13a25a595bcddd77f74f7bc090032" }, "pipfile-spec": 6, "requires": { @@ -26,19 +26,10 @@ }, "anyio": { "hashes": [ - "sha256:a0aeffe2fb1fdf374a8e4b471444f0f3ac4fb9f5a5b542b48824475e0042a5a6", - "sha256:b5fa16c5ff93fa1046f2eeb5bbff2dad4d3514d6cda61d02816dba34fa8c3c2e" + "sha256:413adf95f93886e442aea925f3ee43baa5a765a64a0f52c6081894f9992fdd0b", + "sha256:cb29b9c70620506a9a8f87a309591713446953302d7d995344d0d7c6c0c9a7be" ], - "markers": "python_full_version >= '3.6.2'", - "version": "==3.5.0" - }, - "asgiref": { - "hashes": [ - "sha256:2f8abc20f7248433085eda803936d98992f1343ddb022065779f37c5da0181d0", - "sha256:88d59c13d634dcffe0510be048210188edd79aeccb6a6c9028cdad6f31d730a9" - ], - "markers": "python_version >= '3.7'", - "version": "==3.5.0" + "version": "==3.6.1" }, "asyncio": { "hashes": [ @@ -55,7 +46,6 @@ "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4", "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==21.4.0" }, "bech32": { @@ -63,7 +53,6 @@ "sha256:7d6db8214603bd7871fcfa6c0826ef68b85b0abd90fa21c285a9c5e21d2bd899", "sha256:990dc8e5a5e4feabbdf55207b5315fdd9b73db40be294a19b3752cde9e79d981" ], - "markers": "python_version >= '3.5'", "version": "==1.2.0" }, "bitstring": { @@ -84,96 +73,101 @@ }, "certifi": { "hashes": [ - "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872", - "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569" + "sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d", + "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412" ], - "version": "==2021.10.8" + "version": "==2022.6.15" }, "cffi": { "hashes": [ - "sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3", - "sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2", - "sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636", - "sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20", - "sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728", - "sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27", - "sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66", - "sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443", - "sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0", - "sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7", - "sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39", - "sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605", - "sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a", - "sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37", - "sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029", - "sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139", - "sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc", - "sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df", - "sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14", - "sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880", - "sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2", - "sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a", - "sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e", - "sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474", - "sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024", - "sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8", - "sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0", - "sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e", - "sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a", - "sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e", - "sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032", - "sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6", - "sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e", - "sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b", - "sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e", - "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954", - "sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962", - "sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c", - "sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4", - "sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55", - "sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962", - "sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023", - "sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c", - "sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6", - "sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8", - "sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382", - "sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7", - "sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc", - "sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997", - "sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796" + "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5", + "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef", + "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104", + "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426", + "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405", + "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375", + "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a", + "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e", + "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc", + "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf", + "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185", + "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497", + "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3", + "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35", + "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c", + "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83", + "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21", + "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca", + "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984", + "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac", + "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd", + "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee", + "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a", + "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2", + "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192", + "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7", + "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585", + "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f", + "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e", + "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27", + "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b", + "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e", + "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e", + "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d", + "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c", + "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415", + "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82", + "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02", + "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314", + "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325", + "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c", + "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3", + "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914", + "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045", + "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d", + "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9", + "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5", + "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2", + "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c", + "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3", + "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2", + "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8", + "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d", + "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d", + "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9", + "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162", + "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76", + "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4", + "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e", + "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9", + "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6", + "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b", + "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01", + "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0" ], - "version": "==1.15.0" - }, - "charset-normalizer": { - "hashes": [ - "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597", - "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df" - ], - "markers": "python_version >= '3.5'", - "version": "==2.0.12" + "version": "==1.15.1" }, "click": { "hashes": [ - "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3", - "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b" + "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", + "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" ], - "markers": "python_version >= '3.6'", - "version": "==8.0.3" + "version": "==8.1.3" }, "ecdsa": { "hashes": [ - "sha256:5cf31d5b33743abe0dfc28999036c849a69d548f994b535e527ee3cb7f3ef676", - "sha256:b9f500bb439e4153d0330610f5d26baaf18d17b8ced1bc54410d189385ea68aa" + "sha256:190348041559e21b22a1d65cee485282ca11a6f81d503fddb84d5017e9ed1e49", + "sha256:80600258e7ed2f16b9aa1d7c295bd70194109ad5a30fdee0eaeefef1d4c559dd" ], "index": "pypi", - "version": "==0.17.0" + "version": "==0.18.0" }, "embit": { "hashes": [ - "sha256:d340107dc1604581df59f844d4eb76ec34b0219c2ac2cbc1837c14938a4730ee" + "sha256:5644ae6ed07bb71bf7fb15daf7f5af73d889180e623f5ff1f35a20ad01f0405e" ], "index": "pypi", - "version": "==0.4.12" + "version": "==0.5.0" }, "environs": { "hashes": [ @@ -185,64 +179,72 @@ }, "fastapi": { "hashes": [ - "sha256:dcfee92a7f9a72b5d4b7ca364bd2b009f8fc10d95ed5769be20e94f39f7e5a15", - "sha256:f0a618aff5f6942862f2d3f20f39b1c037e33314d1b8207fd1c3a2cca76dfd8c" + "sha256:15fcabd5c78c266fa7ae7d8de9b384bfc2375ee0503463a6febbe3bab69d6f65", + "sha256:3233d4a789ba018578658e2af1a4bb5e38bdd122ff722b313666a9b2c6786a83" ], "index": "pypi", - "version": "==0.73.0" + "version": "==0.78.0" }, "h11": { "hashes": [ "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6", "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042" ], - "markers": "python_version >= '3.6'", "version": "==0.12.0" }, "httpcore": { "hashes": [ - "sha256:47d772f754359e56dd9d892d9593b6f9870a37aeb8ba51e9a88b09b3d68cfade", - "sha256:7503ec1c0f559066e7e39bc4003fd2ce023d01cf51793e3c173b864eb456ead1" + "sha256:1105b8b73c025f23ff7c36468e4432226cbb959176eab66864b8e31c4ee27fa6", + "sha256:18b68ab86a3ccf3e7dc0f43598eaddcf472b602aba29f9aa6ab85fe2ada3980b" ], - "markers": "python_version >= '3.6'", - "version": "==0.14.7" + "version": "==0.15.0" }, "httptools": { "hashes": [ - "sha256:04114db99605c9b56ea22a8ec4d7b1485b908128ed4f4a8f6438489c428da794", - "sha256:074afd8afdeec0fa6786cd4a1676e0c0be23dc9a017a86647efa6b695168104f", - "sha256:113816f9af7dcfc4aa71ebb5354d77365f666ecf96ac7ff2aa1d24b6bca44165", - "sha256:1a8f26327023fa1a947d36e60a0582149e182fbbc949c8a65ec8665754dbbe69", - "sha256:2119fa619a4c53311f594f25c0205d619350fcb32140ec5057f861952e9b2b4f", - "sha256:21e948034f70e47c8abfa2d5e6f1a5661f87a2cddc7bcc70f61579cc87897c70", - "sha256:32a10a5903b5bc0eb647d01cd1e95bec3bb614a9bf53f0af1e01360b2debdf81", - "sha256:3787c1f46e9722ef7f07ea5c76b0103037483d1b12e34a02c53ceca5afa4e09a", - "sha256:3f82eb106e1474c63dba36a176067e65b48385f4cecddf3616411aa5d1fbdfec", - "sha256:3f9b4856d46ba1f0c850f4e84b264a9a8b4460acb20e865ec00978ad9fbaa4cf", - "sha256:4137137de8976511a392e27bfdcf231bd926ac13d375e0414e927b08217d779e", - "sha256:4687dfc116a9f1eb22a7d797f0dc6f6e17190d406ca4e729634b38aa98044b17", - "sha256:47dba2345aaa01b87e4981e8756af441349340708d5b60712c98c55a4d28f4af", - "sha256:5a836bd85ae1fb4304f674808488dae403e136d274aa5bafd0e6ee456f11c371", - "sha256:6e676bc3bb911b11f3d7e2144b9a53600bf6b9b21e0e4437aa308e1eef094d97", - "sha256:72ee0e3fb9c6437ab3ae34e9abee67fcee6876f4f58504e3f613dd5882aafdb7", - "sha256:79717080dc3f8b1eeb7f820b9b81528acbc04be6041f323fdd97550da2062575", - "sha256:8ac842df4fc3952efa7820b277961ea55e068bbc54cb59a0820400de7ae358d8", - "sha256:9f475b642c48b1b78584bdd12a5143e2c512485664331eade9c29ef769a17598", - "sha256:b8ac7dee63af4346e02b1e6d32202e3b5b3706a9928bec6da6d7a5b066217422", - "sha256:c0ac2e0ce6733c55858932e7d37fcc7b67ba6bb23e9648593c55f663de031b93", - "sha256:c14576b737d9e6e4f2a86af04918dbe9b62f57ce8102a8695c9a382dbe405c7f", - "sha256:cdc3975db86c29817e6d13df14e037c931fc893a710fb71097777a4147090068", - "sha256:eda95634027200f4b2a6d499e7c2e7fa9b8ee57e045dfda26958ea0af27c070b" + "sha256:1a99346ebcb801b213c591540837340bdf6fd060a8687518d01c607d338b7424", + "sha256:1ee0b459257e222b878a6c09ccf233957d3a4dcb883b0847640af98d2d9aac23", + "sha256:20a45bcf22452a10fa8d58b7dbdb474381f6946bf5b8933e3662d572bc61bae4", + "sha256:29bf97a5c532da9c7a04de2c7a9c31d1d54f3abd65a464119b680206bbbb1055", + "sha256:2c9a930c378b3d15d6b695fb95ebcff81a7395b4f9775c4f10a076beb0b2c1ff", + "sha256:2db44a0b294d317199e9f80123e72c6b005c55b625b57fae36de68670090fa48", + "sha256:3194f6d6443befa8d4db16c1946b2fc428a3ceb8ab32eb6f09a59f86104dc1a0", + "sha256:34d2903dd2a3dd85d33705b6fde40bf91fc44411661283763fd0746723963c83", + "sha256:48e48530d9b995a84d1d89ae6b3ec4e59ea7d494b150ac3bbc5e2ac4acce92cd", + "sha256:54bbd295f031b866b9799dd39cb45deee81aca036c9bff9f58ca06726f6494f1", + "sha256:5d1fe6b6661022fd6cac541f54a4237496b246e6f1c0a6b41998ee08a1135afe", + "sha256:645373c070080e632480a3d251d892cb795be3d3a15f86975d0f1aca56fd230d", + "sha256:6a1a7dfc1f9c78a833e2c4904757a0f47ce25d08634dd2a52af394eefe5f9777", + "sha256:701e66b59dd21a32a274771238025d58db7e2b6ecebbab64ceff51b8e31527ae", + "sha256:72aa3fbe636b16d22e04b5a9d24711b043495e0ecfe58080addf23a1a37f3409", + "sha256:7af6bdbd21a2a25d6784f6d67f44f5df33ef39b6159543b9f9064d365c01f919", + "sha256:7ee9f226acab9085037582c059d66769862706e8e8cd2340470ceb8b3850873d", + "sha256:7f7bfb74718f52d5ed47d608d507bf66d3bc01d4a8b3e6dd7134daaae129357b", + "sha256:8e2eb957787cbb614a0f006bfc5798ff1d90ac7c4dd24854c84edbdc8c02369e", + "sha256:903f739c9fb78dab8970b0f3ea51f21955b24b45afa77b22ff0e172fc11ef111", + "sha256:98993805f1e3cdb53de4eed02b55dcc953cdf017ba7bbb2fd89226c086a6d855", + "sha256:9967d9758df505975913304c434cb9ab21e2c609ad859eb921f2f615a038c8de", + "sha256:a113789e53ac1fa26edf99856a61e4c493868e125ae0dd6354cf518948fbbd5c", + "sha256:a522d12e2ddbc2e91842ffb454a1aeb0d47607972c7d8fc88bd0838d97fb8a2a", + "sha256:abe829275cdd4174b4c4e65ad718715d449e308d59793bf3a931ee1bf7e7b86c", + "sha256:c286985b5e194ca0ebb2908d71464b9be8f17cc66d6d3e330e8d5407248f56ad", + "sha256:cd1295f52971097f757edfbfce827b6dbbfb0f7a74901ee7d4933dff5ad4c9af", + "sha256:ceafd5e960b39c7e0d160a1936b68eb87c5e79b3979d66e774f0c77d4d8faaed", + "sha256:d1f27bb0f75bef722d6e22dc609612bfa2f994541621cd2163f8c943b6463dfe", + "sha256:d3a4e165ca6204f34856b765d515d558dc84f1352033b8721e8d06c3e44930c3", + "sha256:d9b90bf58f3ba04e60321a23a8723a1ff2a9377502535e70495e5ada8e6e6722", + "sha256:f72b5d24d6730035128b238decdc4c0f2104b7056a7ca55cf047c106842ec890", + "sha256:fcddfe70553be717d9745990dfdb194e22ee0f60eb8f48c0794e7bfeda30d2d5", + "sha256:fdb9f9ed79bc6f46b021b3319184699ba1a22410a82204e6e89c774530069683" ], - "version": "==0.3.0" + "version": "==0.4.0" }, "httpx": { "hashes": [ - "sha256:d8e778f76d9bbd46af49e7f062467e3157a5a3d2ae4876a4bbfd8a51ed9c9cb4", - "sha256:e35e83d1d2b9b2a609ef367cc4c1e66fd80b750348b20cc9e19d1952fc2ca3f6" + "sha256:42974f577483e1e932c3cdc3cd2303e883cbfba17fe228b0f63589764d7b9c4b", + "sha256:f28eac771ec9eb4866d3fb4ab65abd42d38c424739e80c08d8d20570de60b0ef" ], "index": "pypi", - "version": "==0.22.0" + "version": "==0.23.0" }, "idna": { "hashes": [ @@ -253,11 +255,11 @@ }, "jinja2": { "hashes": [ - "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8", - "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7" + "sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4", + "sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4" ], "index": "pypi", - "version": "==3.0.3" + "version": "==3.0.1" }, "lnurl": { "hashes": [ @@ -267,96 +269,79 @@ "index": "pypi", "version": "==0.3.6" }, + "loguru": { + "hashes": [ + "sha256:066bd06758d0a513e9836fd9c6b5a75bfb3fd36841f4b996bc60b547a309d41c", + "sha256:4e2414d534a2ab57573365b3e6d0234dfb1d84b68b7f3b948e6fb743860a77c3" + ], + "index": "pypi", + "version": "==0.6.0" + }, "markupsafe": { "hashes": [ - "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298", - "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64", - "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b", - "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194", - "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567", - "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff", - "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724", - "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74", - "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646", - "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35", - "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6", - "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a", - "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6", - "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad", - "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26", - "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38", - "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac", - "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7", - "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6", - "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047", - "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75", - "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f", - "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b", - "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135", - "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8", - "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a", - "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a", - "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1", - "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9", - "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864", - "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914", - "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee", - "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f", - "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18", - "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8", - "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2", - "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d", - "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b", - "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b", - "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86", - "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6", - "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f", - "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb", - "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833", - "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28", - "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e", - "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415", - "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902", - "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f", - "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d", - "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9", - "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d", - "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145", - "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066", - "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c", - "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1", - "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a", - "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207", - "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f", - "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53", - "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd", - "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134", - "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85", - "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9", - "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5", - "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94", - "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509", - "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51", - "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872" + "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003", + "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88", + "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5", + "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7", + "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a", + "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603", + "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1", + "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135", + "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247", + "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6", + "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601", + "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77", + "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02", + "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e", + "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63", + "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f", + "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980", + "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b", + "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812", + "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff", + "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96", + "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1", + "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925", + "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a", + "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6", + "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e", + "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f", + "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4", + "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f", + "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3", + "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c", + "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a", + "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417", + "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a", + "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a", + "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37", + "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452", + "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933", + "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a", + "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7" ], - "markers": "python_version >= '3.6'", - "version": "==2.0.1" + "version": "==2.1.1" }, "marshmallow": { "hashes": [ - "sha256:04438610bc6dadbdddb22a4a55bcc7f6f8099e69580b2e67f5a681933a1f4400", - "sha256:4c05c1684e0e97fe779c62b91878f173b937fe097b356cd82f793464f5bc6138" + "sha256:00040ab5ea0c608e8787137627a8efae97fabd60552a05dc889c888f814e75eb", + "sha256:635fb65a3285a31a30f276f30e958070f5214c7196202caa5c7ecf28f5274bc7" ], - "markers": "python_version >= '3.6'", - "version": "==3.14.1" + "version": "==3.17.0" }, "outcome": { "hashes": [ - "sha256:c7dd9375cfd3c12db9801d080a3b63d4b0a261aa996c4c13152380587288d958", - "sha256:e862f01d4e626e63e8f92c38d1f8d5546d3f9cce989263c521b2e7990d186967" + "sha256:6f82bd3de45da303cf1f771ecafa1633750a358436a8bb60e06a1ceb745d2672", + "sha256:c4ab89a56575d6d38a05aa16daeaa333109c1f96167aba8901ab18b6b5e0f7f5" ], - "markers": "python_version >= '3.6'", - "version": "==1.1.0" + "version": "==1.2.0" + }, + "packaging": { + "hashes": [ + "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", + "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" + ], + "version": "==21.3" }, "psycopg2-binary": { "hashes": [ @@ -429,77 +414,79 @@ }, "pycryptodomex": { "hashes": [ - "sha256:1ca8e1b4c62038bb2da55451385246f51f412c5f5eabd64812c01766a5989b4a", - "sha256:298c00ea41a81a491d5b244d295d18369e5aac4b61b77b2de5b249ca61cd6659", - "sha256:2aa887683eee493e015545bd69d3d21ac8d5ad582674ec98f4af84511e353e45", - "sha256:2ce76ed0081fd6ac8c74edc75b9d14eca2064173af79843c24fa62573263c1f2", - "sha256:3da13c2535b7aea94cc2a6d1b1b37746814c74b6e80790daddd55ca5c120a489", - "sha256:406ec8cfe0c098fadb18d597dc2ee6de4428d640c0ccafa453f3d9b2e58d29e2", - "sha256:4d0db8df9ffae36f416897ad184608d9d7a8c2b46c4612c6bc759b26c073f750", - "sha256:530756d2faa40af4c1f74123e1d889bd07feae45bac2fd32f259a35f7aa74151", - "sha256:77931df40bb5ce5e13f4de2bfc982b2ddc0198971fbd947776c8bb5050896eb2", - "sha256:797a36bd1f69df9e2798e33edb4bd04e5a30478efc08f9428c087f17f65a7045", - "sha256:8085bd0ad2034352eee4d4f3e2da985c2749cb7344b939f4d95ead38c2520859", - "sha256:8536bc08d130cae6dcba1ea689f2913dfd332d06113904d171f2f56da6228e89", - "sha256:a4d412eba5679ede84b41dbe48b1bed8f33131ab9db06c238a235334733acc5e", - "sha256:aebecde2adc4a6847094d3bd6a8a9538ef3438a5ea84ac1983fcb167db614461", - "sha256:b276cc4deb4a80f9dfd47a41ebb464b1fe91efd8b1b8620cf5ccf8b824b850d6", - "sha256:b5a185ae79f899b01ca49f365bdf15a45d78d9856f09b0de1a41b92afce1a07f", - "sha256:c4d8977ccda886d88dc3ca789de2f1adc714df912ff3934b3d0a3f3d777deafb", - "sha256:c5dd3ffa663c982d7f1be9eb494a8924f6d40e2e2f7d1d27384cfab1b2ac0662", - "sha256:ca88f2f7020002638276439a01ffbb0355634907d1aa5ca91f3dc0c2e44e8f3b", - "sha256:d2cce1c82a7845d7e2e8a0956c6b7ed3f1661c9acf18eb120fc71e098ab5c6fe", - "sha256:d709572d64825d8d59ea112e11cc7faf6007f294e9951324b7574af4251e4de8", - "sha256:da8db8374295fb532b4b0c467e66800ef17d100e4d5faa2bbbd6df35502da125", - "sha256:e36c7e3b5382cd5669cf199c4a04a0279a43b2a3bdd77627e9b89778ac9ec08c", - "sha256:e95a4a6c54d27a84a4624d2af8bb9ee178111604653194ca6880c98dcad92f48", - "sha256:ee835def05622e0c8b1435a906491760a43d0c462f065ec9143ec4b8d79f8bff", - "sha256:f75009715dcf4a3d680c2338ab19dac5498f8121173a929872950f4fb3a48fbf", - "sha256:f8524b8bc89470cec7ac51734907818d3620fb1637f8f8b542d650ebec42a126" + "sha256:04cc393045a8f19dd110c975e30f38ed7ab3faf21ede415ea67afebd95a22380", + "sha256:0776bfaf2c48154ab54ea45392847c1283d2fcf64e232e85565f858baedfc1fa", + "sha256:0fadb9f7fa3150577800eef35f62a8a24b9ddf1563ff060d9bd3af22d3952c8c", + "sha256:18e2ab4813883ae63396c0ffe50b13554b32bb69ec56f0afaf052e7a7ae0d55b", + "sha256:191e73bc84a8064ad1874dba0ebadedd7cce4dedee998549518f2c74a003b2e1", + "sha256:35a8f7afe1867118330e2e0e0bf759c409e28557fb1fc2fbb1c6c937297dbe9a", + "sha256:3709f13ca3852b0b07fc04a2c03b379189232b24007c466be0f605dd4723e9d4", + "sha256:4540904c09704b6f831059c0dfb38584acb82cb97b0125cd52688c1f1e3fffa6", + "sha256:463119d7d22d0fc04a0f9122e9d3e6121c6648bcb12a052b51bd1eed1b996aa2", + "sha256:46b3f05f2f7ac7841053da4e0f69616929ca3c42f238c405f6c3df7759ad2780", + "sha256:48697790203909fab02a33226fda546604f4e2653f9d47bc5d3eb40879fa7c64", + "sha256:5676a132169a1c1a3712edf25250722ebc8c9102aa9abd814df063ca8362454f", + "sha256:65204412d0c6a8e3c41e21e93a5e6054a74fea501afa03046a388cf042e3377a", + "sha256:67e1e6a92151023ccdfcfbc0afb3314ad30080793b4c27956ea06ab1fb9bcd8a", + "sha256:6f5b6ba8aefd624834bc177a2ac292734996bb030f9d1b388e7504103b6fcddf", + "sha256:7341f1bb2dadb0d1a0047f34c3a58208a92423cdbd3244d998e4b28df5eac0ed", + "sha256:78d9621cf0ea35abf2d38fa2ca6d0634eab6c991a78373498ab149953787e5e5", + "sha256:8eecdf9cdc7343001d047f951b9cc805cd68cb6cd77b20ea46af5bffc5bd3dfb", + "sha256:94c7b60e1f52e1a87715571327baea0733708ab4723346598beca4a3b6879794", + "sha256:996e1ba717077ce1e6d4849af7a1426f38b07b3d173b879e27d5e26d2e958beb", + "sha256:a07a64709e366c2041cd5cfbca592b43998bf4df88f7b0ca73dca37071ccf1bd", + "sha256:b6306403228edde6e289f626a3908a2f7f67c344e712cf7c0a508bab3ad9e381", + "sha256:b9279adc16e4b0f590ceff581f53a80179b02cba9056010d733eb4196134a870", + "sha256:c4cb9cb492ea7dcdf222a8d19a1d09002798ea516aeae8877245206d27326d86", + "sha256:dd452a5af7014e866206d41751886c9b4bf379a339fdf2dbfc7dd16c0fb4f8e0", + "sha256:e2b12968522a0358b8917fc7b28865acac002f02f4c4c6020fcb264d76bfd06d", + "sha256:e3164a18348bd53c69b4435ebfb4ac8a4076291ffa2a70b54f0c4b80c7834b1d", + "sha256:e47bf8776a7e15576887f04314f5228c6527b99946e6638cf2f16da56d260cab", + "sha256:f8be976cec59b11f011f790b88aca67b4ea2bd286578d0bd3e31bcd19afcd3e4", + "sha256:fc9bc7a9b79fe5c750fc81a307052f8daabb709bdaabb0fb18fb136b66b653b5" ], "index": "pypi", - "version": "==3.14.1" + "version": "==3.15.0" }, "pydantic": { "hashes": [ - "sha256:085ca1de245782e9b46cefcf99deecc67d418737a1fd3f6a4f511344b613a5b3", - "sha256:086254884d10d3ba16da0588604ffdc5aab3f7f09557b998373e885c690dd398", - "sha256:0b6037175234850ffd094ca77bf60fb54b08b5b22bc85865331dd3bda7a02fa1", - "sha256:0fe476769acaa7fcddd17cadd172b156b53546ec3614a4d880e5d29ea5fbce65", - "sha256:1d5278bd9f0eee04a44c712982343103bba63507480bfd2fc2790fa70cd64cf4", - "sha256:2cc6a4cb8a118ffec2ca5fcb47afbacb4f16d0ab8b7350ddea5e8ef7bcc53a16", - "sha256:2ee7e3209db1e468341ef41fe263eb655f67f5c5a76c924044314e139a1103a2", - "sha256:3011b975c973819883842c5ab925a4e4298dffccf7782c55ec3580ed17dc464c", - "sha256:3c3b035103bd4e2e4a28da9da7ef2fa47b00ee4a9cf4f1a735214c1bcd05e0f6", - "sha256:4c68c3bc88dbda2a6805e9a142ce84782d3930f8fdd9655430d8576315ad97ce", - "sha256:574936363cd4b9eed8acdd6b80d0143162f2eb654d96cb3a8ee91d3e64bf4cf9", - "sha256:5a79330f8571faf71bf93667d3ee054609816f10a259a109a0738dac983b23c3", - "sha256:5e48ef4a8b8c066c4a31409d91d7ca372a774d0212da2787c0d32f8045b1e034", - "sha256:6c5b77947b9e85a54848343928b597b4f74fc364b70926b3c4441ff52620640c", - "sha256:742645059757a56ecd886faf4ed2441b9c0cd406079c2b4bee51bcc3fbcd510a", - "sha256:7bdfdadb5994b44bd5579cfa7c9b0e1b0e540c952d56f627eb227851cda9db77", - "sha256:815ddebb2792efd4bba5488bc8fde09c29e8ca3227d27cf1c6990fc830fd292b", - "sha256:8b5ac0f1c83d31b324e57a273da59197c83d1bb18171e512908fe5dc7278a1d6", - "sha256:96f240bce182ca7fe045c76bcebfa0b0534a1bf402ed05914a6f1dadff91877f", - "sha256:a733965f1a2b4090a5238d40d983dcd78f3ecea221c7af1497b845a9709c1721", - "sha256:ab624700dc145aa809e6f3ec93fb8e7d0f99d9023b713f6a953637429b437d37", - "sha256:b2571db88c636d862b35090ccf92bf24004393f85c8870a37f42d9f23d13e032", - "sha256:bbbc94d0c94dd80b3340fc4f04fd4d701f4b038ebad72c39693c794fd3bc2d9d", - "sha256:c0727bda6e38144d464daec31dff936a82917f431d9c39c39c60a26567eae3ed", - "sha256:c556695b699f648c58373b542534308922c46a1cda06ea47bc9ca45ef5b39ae6", - "sha256:c86229333cabaaa8c51cf971496f10318c4734cf7b641f08af0a6fbf17ca3054", - "sha256:c8d7da6f1c1049eefb718d43d99ad73100c958a5367d30b9321b092771e96c25", - "sha256:c8e9dcf1ac499679aceedac7e7ca6d8641f0193c591a2d090282aaf8e9445a46", - "sha256:cb23bcc093697cdea2708baae4f9ba0e972960a835af22560f6ae4e7e47d33f5", - "sha256:d1e4c28f30e767fd07f2ddc6f74f41f034d1dd6bc526cd59e63a82fe8bb9ef4c", - "sha256:d9c9bdb3af48e242838f9f6e6127de9be7063aad17b32215ccc36a09c5cf1070", - "sha256:dee5ef83a76ac31ab0c78c10bd7d5437bfdb6358c95b91f1ba7ff7b76f9996a1", - "sha256:e0896200b6a40197405af18828da49f067c2fa1f821491bc8f5bde241ef3f7d7", - "sha256:f5a64b64ddf4c99fe201ac2724daada8595ada0d102ab96d019c1555c2d6441d", - "sha256:f947352c3434e8b937e3aa8f96f47bdfe6d92779e44bb3f41e4c213ba6a32145" + "sha256:02eefd7087268b711a3ff4db528e9916ac9aa18616da7bca69c1871d0b7a091f", + "sha256:059b6c1795170809103a1538255883e1983e5b831faea6558ef873d4955b4a74", + "sha256:0bf07cab5b279859c253d26a9194a8906e6f4a210063b84b433cf90a569de0c1", + "sha256:1542636a39c4892c4f4fa6270696902acb186a9aaeac6f6cf92ce6ae2e88564b", + "sha256:177071dfc0df6248fd22b43036f936cfe2508077a72af0933d0c1fa269b18537", + "sha256:18f3e912f9ad1bdec27fb06b8198a2ccc32f201e24174cec1b3424dda605a310", + "sha256:1dd8fecbad028cd89d04a46688d2fcc14423e8a196d5b0a5c65105664901f810", + "sha256:1ed987c3ff29fff7fd8c3ea3a3ea877ad310aae2ef9889a119e22d3f2db0691a", + "sha256:447d5521575f18e18240906beadc58551e97ec98142266e521c34968c76c8761", + "sha256:494f7c8537f0c02b740c229af4cb47c0d39840b829ecdcfc93d91dcbb0779892", + "sha256:4988c0f13c42bfa9ddd2fe2f569c9d54646ce84adc5de84228cfe83396f3bd58", + "sha256:4ce9ae9e91f46c344bec3b03d6ee9612802682c1551aaf627ad24045ce090761", + "sha256:5d93d4e95eacd313d2c765ebe40d49ca9dd2ed90e5b37d0d421c597af830c195", + "sha256:61b6760b08b7c395975d893e0b814a11cf011ebb24f7d869e7118f5a339a82e1", + "sha256:72ccb318bf0c9ab97fc04c10c37683d9eea952ed526707fabf9ac5ae59b701fd", + "sha256:79b485767c13788ee314669008d01f9ef3bc05db9ea3298f6a50d3ef596a154b", + "sha256:7eb57ba90929bac0b6cc2af2373893d80ac559adda6933e562dcfb375029acee", + "sha256:8bc541a405423ce0e51c19f637050acdbdf8feca34150e0d17f675e72d119580", + "sha256:969dd06110cb780da01336b281f53e2e7eb3a482831df441fb65dd30403f4608", + "sha256:985ceb5d0a86fcaa61e45781e567a59baa0da292d5ed2e490d612d0de5796918", + "sha256:9bcf8b6e011be08fb729d110f3e22e654a50f8a826b0575c7196616780683380", + "sha256:9ce157d979f742a915b75f792dbd6aa63b8eccaf46a1005ba03aa8a986bde34a", + "sha256:9f659a5ee95c8baa2436d392267988fd0f43eb774e5eb8739252e5a7e9cf07e0", + "sha256:a4a88dcd6ff8fd47c18b3a3709a89adb39a6373f4482e04c1b765045c7e282fd", + "sha256:a955260d47f03df08acf45689bd163ed9df82c0e0124beb4251b1290fa7ae728", + "sha256:a9af62e9b5b9bc67b2a195ebc2c2662fdf498a822d62f902bf27cccb52dbbf49", + "sha256:ae72f8098acb368d877b210ebe02ba12585e77bd0db78ac04a1ee9b9f5dd2166", + "sha256:b83ba3825bc91dfa989d4eed76865e71aea3a6ca1388b59fc801ee04c4d8d0d6", + "sha256:c11951b404e08b01b151222a1cb1a9f0a860a8153ce8334149ab9199cd198131", + "sha256:c320c64dd876e45254bdd350f0179da737463eea41c43bacbee9d8c9d1021f11", + "sha256:c8098a724c2784bf03e8070993f6d46aa2eeca031f8d8a048dff277703e6e193", + "sha256:d12f96b5b64bec3f43c8e82b4aab7599d0157f11c798c9f9c528a72b9e0b339a", + "sha256:e565a785233c2d03724c4dc55464559639b1ba9ecf091288dd47ad9c629433bd", + "sha256:f0f047e11febe5c3198ed346b507e1d010330d56ad615a7e0a89fae604065a0e", + "sha256:fe4670cb32ea98ffbf5a1262f14c3e102cccd92b1869df3bb09538158ba90fe6" ], - "markers": "python_full_version >= '3.6.1'", - "version": "==1.9.0" + "version": "==1.9.1" }, "pyngrok": { "hashes": [ @@ -508,6 +495,13 @@ "index": "pypi", "version": "==5.1.0" }, + "pyparsing": { + "hashes": [ + "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb", + "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc" + ], + "version": "==3.0.9" + }, "pypng": { "hashes": [ "sha256:76f8a1539ec56451da7ab7121f12a361969fe0f2d48d703d198ce2a99d6c5afd" @@ -525,18 +519,17 @@ }, "pyscss": { "hashes": [ - "sha256:f1df571569021a23941a538eb154405dde80bed35dc1ea7c5f3e18e0144746bf" + "sha256:8f35521ffe36afa8b34c7d6f3195088a7057c185c2b8f15ee459ab19748669ff" ], "index": "pypi", - "version": "==1.3.7" + "version": "==1.4.0" }, "python-dotenv": { "hashes": [ - "sha256:32b2bdc1873fd3a3c346da1c6db83d0053c3c62f28f1f38516070c4c8971b1d3", - "sha256:a5de49a31e953b45ff2d2fd434bbc2670e8db5273606c1e737cc6b93eff3655f" + "sha256:b7e3b04a59693c42c36f9ab1cc2acc46fa5df8c78e178fc33a8d4cd05c8d498f", + "sha256:d92a187be61fe482e4fd675b6d52200e7be63a12b724abbf931a40ce4fa92938" ], - "markers": "python_full_version >= '3.5.0'", - "version": "==0.19.2" + "version": "==0.20.0" }, "pyyaml": { "hashes": [ @@ -581,13 +574,9 @@ "sha256:026c0de2ee8385d1255b9c2426cd4f03fe9177ac94c09979bc601946c8493aa0", "sha256:99142650756ef1998ce0661568f54a47dac8c638fb27e3816c02536575dbba8c" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.6.0.post0" }, "rfc3986": { - "extras": [ - "idna2008" - ], "hashes": [ "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835", "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97" @@ -625,18 +614,17 @@ }, "shortuuid": { "hashes": [ - "sha256:44a7a86bcf24dbaba2e626cf80c779926b7c3a0d31a3a013e0d3cd1077707d23", - "sha256:9435e87e5a64f3b92f7110c81f989a3b7bdb9358e22d2359829167da476cfc23" + "sha256:459f12fa1acc34ff213b1371467c0325169645a31ed989e268872339af7563d5", + "sha256:b2bb9eb7773170e253bb7ba25971023acb473517a8b76803d9618668cb1dd46f" ], "index": "pypi", - "version": "==1.0.8" + "version": "==1.0.9" }, "six": { "hashes": [ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.16.0" }, "sniffio": { @@ -644,7 +632,6 @@ "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663", "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de" ], - "markers": "python_version >= '3.5'", "version": "==1.2.0" }, "sqlalchemy": { @@ -693,11 +680,11 @@ }, "sqlalchemy-aio": { "hashes": [ - "sha256:7f77366f55d34891c87386dd0962a28b948b684e8ea5edb7daae4187c0b291bf", - "sha256:f767320427c22c66fa5840a1f17f3261110a8ddc8560558f4fbf12d31a66b17b" + "sha256:3f4aa392c38f032d6734826a4138a0f02ed3122d442ed142be1e5964f2a33b60", + "sha256:f531c7982662d71dfc0b117e77bb2ed544e25cd5361e76cf9f5208edcfb71f7b" ], "index": "pypi", - "version": "==0.16.0" + "version": "==0.17.0" }, "sse-starlette": { "hashes": [ @@ -709,30 +696,27 @@ }, "starlette": { "hashes": [ - "sha256:26a18cbda5e6b651c964c12c88b36d9898481cd428ed6e063f5f29c418f73050", - "sha256:57eab3cc975a28af62f6faec94d355a410634940f10b30d68d31cb5ec1b44ae8" + "sha256:5a60c5c2d051f3a8eb546136aa0c9399773a689595e099e0877704d5888279bf", + "sha256:c6d21096774ecb9639acad41b86b7706e52ba3bf1dc13ea4ed9ad593d47e24c7" ], - "markers": "python_version >= '3.6'", - "version": "==0.17.1" + "version": "==0.19.1" }, "typing-extensions": { "hashes": [ - "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42", - "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2" + "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02", + "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6" ], "index": "pypi", - "version": "==4.1.1" + "markers": "python_version < '3.10'", + "version": "==4.3.0" }, "uvicorn": { - "extras": [ - "standard" - ], "hashes": [ - "sha256:25850bbc86195a71a6477b3e4b3b7b4c861fb687fb96912972ce5324472b1011", - "sha256:e85872d84fb651cccc4c5d2a71cf7ead055b8fb4d8f1e78e36092282c0cf2aec" + "sha256:c19a057deb1c5bb060946e2e5c262fc01590c6529c0af2c3d9ce941e89bc30e0", + "sha256:cade07c403c397f9fe275492a48c1b869efd175d5d8a692df649e6e7e2ed8f4e" ], "index": "pypi", - "version": "==0.17.4" + "version": "==0.18.2" }, "uvloop": { "hashes": [ @@ -755,65 +739,75 @@ ], "version": "==0.16.0" }, - "watchgod": { + "watchfiles": { "hashes": [ - "sha256:48140d62b0ebe9dd9cf8381337f06351e1f2e70b2203fa9c6eff4e572ca84f29", - "sha256:d6c1ea21df37847ac0537ca0d6c2f4cdf513562e95f77bb93abbcf05573407b7" + "sha256:56abed43e645d1f2d6def83e35999cc5758b051aff54ca1065cbfcaea15b3389", + "sha256:65ca99a94fcab29d00aa406526eb29cf198c0661854d59a315596064fed02141", + "sha256:67d4c66e46a564059df4aeedab78f09cba0b697bf36cc77566b0a7015dfb7f5d", + "sha256:6e0e8829d32b05151e6009570449f44f891e05f518e495d25f960e0d0b2d0064", + "sha256:715733c2ac9da67b2790788657ff6f8b3797eb31565bfc592289b523ae907ca2", + "sha256:7b81c6e404b2aa62482a719eb778e4a16d01728302dce1f1512c1e5354a73fda", + "sha256:82238d08d8a49f1a1ba254278cd4329a154f6100b028393059722ebeddd2ff3d", + "sha256:955e8f840e1996a8a41be57de4c03af7b1515a685b7fb6abe222f859e413a907", + "sha256:cab62510f990d195986302aa6a48ed636d685b099927049120d520c96069fa49", + "sha256:d1f9de6b776b3aff17898a4cf5ac5a2d0a16212ea7aad2bbe0ef6aa3e79a96af", + "sha256:d4f45acd1143db6d3ee77a4ff12d3239bc8083108133e6174e9dcce59c1f9902", + "sha256:f7f71012e096e11256fae3b37617a9777980f281e18deb2e789e85cd5b113935" ], - "version": "==0.7" + "version": "==0.15.0" }, "websockets": { "hashes": [ - "sha256:002071169d2e44ce8eb9e5ebac9fbce142ba4b5146eef1cfb16b177a27662657", - "sha256:05e7f098c76b0a4743716590bb8f9706de19f1ef5148d61d0cf76495ec3edb9c", - "sha256:08a42856158307e231b199671c4fce52df5786dd3d703f36b5d8ac76b206c485", - "sha256:0d93b7cadc761347d98da12ec1930b5c71b2096f1ceed213973e3cda23fead9c", - "sha256:10edd9d7d3581cfb9ff544ac09fc98cab7ee8f26778a5a8b2d5fd4b0684c5ba5", - "sha256:14e9cf68a08d1a5d42109549201aefba473b1d925d233ae19035c876dd845da9", - "sha256:181d2b25de5a437b36aefedaf006ecb6fa3aa1328ec0236cdde15f32f9d3ff6d", - "sha256:189ed478395967d6a98bb293abf04e8815349e17456a0a15511f1088b6cb26e4", - "sha256:1d858fb31e5ac992a2cdf17e874c95f8a5b1e917e1fb6b45ad85da30734b223f", - "sha256:1dafe98698ece09b8ccba81b910643ff37198e43521d977be76caf37709cf62b", - "sha256:3477146d1f87ead8df0f27e8960249f5248dceb7c2741e8bbec9aa5338d0c053", - "sha256:38db6e2163b021642d0a43200ee2dec8f4980bdbda96db54fde72b283b54cbfc", - "sha256:3a02ab91d84d9056a9ee833c254895421a6333d7ae7fff94b5c68e4fa8095519", - "sha256:3bbf080f3892ba1dc8838786ec02899516a9d227abe14a80ef6fd17d4fb57127", - "sha256:3ef6f73854cded34e78390dbdf40dfdcf0b89b55c0e282468ef92646fce8d13a", - "sha256:468f0031fdbf4d643f89403a66383247eb82803430b14fa27ce2d44d2662ca37", - "sha256:483edee5abed738a0b6a908025be47f33634c2ad8e737edd03ffa895bd600909", - "sha256:531d8eb013a9bc6b3ad101588182aa9b6dd994b190c56df07f0d84a02b85d530", - "sha256:5560558b0dace8312c46aa8915da977db02738ac8ecffbc61acfbfe103e10155", - "sha256:5bb6256de5a4fb1d42b3747b4e2268706c92965d75d0425be97186615bf2f24f", - "sha256:667c41351a6d8a34b53857ceb8343a45c85d438ee4fd835c279591db8aeb85be", - "sha256:6b014875fae19577a392372075e937ebfebf53fd57f613df07b35ab210f31534", - "sha256:6fdec1a0b3e5630c58e3d8704d2011c678929fce90b40908c97dfc47de8dca72", - "sha256:7bdd3d26315db0a9cf8a0af30ca95e0aa342eda9c1377b722e71ccd86bc5d1dd", - "sha256:7c9407719f42cb77049975410490c58a705da6af541adb64716573e550e5c9db", - "sha256:7d6673b2753f9c5377868a53445d0c321ef41ff3c8e3b6d57868e72054bfce5f", - "sha256:816ae7dac2c6522cfa620947ead0ca95ac654916eebf515c94d7c28de5601a6e", - "sha256:882c0b8bdff3bf1bd7f024ce17c6b8006042ec4cceba95cf15df57e57efa471c", - "sha256:8877861e3dee38c8d302eee0d5dbefa6663de3b46dc6a888f70cd7e82562d1f7", - "sha256:888a5fa2a677e0c2b944f9826c756475980f1b276b6302e606f5c4ff5635be9e", - "sha256:89e985d40d407545d5f5e2e58e1fdf19a22bd2d8cd54d20a882e29f97e930a0a", - "sha256:97b4b68a2ddaf5c4707ae79c110bfd874c5be3c6ac49261160fb243fa45d8bbb", - "sha256:98de71f86bdb29430fd7ba9997f47a6b10866800e3ea577598a786a785701bb0", - "sha256:9f304a22ece735a3da8a51309bc2c010e23961a8f675fae46fdf62541ed62123", - "sha256:9fd62c6dc83d5d35fb6a84ff82ec69df8f4657fff05f9cd6c7d9bec0dd57f0f6", - "sha256:a249139abc62ef333e9e85064c27fefb113b16ffc5686cefc315bdaef3eefbc8", - "sha256:b66e6d514f12c28d7a2d80bb2a48ef223342e99c449782d9831b0d29a9e88a17", - "sha256:b68b6caecb9a0c6db537aa79750d1b592a841e4f1a380c6196091e65b2ad35f9", - "sha256:baa83174390c0ff4fc1304fbe24393843ac7a08fdd59295759c4b439e06b1536", - "sha256:bb01ea7b5f52e7125bdc3c5807aeaa2d08a0553979cf2d96a8b7803ea33e15e7", - "sha256:cfae282c2aa7f0c4be45df65c248481f3509f8c40ca8b15ed96c35668ae0ff69", - "sha256:d0d81b46a5c87d443e40ce2272436da8e6092aa91f5fbeb60d1be9f11eff5b4c", - "sha256:d9b245db5a7e64c95816e27d72830e51411c4609c05673d1ae81eb5d23b0be54", - "sha256:ddab2dc69ee5ae27c74dbfe9d7bb6fee260826c136dca257faa1a41d1db61a89", - "sha256:e1b60fd297adb9fc78375778a5220da7f07bf54d2a33ac781319650413fc6a60", - "sha256:e259be0863770cb91b1a6ccf6907f1ac2f07eff0b7f01c249ed751865a70cb0d", - "sha256:e3872ae57acd4306ecf937d36177854e218e999af410a05c17168cd99676c512", - "sha256:e4819c6fb4f336fd5388372cb556b1f3a165f3f68e66913d1a2fc1de55dc6f58" + "sha256:07cdc0a5b2549bcfbadb585ad8471ebdc7bdf91e32e34ae3889001c1c106a6af", + "sha256:210aad7fdd381c52e58777560860c7e6110b6174488ef1d4b681c08b68bf7f8c", + "sha256:28dd20b938a57c3124028680dc1600c197294da5db4292c76a0b48efb3ed7f76", + "sha256:2f94fa3ae454a63ea3a19f73b95deeebc9f02ba2d5617ca16f0bbdae375cda47", + "sha256:31564a67c3e4005f27815634343df688b25705cccb22bc1db621c781ddc64c69", + "sha256:347974105bbd4ea068106ec65e8e8ebd86f28c19e529d115d89bd8cc5cda3079", + "sha256:379e03422178436af4f3abe0aa8f401aa77ae2487843738542a75faf44a31f0c", + "sha256:3eda1cb7e9da1b22588cefff09f0951771d6ee9fa8dbe66f5ae04cc5f26b2b55", + "sha256:51695d3b199cd03098ae5b42833006a0f43dc5418d3102972addc593a783bc02", + "sha256:54c000abeaff6d8771a4e2cef40900919908ea7b6b6a30eae72752607c6db559", + "sha256:5b936bf552e4f6357f5727579072ff1e1324717902127ffe60c92d29b67b7be3", + "sha256:6075fd24df23133c1b078e08a9b04a3bc40b31a8def4ee0b9f2c8865acce913e", + "sha256:661f641b44ed315556a2fa630239adfd77bd1b11cb0b9d96ed8ad90b0b1e4978", + "sha256:6ea6b300a6bdd782e49922d690e11c3669828fe36fc2471408c58b93b5535a98", + "sha256:6ed1d6f791eabfd9808afea1e068f5e59418e55721db8b7f3bfc39dc831c42ae", + "sha256:7934e055fd5cd9dee60f11d16c8d79c4567315824bacb1246d0208a47eca9755", + "sha256:7ab36e17af592eec5747c68ef2722a74c1a4a70f3772bc661079baf4ae30e40d", + "sha256:7f6d96fdb0975044fdd7953b35d003b03f9e2bcf85f2d2cf86285ece53e9f991", + "sha256:83e5ca0d5b743cde3d29fda74ccab37bdd0911f25bd4cdf09ff8b51b7b4f2fa1", + "sha256:85506b3328a9e083cc0a0fb3ba27e33c8db78341b3eb12eb72e8afd166c36680", + "sha256:8af75085b4bc0b5c40c4a3c0e113fa95e84c60f4ed6786cbb675aeb1ee128247", + "sha256:8b1359aba0ff810d5830d5ab8e2c4a02bebf98a60aa0124fb29aa78cfdb8031f", + "sha256:8fbd7d77f8aba46d43245e86dd91a8970eac4fb74c473f8e30e9c07581f852b2", + "sha256:907e8247480f287aa9bbc9391bd6de23c906d48af54c8c421df84655eef66af7", + "sha256:93d5ea0b5da8d66d868b32c614d2b52d14304444e39e13a59566d4acb8d6e2e4", + "sha256:97bc9d41e69a7521a358f9b8e44871f6cdeb42af31815c17aed36372d4eec667", + "sha256:994cdb1942a7a4c2e10098d9162948c9e7b235df755de91ca33f6e0481366fdb", + "sha256:a141de3d5a92188234afa61653ed0bbd2dde46ad47b15c3042ffb89548e77094", + "sha256:a1e15b230c3613e8ea82c9fc6941b2093e8eb939dd794c02754d33980ba81e36", + "sha256:aad5e300ab32036eb3fdc350ad30877210e2f51bceaca83fb7fef4d2b6c72b79", + "sha256:b529fdfa881b69fe563dbd98acce84f3e5a67df13de415e143ef053ff006d500", + "sha256:b9c77f0d1436ea4b4dc089ed8335fa141e6a251a92f75f675056dac4ab47a71e", + "sha256:bb621ec2dbbbe8df78a27dbd9dd7919f9b7d32a73fafcb4d9252fc4637343582", + "sha256:c7250848ce69559756ad0086a37b82c986cd33c2d344ab87fea596c5ac6d9442", + "sha256:c8d1d14aa0f600b5be363077b621b1b4d1eb3fbf90af83f9281cda668e6ff7fd", + "sha256:d1655a6fc7aecd333b079d00fb3c8132d18988e47f19740c69303bf02e9883c6", + "sha256:d6353ba89cfc657a3f5beabb3b69be226adbb5c6c7a66398e17809b0ce3c4731", + "sha256:da4377904a3379f0c1b75a965fff23b28315bcd516d27f99a803720dfebd94d4", + "sha256:e49ea4c1a9543d2bd8a747ff24411509c29e4bdcde05b5b0895e2120cb1a761d", + "sha256:e4e08305bfd76ba8edab08dcc6496f40674f44eb9d5e23153efa0a35750337e8", + "sha256:e6fa05a680e35d0fcc1470cb070b10e6fe247af54768f488ed93542e71339d6f", + "sha256:e7e6f2d6fd48422071cc8a6f8542016f350b79cc782752de531577d35e9bd677", + "sha256:e904c0381c014b914136c492c8fa711ca4cced4e9b3d110e5e7d436d0fc289e8", + "sha256:ec2b0ab7edc8cd4b0eb428b38ed89079bdc20c6bdb5f889d353011038caac2f9", + "sha256:ef5ce841e102278c1c2e98f043db99d6755b1c58bde475516aef3a008ed7f28e", + "sha256:f351c7d7d92f67c0609329ab2735eee0426a03022771b00102816a72715bb00b", + "sha256:fab7c640815812ed5f10fbee7abbf58788d602046b7bb3af9b1ac753a6d5e916", + "sha256:fc06cc8073c8e87072138ba1e431300e2d408f054b27047d047b549455066ff4" ], - "version": "==10.1" + "version": "==10.3" } }, "develop": { @@ -829,7 +823,6 @@ "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4", "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==21.4.0" }, "black": { @@ -839,63 +832,79 @@ "index": "pypi", "version": "==20.8b1" }, + "certifi": { + "hashes": [ + "sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d", + "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412" + ], + "version": "==2022.6.15" + }, + "charset-normalizer": { + "hashes": [ + "sha256:5189b6f22b01957427f35b6a08d9a0bc45b46d3788ef5a92e978433c7a35f8a5", + "sha256:575e708016ff3a5e3681541cb9d79312c416835686d054a23accb873b254f413" + ], + "version": "==2.1.0" + }, "click": { "hashes": [ - "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3", - "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b" + "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", + "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" ], - "markers": "python_version >= '3.6'", - "version": "==8.0.3" + "version": "==8.1.3" }, "coverage": { - "extras": [ - "toml" - ], "hashes": [ - "sha256:1245ab82e8554fa88c4b2ab1e098ae051faac5af829efdcf2ce6b34dccd5567c", - "sha256:1bc6d709939ff262fd1432f03f080c5042dc6508b6e0d3d20e61dd045456a1a0", - "sha256:25e73d4c81efa8ea3785274a2f7f3bfbbeccb6fcba2a0bdd3be9223371c37554", - "sha256:276b13cc085474e482566c477c25ed66a097b44c6e77132f3304ac0b039f83eb", - "sha256:2aed4761809640f02e44e16b8b32c1a5dee5e80ea30a0ff0912158bde9c501f2", - "sha256:2dd70a167843b4b4b2630c0c56f1b586fe965b4f8ac5da05b6690344fd065c6b", - "sha256:352c68e233409c31048a3725c446a9e48bbff36e39db92774d4f2380d630d8f8", - "sha256:3f2b05757c92ad96b33dbf8e8ec8d4ccb9af6ae3c9e9bd141c7cc44d20c6bcba", - "sha256:448d7bde7ceb6c69e08474c2ddbc5b4cd13c9e4aa4a717467f716b5fc938a734", - "sha256:463e52616ea687fd323888e86bf25e864a3cc6335a043fad6bbb037dbf49bbe2", - "sha256:482fb42eea6164894ff82abbcf33d526362de5d1a7ed25af7ecbdddd28fc124f", - "sha256:56c4a409381ddd7bbff134e9756077860d4e8a583d310a6f38a2315b9ce301d0", - "sha256:56d296cbc8254a7dffdd7bcc2eb70be5a233aae7c01856d2d936f5ac4e8ac1f1", - "sha256:5e15d424b8153756b7c903bde6d4610be0c3daca3986173c18dd5c1a1625e4cd", - "sha256:618eeba986cea7f621d8607ee378ecc8c2504b98b3fdc4952b30fe3578304687", - "sha256:61d47a897c1e91f33f177c21de897267b38fbb45f2cd8e22a710bcef1df09ac1", - "sha256:621f6ea7260ea2ffdaec64fe5cb521669984f567b66f62f81445221d4754df4c", - "sha256:6a5cdc3adb4f8bb8d8f5e64c2e9e282bc12980ef055ec6da59db562ee9bdfefa", - "sha256:6c3f6158b02ac403868eea390930ae64e9a9a2a5bbfafefbb920d29258d9f2f8", - "sha256:704f89b87c4f4737da2860695a18c852b78ec7279b24eedacab10b29067d3a38", - "sha256:72128176fea72012063200b7b395ed8a57849282b207321124d7ff14e26988e8", - "sha256:78fbb2be068a13a5d99dce9e1e7d168db880870f7bc73f876152130575bd6167", - "sha256:7bff3a98f63b47464480de1b5bdd80c8fade0ba2832c9381253c9b74c4153c27", - "sha256:84f2436d6742c01136dd940ee158bfc7cf5ced3da7e4c949662b8703b5cd8145", - "sha256:9976fb0a5709988778ac9bc44f3d50fccd989987876dfd7716dee28beed0a9fa", - "sha256:9ad0a117b8dc2061ce9461ea4c1b4799e55edceb236522c5b8f958ce9ed8fa9a", - "sha256:9e3dd806f34de38d4c01416344e98eab2437ac450b3ae39c62a0ede2f8b5e4ed", - "sha256:9eb494070aa060ceba6e4bbf44c1bc5fa97bfb883a0d9b0c9049415f9e944793", - "sha256:9fde6b90889522c220dd56a670102ceef24955d994ff7af2cb786b4ba8fe11e4", - "sha256:9fff3ff052922cb99f9e52f63f985d4f7a54f6b94287463bc66b7cdf3eb41217", - "sha256:a06c358f4aed05fa1099c39decc8022261bb07dfadc127c08cfbd1391b09689e", - "sha256:a4f923b9ab265136e57cc14794a15b9dcea07a9c578609cd5dbbfff28a0d15e6", - "sha256:c5b81fb37db76ebea79aa963b76d96ff854e7662921ce742293463635a87a78d", - "sha256:d5ed164af5c9078596cfc40b078c3b337911190d3faeac830c3f1274f26b8320", - "sha256:d651fde74a4d3122e5562705824507e2f5b2d3d57557f1916c4b27635f8fbe3f", - "sha256:de73fca6fb403dd72d4da517cfc49fcf791f74eee697d3219f6be29adf5af6ce", - "sha256:e647a0be741edbb529a72644e999acb09f2ad60465f80757da183528941ff975", - "sha256:e92c7a5f7d62edff50f60a045dc9542bf939758c95b2fcd686175dd10ce0ed10", - "sha256:eeffd96882d8c06d31b65dddcf51db7c612547babc1c4c5db6a011abe9798525", - "sha256:f5a4551dfd09c3bd12fca8144d47fe7745275adf3229b7223c2f9e29a975ebda", - "sha256:fac0bcc5b7e8169bffa87f0dcc24435446d329cbc2b5486d155c2e0f3b493ae1" + "sha256:0895ea6e6f7f9939166cc835df8fa4599e2d9b759b02d1521b574e13b859ac32", + "sha256:0f211df2cba951ffcae210ee00e54921ab42e2b64e0bf2c0befc977377fb09b7", + "sha256:147605e1702d996279bb3cc3b164f408698850011210d133a2cb96a73a2f7996", + "sha256:24b04d305ea172ccb21bee5bacd559383cba2c6fcdef85b7701cf2de4188aa55", + "sha256:25b7ec944f114f70803d6529394b64f8749e93cbfac0fe6c5ea1b7e6c14e8a46", + "sha256:2b20286c2b726f94e766e86a3fddb7b7e37af5d0c635bdfa7e4399bc523563de", + "sha256:2dff52b3e7f76ada36f82124703f4953186d9029d00d6287f17c68a75e2e6039", + "sha256:2f8553878a24b00d5ab04b7a92a2af50409247ca5c4b7a2bf4eabe94ed20d3ee", + "sha256:3def6791adf580d66f025223078dc84c64696a26f174131059ce8e91452584e1", + "sha256:422fa44070b42fef9fb8dabd5af03861708cdd6deb69463adc2130b7bf81332f", + "sha256:4f89d8e03c8a3757aae65570d14033e8edf192ee9298303db15955cadcff0c63", + "sha256:5336e0352c0b12c7e72727d50ff02557005f79a0b8dcad9219c7c4940a930083", + "sha256:54d8d0e073a7f238f0666d3c7c0d37469b2aa43311e4024c925ee14f5d5a1cbe", + "sha256:5ef42e1db047ca42827a85e34abe973971c635f83aed49611b7f3ab49d0130f0", + "sha256:5f65e5d3ff2d895dab76b1faca4586b970a99b5d4b24e9aafffc0ce94a6022d6", + "sha256:6c3ccfe89c36f3e5b9837b9ee507472310164f352c9fe332120b764c9d60adbe", + "sha256:6d0b48aff8e9720bdec315d67723f0babd936a7211dc5df453ddf76f89c59933", + "sha256:6fe75dcfcb889b6800f072f2af5a331342d63d0c1b3d2bf0f7b4f6c353e8c9c0", + "sha256:79419370d6a637cb18553ecb25228893966bd7935a9120fa454e7076f13b627c", + "sha256:7bb00521ab4f99fdce2d5c05a91bddc0280f0afaee0e0a00425e28e209d4af07", + "sha256:80db4a47a199c4563d4a25919ff29c97c87569130375beca3483b41ad5f698e8", + "sha256:866ebf42b4c5dbafd64455b0a1cd5aa7b4837a894809413b930026c91e18090b", + "sha256:8af6c26ba8df6338e57bedbf916d76bdae6308e57fc8f14397f03b5da8622b4e", + "sha256:a13772c19619118903d65a91f1d5fea84be494d12fd406d06c849b00d31bf120", + "sha256:a697977157adc052284a7160569b36a8bbec09db3c3220642e6323b47cec090f", + "sha256:a9032f9b7d38bdf882ac9f66ebde3afb8145f0d4c24b2e600bc4c6304aafb87e", + "sha256:b5e28db9199dd3833cc8a07fa6cf429a01227b5d429facb56eccd765050c26cd", + "sha256:c77943ef768276b61c96a3eb854eba55633c7a3fddf0a79f82805f232326d33f", + "sha256:d230d333b0be8042ac34808ad722eabba30036232e7a6fb3e317c49f61c93386", + "sha256:d4548be38a1c810d79e097a38107b6bf2ff42151900e47d49635be69943763d8", + "sha256:d4e7ced84a11c10160c0697a6cc0b214a5d7ab21dfec1cd46e89fbf77cc66fae", + "sha256:d56f105592188ce7a797b2bd94b4a8cb2e36d5d9b0d8a1d2060ff2a71e6b9bbc", + "sha256:d714af0bdba67739598849c9f18efdcc5a0412f4993914a0ec5ce0f1e864d783", + "sha256:d774d9e97007b018a651eadc1b3970ed20237395527e22cbeb743d8e73e0563d", + "sha256:e0524adb49c716ca763dbc1d27bedce36b14f33e6b8af6dba56886476b42957c", + "sha256:e2618cb2cf5a7cc8d698306e42ebcacd02fb7ef8cfc18485c59394152c70be97", + "sha256:e36750fbbc422c1c46c9d13b937ab437138b998fe74a635ec88989afb57a3978", + "sha256:edfdabe7aa4f97ed2b9dd5dde52d2bb29cb466993bb9d612ddd10d0085a683cf", + "sha256:f22325010d8824594820d6ce84fa830838f581a7fd86a9235f0d2ed6deb61e29", + "sha256:f23876b018dfa5d3e98e96f5644b109090f16a4acb22064e0f06933663005d39", + "sha256:f7bd0ffbcd03dc39490a1f40b2669cc414fae0c4e16b77bb26806a4d0b7d1452" ], - "markers": "python_version >= '3.7'", - "version": "==6.3.1" + "version": "==6.4.2" + }, + "idna": { + "hashes": [ + "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", + "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" + ], + "version": "==3.3" }, "iniconfig": { "hashes": [ @@ -904,31 +913,42 @@ ], "version": "==1.1.1" }, - "mypy": { + "mock": { "hashes": [ - "sha256:0038b21890867793581e4cb0d810829f5fd4441aa75796b53033af3aa30430ce", - "sha256:1171f2e0859cfff2d366da2c7092b06130f232c636a3f7301e3feb8b41f6377d", - "sha256:1b06268df7eb53a8feea99cbfff77a6e2b205e70bf31743e786678ef87ee8069", - "sha256:1b65714dc296a7991000b6ee59a35b3f550e0073411ac9d3202f6516621ba66c", - "sha256:1bf752559797c897cdd2c65f7b60c2b6969ffe458417b8d947b8340cc9cec08d", - "sha256:300717a07ad09525401a508ef5d105e6b56646f7942eb92715a1c8d610149714", - "sha256:3c5b42d0815e15518b1f0990cff7a705805961613e701db60387e6fb663fe78a", - "sha256:4365c60266b95a3f216a3047f1d8e3f895da6c7402e9e1ddfab96393122cc58d", - "sha256:50c7346a46dc76a4ed88f3277d4959de8a2bd0a0fa47fa87a4cde36fe247ac05", - "sha256:5b56154f8c09427bae082b32275a21f500b24d93c88d69a5e82f3978018a0266", - "sha256:74f7eccbfd436abe9c352ad9fb65872cc0f1f0a868e9d9c44db0893440f0c697", - "sha256:7b3f6f557ba4afc7f2ce6d3215d5db279bcf120b3cfd0add20a5d4f4abdae5bc", - "sha256:8c11003aaeaf7cc2d0f1bc101c1cc9454ec4cc9cb825aef3cafff8a5fdf4c799", - "sha256:8ca7f8c4b1584d63c9a0f827c37ba7a47226c19a23a753d52e5b5eddb201afcd", - "sha256:c89702cac5b302f0c5d33b172d2b55b5df2bede3344a2fbed99ff96bddb2cf00", - "sha256:d8f1ff62f7a879c9fe5917b3f9eb93a79b78aad47b533911b853a757223f72e7", - "sha256:d9d2b84b2007cea426e327d2483238f040c49405a6bf4074f605f0156c91a47a", - "sha256:e839191b8da5b4e5d805f940537efcaa13ea5dd98418f06dc585d2891d228cf0", - "sha256:f9fe20d0872b26c4bba1c1be02c5340de1019530302cf2dcc85c7f9fc3252ae0", - "sha256:ff3bf387c14c805ab1388185dd22d6b210824e164d4bb324b195ff34e322d166" + "sha256:122fcb64ee37cfad5b3f48d7a7d51875d7031aaf3d8be7c42e2bee25044eee62", + "sha256:7d3fbbde18228f4ff2f1f119a45cdffa458b4c0dee32eb4d2bb2f82554bac7bc" ], "index": "pypi", - "version": "==0.931" + "version": "==4.0.3" + }, + "mypy": { + "hashes": [ + "sha256:006be38474216b833eca29ff6b73e143386f352e10e9c2fbe76aa8549e5554f5", + "sha256:03c6cc893e7563e7b2949b969e63f02c000b32502a1b4d1314cabe391aa87d66", + "sha256:0e9f70df36405c25cc530a86eeda1e0867863d9471fe76d1273c783df3d35c2e", + "sha256:1ece702f29270ec6af25db8cf6185c04c02311c6bb21a69f423d40e527b75c56", + "sha256:3e09f1f983a71d0672bbc97ae33ee3709d10c779beb613febc36805a6e28bb4e", + "sha256:439c726a3b3da7ca84a0199a8ab444cd8896d95012c4a6c4a0d808e3147abf5d", + "sha256:5a0b53747f713f490affdceef835d8f0cb7285187a6a44c33821b6d1f46ed813", + "sha256:5f1332964963d4832a94bebc10f13d3279be3ce8f6c64da563d6ee6e2eeda932", + "sha256:63e85a03770ebf403291ec50097954cc5caf2a9205c888ce3a61bd3f82e17569", + "sha256:64759a273d590040a592e0f4186539858c948302c653c2eac840c7a3cd29e51b", + "sha256:697540876638ce349b01b6786bc6094ccdaba88af446a9abb967293ce6eaa2b0", + "sha256:9940e6916ed9371809b35b2154baf1f684acba935cd09928952310fbddaba648", + "sha256:9f5f5a74085d9a81a1f9c78081d60a0040c3efb3f28e5c9912b900adf59a16e6", + "sha256:a5ea0875a049de1b63b972456542f04643daf320d27dc592d7c3d9cd5d9bf950", + "sha256:b117650592e1782819829605a193360a08aa99f1fc23d1d71e1a75a142dc7e15", + "sha256:b24be97351084b11582fef18d79004b3e4db572219deee0212078f7cf6352723", + "sha256:b88f784e9e35dcaa075519096dc947a388319cb86811b6af621e3523980f1c8a", + "sha256:bdd5ca340beffb8c44cb9dc26697628d1b88c6bddf5c2f6eb308c46f269bb6f3", + "sha256:d5aaf1edaa7692490f72bdb9fbd941fbf2e201713523bdb3f4038be0af8846c6", + "sha256:e999229b9f3198c0c880d5e269f9f8129c8862451ce53a011326cad38b9ccd24", + "sha256:f4a21d01fc0ba4e31d82f0fff195682e29f9401a8bdb7173891070eb260aeb3b", + "sha256:f4b794db44168a4fc886e3450201365c9526a522c46ba089b55e1f11c163750d", + "sha256:f730d56cb924d371c26b8eaddeea3cc07d78ff51c521c6d04899ac6904b75492" + ], + "index": "pypi", + "version": "==0.961" }, "mypy-extensions": { "hashes": [ @@ -942,7 +962,6 @@ "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" ], - "markers": "python_version >= '3.6'", "version": "==21.3" }, "pathspec": { @@ -957,7 +976,6 @@ "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159", "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3" ], - "markers": "python_version >= '3.6'", "version": "==1.0.0" }, "py": { @@ -965,24 +983,31 @@ "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719", "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==1.11.0" }, "pyparsing": { "hashes": [ - "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea", - "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484" + "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb", + "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc" ], - "markers": "python_version >= '3.6'", - "version": "==3.0.7" + "version": "==3.0.9" }, "pytest": { "hashes": [ - "sha256:9ce3ff477af913ecf6321fe337b93a2c0dcf2a0a1439c43f5452112c1e4280db", - "sha256:e30905a0c131d3d94b89624a1cc5afec3e0ba2fbdb151867d8e0ebd49850f171" + "sha256:13d0e3ccfc2b6e26be000cb6568c832ba67ba32e719443bfe725814d3c42433c", + "sha256:a06a0425453864a270bc45e71f783330a7428defb4230fb5e6a731fde06ecd45" ], "index": "pypi", - "version": "==7.0.1" + "version": "==7.1.2" + }, + "pytest-asyncio": { + "hashes": [ + "sha256:16cf40bdf2b4fb7fc8e4b82bd05ce3fbcd454cbf7b92afc445fe299dabb88213", + "sha256:7659bdb0a9eb9c6e3ef992eef11a2b3e69697800ad02fb06374a210d85b29f91", + "sha256:8fafa6c52161addfd41ee7ab35f11836c5a16ec208f93ee388f752bea3493a84" + ], + "index": "pypi", + "version": "==0.18.3" }, "pytest-cov": { "hashes": [ @@ -994,89 +1019,96 @@ }, "regex": { "hashes": [ - "sha256:04611cc0f627fc4a50bc4a9a2e6178a974c6a6a4aa9c1cca921635d2c47b9c87", - "sha256:0b5d6f9aed3153487252d00a18e53f19b7f52a1651bc1d0c4b5844bc286dfa52", - "sha256:0d2f5c3f7057530afd7b739ed42eb04f1011203bc5e4663e1e1d01bb50f813e3", - "sha256:11772be1eb1748e0e197a40ffb82fb8fd0d6914cd147d841d9703e2bef24d288", - "sha256:1333b3ce73269f986b1fa4d5d395643810074dc2de5b9d262eb258daf37dc98f", - "sha256:16f81025bb3556eccb0681d7946e2b35ff254f9f888cff7d2120e8826330315c", - "sha256:1a171eaac36a08964d023eeff740b18a415f79aeb212169080c170ec42dd5184", - "sha256:1d6301f5288e9bdca65fab3de6b7de17362c5016d6bf8ee4ba4cbe833b2eda0f", - "sha256:1e031899cb2bc92c0cf4d45389eff5b078d1936860a1be3aa8c94fa25fb46ed8", - "sha256:1f8c0ae0a0de4e19fddaaff036f508db175f6f03db318c80bbc239a1def62d02", - "sha256:2245441445099411b528379dee83e56eadf449db924648e5feb9b747473f42e3", - "sha256:22709d701e7037e64dae2a04855021b62efd64a66c3ceed99dfd684bfef09e38", - "sha256:24c89346734a4e4d60ecf9b27cac4c1fee3431a413f7aa00be7c4d7bbacc2c4d", - "sha256:25716aa70a0d153cd844fe861d4f3315a6ccafce22b39d8aadbf7fcadff2b633", - "sha256:2dacb3dae6b8cc579637a7b72f008bff50a94cde5e36e432352f4ca57b9e54c4", - "sha256:34316bf693b1d2d29c087ee7e4bb10cdfa39da5f9c50fa15b07489b4ab93a1b5", - "sha256:36b2d700a27e168fa96272b42d28c7ac3ff72030c67b32f37c05616ebd22a202", - "sha256:37978254d9d00cda01acc1997513f786b6b971e57b778fbe7c20e30ae81a97f3", - "sha256:38289f1690a7e27aacd049e420769b996826f3728756859420eeee21cc857118", - "sha256:385ccf6d011b97768a640e9d4de25412204fbe8d6b9ae39ff115d4ff03f6fe5d", - "sha256:3c7ea86b9ca83e30fa4d4cd0eaf01db3ebcc7b2726a25990966627e39577d729", - "sha256:49810f907dfe6de8da5da7d2b238d343e6add62f01a15d03e2195afc180059ed", - "sha256:519c0b3a6fbb68afaa0febf0d28f6c4b0a1074aefc484802ecb9709faf181607", - "sha256:51f02ca184518702975b56affde6c573ebad4e411599005ce4468b1014b4786c", - "sha256:552a39987ac6655dad4bf6f17dd2b55c7b0c6e949d933b8846d2e312ee80005a", - "sha256:596f5ae2eeddb79b595583c2e0285312b2783b0ec759930c272dbf02f851ff75", - "sha256:6014038f52b4b2ac1fa41a58d439a8a00f015b5c0735a0cd4b09afe344c94899", - "sha256:61ebbcd208d78658b09e19c78920f1ad38936a0aa0f9c459c46c197d11c580a0", - "sha256:6213713ac743b190ecbf3f316d6e41d099e774812d470422b3a0f137ea635832", - "sha256:637e27ea1ebe4a561db75a880ac659ff439dec7f55588212e71700bb1ddd5af9", - "sha256:6aa427c55a0abec450bca10b64446331b5ca8f79b648531138f357569705bc4a", - "sha256:6ca45359d7a21644793de0e29de497ef7f1ae7268e346c4faf87b421fea364e6", - "sha256:6db1b52c6f2c04fafc8da17ea506608e6be7086715dab498570c3e55e4f8fbd1", - "sha256:752e7ddfb743344d447367baa85bccd3629c2c3940f70506eb5f01abce98ee68", - "sha256:760c54ad1b8a9b81951030a7e8e7c3ec0964c1cb9fee585a03ff53d9e531bb8e", - "sha256:768632fd8172ae03852e3245f11c8a425d95f65ff444ce46b3e673ae5b057b74", - "sha256:7a0b9f6a1a15d494b35f25ed07abda03209fa76c33564c09c9e81d34f4b919d7", - "sha256:7e070d3aef50ac3856f2ef5ec7214798453da878bb5e5a16c16a61edf1817cc3", - "sha256:7e12949e5071c20ec49ef00c75121ed2b076972132fc1913ddf5f76cae8d10b4", - "sha256:7e26eac9e52e8ce86f915fd33380f1b6896a2b51994e40bb094841e5003429b4", - "sha256:85ffd6b1cb0dfb037ede50ff3bef80d9bf7fa60515d192403af6745524524f3b", - "sha256:8618d9213a863c468a865e9d2ec50221015f7abf52221bc927152ef26c484b4c", - "sha256:8acef4d8a4353f6678fd1035422a937c2170de58a2b29f7da045d5249e934101", - "sha256:8d2f355a951f60f0843f2368b39970e4667517e54e86b1508e76f92b44811a8a", - "sha256:90b6840b6448203228a9d8464a7a0d99aa8fa9f027ef95fe230579abaf8a6ee1", - "sha256:9187500d83fd0cef4669385cbb0961e227a41c0c9bc39219044e35810793edf7", - "sha256:93c20777a72cae8620203ac11c4010365706062aa13aaedd1a21bb07adbb9d5d", - "sha256:93cce7d422a0093cfb3606beae38a8e47a25232eea0f292c878af580a9dc7605", - "sha256:94c623c331a48a5ccc7d25271399aff29729fa202c737ae3b4b28b89d2b0976d", - "sha256:97f32dc03a8054a4c4a5ab5d761ed4861e828b2c200febd4e46857069a483916", - "sha256:9a2bf98ac92f58777c0fafc772bf0493e67fcf677302e0c0a630ee517a43b949", - "sha256:a602bdc8607c99eb5b391592d58c92618dcd1537fdd87df1813f03fed49957a6", - "sha256:a9d24b03daf7415f78abc2d25a208f234e2c585e5e6f92f0204d2ab7b9ab48e3", - "sha256:abfcb0ef78df0ee9df4ea81f03beea41849340ce33a4c4bd4dbb99e23ec781b6", - "sha256:b013f759cd69cb0a62de954d6d2096d648bc210034b79b1881406b07ed0a83f9", - "sha256:b02e3e72665cd02afafb933453b0c9f6c59ff6e3708bd28d0d8580450e7e88af", - "sha256:b52cc45e71657bc4743a5606d9023459de929b2a198d545868e11898ba1c3f59", - "sha256:ba37f11e1d020969e8a779c06b4af866ffb6b854d7229db63c5fdddfceaa917f", - "sha256:bb804c7d0bfbd7e3f33924ff49757de9106c44e27979e2492819c16972ec0da2", - "sha256:bf594cc7cc9d528338d66674c10a5b25e3cde7dd75c3e96784df8f371d77a298", - "sha256:c38baee6bdb7fe1b110b6b3aaa555e6e872d322206b7245aa39572d3fc991ee4", - "sha256:c73d2166e4b210b73d1429c4f1ca97cea9cc090e5302df2a7a0a96ce55373f1c", - "sha256:c9099bf89078675c372339011ccfc9ec310310bf6c292b413c013eb90ffdcafc", - "sha256:cf0db26a1f76aa6b3aa314a74b8facd586b7a5457d05b64f8082a62c9c49582a", - "sha256:d19a34f8a3429bd536996ad53597b805c10352a8561d8382e05830df389d2b43", - "sha256:da80047524eac2acf7c04c18ac7a7da05a9136241f642dd2ed94269ef0d0a45a", - "sha256:de2923886b5d3214be951bc2ce3f6b8ac0d6dfd4a0d0e2a4d2e5523d8046fdfb", - "sha256:defa0652696ff0ba48c8aff5a1fac1eef1ca6ac9c660b047fc8e7623c4eb5093", - "sha256:e54a1eb9fd38f2779e973d2f8958fd575b532fe26013405d1afb9ee2374e7ab8", - "sha256:e5c31d70a478b0ca22a9d2d76d520ae996214019d39ed7dd93af872c7f301e52", - "sha256:ebaeb93f90c0903233b11ce913a7cb8f6ee069158406e056f884854c737d2442", - "sha256:ecfe51abf7f045e0b9cdde71ca9e153d11238679ef7b5da6c82093874adf3338", - "sha256:f99112aed4fb7cee00c7f77e8b964a9b10f69488cdff626ffd797d02e2e4484f", - "sha256:fd914db437ec25bfa410f8aa0aa2f3ba87cdfc04d9919d608d02330947afaeab" + "sha256:00d2e907d3c5e4f85197c8d2263a9cc2d34bf234a9c6236ae42a3fb0bc09b759", + "sha256:0186edcda692c38381db8ac257c2d023fd2e08818d45dc5bee4ed84212045f51", + "sha256:06c509bd7dcb7966bdb03974457d548e54d8327bad5b0c917e87248edc43e2eb", + "sha256:0a3f3f45c5902eb4d90266002ccb035531ae9b9278f6d5e8028247c34d192099", + "sha256:0c1821146b429e6fdbd13ea10f26765e48d5284bc79749468cfbfe3ceb929f0d", + "sha256:0d93167b7d7731fa9ff9fdc1bae84ec9c7133b01a35f8cc04e926d48da6ce1f7", + "sha256:0fd8c3635fa03ef79d07c7b3ed693b3f3930ccb52c0c51761c3296a7525b135c", + "sha256:119091c675e6ad19da8770f89aa1d52f4ad2a2018d631956f3e90c45882df880", + "sha256:121981ba84309dabefd5e1debd49be6d51624e54b4d44bfc184cd8d555ff1df1", + "sha256:1244e9b9b4b81c9c34e8a84273ffaeebdc78abc98a5b02dcdd49845eb3c63bd7", + "sha256:12e1404dfb4e928d3273a10e3468877fe84bdcd3c50b655a2c9613cfc5d9fe63", + "sha256:13d74951c14708f00700bb29475129ecbc40e01b4029c62ee7bfe9d1f59f31ce", + "sha256:162a5939a6fdf48658d3565eeff35acdd207e07367bf5caaff3d9ea7cb77d7a9", + "sha256:1703490c5b850fa9cef1af00c58966756042e6ca22f4fb5bb857345cd535834f", + "sha256:18e6203cfd81df42a987175aaeed7ba46bcb42130cd81763e2d5edcff0006d5d", + "sha256:192c2784833aea6fc7b004730bf1b91b8b8c6b998b30271aaf3bd8adfef20a96", + "sha256:1948d3ceac5b2d55bc93159c1e0679a256a87a54c735be5cef4543a9e692dbb9", + "sha256:206a327e628bc529d64b21ff79a5e2564f5aec7dc7abcd4b2e8a4b271ec10550", + "sha256:2e5db20412f0db8798ff72473d16da5f13ec808e975b49188badb2462f529fa9", + "sha256:2f94b0befc811fe74a972b1739fffbf74c0dc1a91102aca8e324aa4f2c6991bd", + "sha256:303676797c4c7978726e74eb8255d68f7125a3a29da71ff453448f2117290e9a", + "sha256:34ae4f35db30caa4caf85c55069fcb7a05966a3a5ba6e9e1dab5477d84fbb08a", + "sha256:3c6df8be7d1dd35a0d9a200fbc29f888c4452c8882d284f87608046152e049e6", + "sha256:402fa998c5988d11ed34585eb65740dcebd0fd11844d12eb0a6b4be178eb9c64", + "sha256:40a28759d345c0bb1f5b0ac74ac04f5d48136019522c95c0ec4b07786f67ce20", + "sha256:414ae507ba88264444baf771fec43ce0adcd4c5dbb304d3e0716f3f4d4499d2e", + "sha256:42da079e31ae9818ffa7a35cdd16ab7104e3f7eca9c0958040aede827b2e55c6", + "sha256:473a7d21932ce7c314953b33c32e63df690181860edcdf14bba1278cdf71b07f", + "sha256:49fcb45931a693b0e901972c5e077ea2cf30ec39da699645c43cb8b1542c6e14", + "sha256:4c5913cb9769038bd03e42318955c2f15a688384a6a0b807bcfc8271603d9277", + "sha256:4cfeb71095c8d8380a5df5a38ff94d27a3f483717e509130a822b4d6400b7991", + "sha256:4dc74f0171eede67d79a79c06eca0fe5b7b280dbb8c27ad1fae4ced2ad66268f", + "sha256:5b1cffff2d9f832288fe516021cb81c95c57c0067b13a82f1d2daabdbc2f4270", + "sha256:601c99ac775b6c89699a48976f3dbb000b47d3ca59362c8abc9582e6d0780d91", + "sha256:667a06bb8d72b6da3d9cf38dac4ba969688868ed2279a692e993d2c0e1c30aba", + "sha256:673549a0136c7893f567ed71ab5225ed3701c79b17c0a7faee846c645fc24010", + "sha256:67bd3bdd27db7a6460384869dd4b9c54267d805b67d70b20495bb5767f8e051c", + "sha256:727edff0a4eaff3b6d26cbb50216feac9055aba7e6290eec23c061c2fe2fab55", + "sha256:782627a1cb8fbb1c78d8e841f5b71c2c683086c038f975bebdac7cce7678a96f", + "sha256:7d462ba84655abeddae4dfc517fe1afefb5430b3b5acb0a954de12a47aea7183", + "sha256:8ab39aa445d00902c43a1e951871bedc7f18d095a21eccba153d594faac34aea", + "sha256:8e2075ed4ea2e231e2e98b16cfa5dae87e9a6045a71104525e1efc29aa8faa8e", + "sha256:9daeccb2764bf4cc280c40c6411ae176bb0876948e536590a052b3d647254c95", + "sha256:9e4006942334fa954ebd32fa0728718ec870f95f4ba7cda9edc46dd49c294f22", + "sha256:9f1c8fffd4def0b76c0947b8cb261b266e31041785dc2dc2db7569407a2f54fe", + "sha256:a00cd58a30a1041c193777cb1bc090200b05ff4b073d5935738afd1023e63069", + "sha256:a0220a7a16fd4bfc700661f920510defd31ef7830ce992d5cc51777aa8ccd724", + "sha256:a048f91823862270905cb22ef88038b08aac852ce48e0ecc4b4bf1b895ec37d9", + "sha256:a3c47c71fde0c5d584402e67546c81af9951540f1f622d821e9c20761556473a", + "sha256:a6d9ea727fd1233ee746bf44dd37e7d4320b3ed8ff09e73d7638c969b28d280f", + "sha256:ab0709daedc1099bbd4371ae17eeedd4efc1cf70fcdcfe5de1374a0944b61f80", + "sha256:ab1cb36b411f16da6e057ef8e6657dd0af36f59a667f07e0b4b617e44e53d7b2", + "sha256:ae1c5b435d44aa91d48cc710f20c3485e0584a3ad3565d5ae031d61a35f674f4", + "sha256:b279b9bb401af41130fd2a09427105100bc8c624ed45da1c81c1c0d0aa639734", + "sha256:b72a4ec79a15f6066d14ae1c472b743af4b4ecee14420e8d6e4a336b49b8f21c", + "sha256:c2cd93725911c0159d597b90c96151070ef7e0e67604637e2f2abe06c34bf079", + "sha256:c7c5f914b0eb5242c09f91058b80295525897e873b522575ab235b48db125597", + "sha256:d07d849c9e2eca80adb85d3567302a47195a603ad7b1f0a07508e253c041f954", + "sha256:d2672d68cf6c8452b6758fc3cd2d8feac966d511eed79a68182a5297b473af9c", + "sha256:d35bbcbf70d14f724e7489746cf68efe122796578addd98f91428e144d0ad266", + "sha256:d40b4447784dbe0896a6d10a178f6724598161f942c56f5a60dc0ef7fe63f7a1", + "sha256:d561dcb0fb0ab858291837d51330696a45fd3ba6912a332a4ee130e5484b9e47", + "sha256:d7f5ccfff648093152cadf6d886c7bd922047532f72024c953a79c7553aac2fe", + "sha256:dce6b2ad817e3eb107f8704782b091b0631dd3adf47f14bdc086165d05b528b0", + "sha256:e1fdda3ec7e9785065b67941693995cab95b54023a21db9bf39e54cc7b2c3526", + "sha256:e2a262ec85c595fc8e1f3162cafc654d2219125c00ea3a190c173cea70d2cc7a", + "sha256:e2fc1e3928c1189c0382c547c17717c6d9f425fffe619ef94270fe4c6c8be0a6", + "sha256:ea27acd97a752cfefa9907da935e583efecb302e6e9866f37565968c8407ad58", + "sha256:ee769a438827e443ed428e66d0aa7131c653ecd86ddc5d4644a81ed1d93af0e7", + "sha256:f32e0d1c7e7b0b9c3cac76f3d278e7ee6b99c95672d2c1c6ea625033431837c0", + "sha256:f355caec5bbce20421dc26e53787b10e32fd0df68db2b795435217210c08d69c", + "sha256:f87e9108bb532f8a1fc6bf7e69b930a35c7b0267b8fef0a3ede0bcb4c5aaa531", + "sha256:f8a2fd2f62a77536e4e3193303bec380df40d99e253b1c8f9b6eafa07eaeff67", + "sha256:fbdf4fc6adf38fab1091c579ece3fe9f493bd0f1cfc3d2c76d2e52461ca4f8a9" ], - "version": "==2022.1.18" + "version": "==2022.7.9" + }, + "requests": { + "hashes": [ + "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983", + "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349" + ], + "index": "pypi", + "version": "==2.28.1" }, "toml": { "hashes": [ "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==0.10.2" }, "tomli": { @@ -1088,41 +1120,48 @@ }, "typed-ast": { "hashes": [ - "sha256:0eb77764ea470f14fcbb89d51bc6bbf5e7623446ac4ed06cbd9ca9495b62e36e", - "sha256:1098df9a0592dd4c8c0ccfc2e98931278a6c6c53cb3a3e2cf7e9ee3b06153344", - "sha256:183b183b7771a508395d2cbffd6db67d6ad52958a5fdc99f450d954003900266", - "sha256:18fe320f354d6f9ad3147859b6e16649a0781425268c4dde596093177660e71a", - "sha256:26a432dc219c6b6f38be20a958cbe1abffcc5492821d7e27f08606ef99e0dffd", - "sha256:294a6903a4d087db805a7656989f613371915fc45c8cc0ddc5c5a0a8ad9bea4d", - "sha256:31d8c6b2df19a777bc8826770b872a45a1f30cfefcfd729491baa5237faae837", - "sha256:33b4a19ddc9fc551ebabca9765d54d04600c4a50eda13893dadf67ed81d9a098", - "sha256:42c47c3b43fe3a39ddf8de1d40dbbfca60ac8530a36c9b198ea5b9efac75c09e", - "sha256:525a2d4088e70a9f75b08b3f87a51acc9cde640e19cc523c7e41aa355564ae27", - "sha256:58ae097a325e9bb7a684572d20eb3e1809802c5c9ec7108e85da1eb6c1a3331b", - "sha256:676d051b1da67a852c0447621fdd11c4e104827417bf216092ec3e286f7da596", - "sha256:74cac86cc586db8dfda0ce65d8bcd2bf17b58668dfcc3652762f3ef0e6677e76", - "sha256:8c08d6625bb258179b6e512f55ad20f9dfef019bbfbe3095247401e053a3ea30", - "sha256:90904d889ab8e81a956f2c0935a523cc4e077c7847a836abee832f868d5c26a4", - "sha256:963a0ccc9a4188524e6e6d39b12c9ca24cc2d45a71cfdd04a26d883c922b4b78", - "sha256:bbebc31bf11762b63bf61aaae232becb41c5bf6b3461b80a4df7e791fabb3aca", - "sha256:bc2542e83ac8399752bc16e0b35e038bdb659ba237f4222616b4e83fb9654985", - "sha256:c29dd9a3a9d259c9fa19d19738d021632d673f6ed9b35a739f48e5f807f264fb", - "sha256:c7407cfcad702f0b6c0e0f3e7ab876cd1d2c13b14ce770e412c0c4b9728a0f88", - "sha256:da0a98d458010bf4fe535f2d1e367a2e2060e105978873c04c04212fb20543f7", - "sha256:df05aa5b241e2e8045f5f4367a9f6187b09c4cdf8578bb219861c4e27c443db5", - "sha256:f290617f74a610849bd8f5514e34ae3d09eafd521dceaa6cf68b3f4414266d4e", - "sha256:f30ddd110634c2d7534b2d4e0e22967e88366b0d356b24de87419cc4410c41b7" + "sha256:0261195c2062caf107831e92a76764c81227dae162c4f75192c0d489faf751a2", + "sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1", + "sha256:183afdf0ec5b1b211724dfef3d2cad2d767cbefac291f24d69b00546c1837fb6", + "sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62", + "sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac", + "sha256:2efae9db7a8c05ad5547d522e7dbe62c83d838d3906a3716d1478b6c1d61388d", + "sha256:370788a63915e82fd6f212865a596a0fefcbb7d408bbbb13dea723d971ed8bdc", + "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2", + "sha256:3e123d878ba170397916557d31c8f589951e353cc95fb7f24f6bb69adc1a8a97", + "sha256:4879da6c9b73443f97e731b617184a596ac1235fe91f98d279a7af36c796da35", + "sha256:4e964b4ff86550a7a7d56345c7864b18f403f5bd7380edf44a3c1fb4ee7ac6c6", + "sha256:639c5f0b21776605dd6c9dbe592d5228f021404dafd377e2b7ac046b0349b1a1", + "sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4", + "sha256:6778e1b2f81dfc7bc58e4b259363b83d2e509a65198e85d5700dfae4c6c8ff1c", + "sha256:683407d92dc953c8a7347119596f0b0e6c55eb98ebebd9b23437501b28dcbb8e", + "sha256:79b1e0869db7c830ba6a981d58711c88b6677506e648496b1f64ac7d15633aec", + "sha256:7d5d014b7daa8b0bf2eaef684295acae12b036d79f54178b92a2b6a56f92278f", + "sha256:98f80dee3c03455e92796b58b98ff6ca0b2a6f652120c263efdba4d6c5e58f72", + "sha256:a94d55d142c9265f4ea46fab70977a1944ecae359ae867397757d836ea5a3f47", + "sha256:a9916d2bb8865f973824fb47436fa45e1ebf2efd920f2b9f99342cb7fab93f72", + "sha256:c542eeda69212fa10a7ada75e668876fdec5f856cd3d06829e6aa64ad17c8dfe", + "sha256:cf4afcfac006ece570e32d6fa90ab74a17245b83dfd6655a6f68568098345ff6", + "sha256:ebd9d7f80ccf7a82ac5f88c521115cc55d84e35bf8b446fcd7836eb6b98929a3", + "sha256:ed855bbe3eb3715fca349c80174cfcfd699c2f9de574d40527b8429acae23a66" ], - "markers": "python_version >= '3.6'", - "version": "==1.5.2" + "version": "==1.5.4" }, "typing-extensions": { "hashes": [ - "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42", - "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2" + "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02", + "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6" ], "index": "pypi", - "version": "==4.1.1" + "markers": "python_version < '3.10'", + "version": "==4.3.0" + }, + "urllib3": { + "hashes": [ + "sha256:8298d6d56d39be0e3bc13c1c97d133f9b45d797169a0e11cdd0e0489d786f7ec", + "sha256:879ba4d1e89654d9769ce13121e0f94310ea32e8d2f8cf587b77c08bbcdb30d6" + ], + "version": "==1.26.10" } } } diff --git a/README.md b/README.md index 020f617cb..375da5cf6 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ LNbits (LNbits is beta, for responsible disclosure of any concerns please contact lnbits@pm.me) -Use [lnbits.com](https://lnbits.com), or run your own LNbits server! +Use [legend.lnbits.com](https://legend.lnbits.com), or run your own LNbits server! LNbits is a very simple Python server that sits on top of any funding source, and can be used as: @@ -33,7 +33,7 @@ LNbits is inspired by all the great work of [opennode.com](https://www.opennode. ## Running LNbits -See the [install guide](docs/devs/installation.md) for details on installation and setup. +See the [install guide](docs/guide/installation.md) for details on installation and setup. ## LNbits as an account system diff --git a/docs/devs/installation.md b/docs/devs/installation.md index cbf234cc9..f4d6b145d 100644 --- a/docs/devs/installation.md +++ b/docs/devs/installation.md @@ -7,46 +7,10 @@ nav_order: 1 # Installation -LNbits uses [Pipenv][pipenv] to manage Python packages. +This guide has been moved to the [installation guide](../guide/installation.md). +To install the developer packages, use `pipenv install --dev`. -```sh -git clone https://github.com/lnbits/lnbits-legend.git -cd lnbits-legend/ +## Notes: -sudo apt-get install pipenv -pipenv shell -# pipenv --python 3.9 shell (if you wish to use a version of Python higher than 3.7) -pipenv install --dev -# pipenv --python 3.9 install --dev (if you wish to use a version of Python higher than 3.7) - -# If any of the modules fails to install, try checking and upgrading your setupTool module -# pip install -U setuptools - -# install libffi/libpq in case "pipenv install" fails -# sudo apt-get install -y libffi-dev libpq-dev -``` -## Running the server - -Create the data folder and edit the .env file: - - mkdir data - cp .env.example .env - sudo nano .env - -To then run the server for development purposes (includes hot-reload), use: - - pipenv run python -m uvicorn lnbits.__main__:app --host 0.0.0.0 --reload - -For production, use: - - pipenv run python -m uvicorn lnbits.__main__:app --host 0.0.0.0 - -You might also need to install additional packages, depending on the [backend wallet](../guide/wallets.md) you use. -E.g. when you want to use LND you have to `pipenv run pip install lndgrpc` and `pipenv run pip install purerpc`. - -Take a look at [Polar][polar] for an excellent way of spinning up a Lightning Network dev environment. - -**Notes**: - -* We reccomend using Caddy for a reverse-proxy if you want to serve your install through a domain, alternatively you can use [ngrok](https://ngrok.com/). +* We recommend using Caddy for a reverse-proxy if you want to serve your install through a domain, alternatively you can use [ngrok](https://ngrok.com/). * Screen works well if you want LNbits to continue running when you close your terminal session. diff --git a/docs/guide/installation.md b/docs/guide/installation.md index b458c3f18..cc5a40f44 100644 --- a/docs/guide/installation.md +++ b/docs/guide/installation.md @@ -4,8 +4,88 @@ title: Basic installation nav_order: 2 --- + + # Basic installation -Install Postgres and setup a database for LNbits: + +You can choose between two python package managers, `venv` and `pipenv`. Both are fine but if you don't know what you're doing, just go for the first option. + +By default, LNbits will use SQLite as its database. You can also use PostgreSQL which is recommended for applications with a high load (see guide below). + +## Option 1: venv + +Download this repo and install the dependencies: + +```sh +git clone https://github.com/lnbits/lnbits-legend.git +cd lnbits-legend/ +# ensure you have virtualenv installed, on debian/ubuntu 'apt install python3-venv' +python3 -m venv venv +# If you have problems here, try `sudo apt install -y pkg-config libpq-dev` +./venv/bin/pip install -r requirements.txt +# create the data folder and the .env file +mkdir data && cp .env.example .env +``` + +#### Running the server + +```sh +./venv/bin/uvicorn lnbits.__main__:app --port 5000 +``` + +If you want to host LNbits on the internet, run with the option `--host 0.0.0.0`. + + +## Option 2: pipenv + +You can also use Pipenv to manage your python packages. + +```sh +git clone https://github.com/lnbits/lnbits-legend.git +cd lnbits-legend/ + +sudo apt update && sudo apt install -y pipenv +pipenv install --dev +# pipenv --python 3.9 install --dev (if you wish to use a version of Python higher than 3.7) +pipenv shell +# pipenv --python 3.9 shell (if you wish to use a version of Python higher than 3.7) + +# If any of the modules fails to install, try checking and upgrading your setupTool module +# pip install -U setuptools wheel + +# install libffi/libpq in case "pipenv install" fails +# sudo apt-get install -y libffi-dev libpq-dev + + mkdir data && cp .env.example .env +``` + +#### Running the server + +```sh +pipenv run python -m uvicorn lnbits.__main__:app --port 5000 --host 0.0.0.0 +``` + +Add the flag `--reload` for development (includes hot-reload). + +### Troubleshooting + +Problems installing? These commands have helped us install LNbits. + +```sh +sudo apt install pkg-config libffi-dev libpq-dev setuptools + +# if the secp256k1 build fails: +# if you used venv (option 1) +./venv/bin/pip install setuptools wheel +# if you used pipenv (option 2) +pipenv install setuptools wheel +# build essentials for debian/ubuntu +sudo apt install python3-dev gcc build-essential +``` + +### Optional: PostgreSQL database + +If you want to use LNbits at scale, we recommend using PostgreSQL as the backend database. Install Postgres and setup a database for LNbits: ```sh # on debian/ubuntu 'sudo apt-get -y install postgresql' @@ -22,34 +102,35 @@ createdb lnbits exit ``` -Download this repo and install the dependencies: +You need to edit the `.env` file. ```sh -git clone https://github.com/lnbits/lnbits-legend.git -cd lnbits-legend/ -# ensure you have virtualenv installed, on debian/ubuntu 'apt install python3-venv' should work -python3 -m venv venv -./venv/bin/pip install -r requirements.txt -cp .env.example .env # 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" # save and exit -./venv/bin/uvicorn lnbits.__main__:app --port 5000 ``` +# Using LNbits + Now you can visit your LNbits at http://localhost:5000/. -Now modify the `.env` file with any settings you prefer and add a proper [funding source](./wallets.md) by modifying the value of `LNBITS_BACKEND_WALLET_CLASS` and providing the extra information and credentials related to the chosen funding source. +Now modify the `.env` file with any settings you prefer and add a proper [funding source](./wallets.md) by modifying the value of `LNBITS_BACKEND_WALLET_CLASS` and providing the extra information and credentials related to the chosen funding source. Then you can restart it and it will be using the new settings. -You might also need to install additional packages or perform additional setup steps, depending on the chosen backend. See [the short guide](./wallets.md) on each different funding source. +You might also need to install additional packages or perform additional setup steps, depending on the chosen backend. See [the short guide](./wallets.md) on each different funding source. -## Important note -If you already have LNbits installed and running, on an SQLite database, we **HIGHLY** recommend you migrate to postgres! +Take a look at [Polar](https://lightningpolar.com/) for an excellent way of spinning up a Lightning Network dev environment. -There's a script included that can do the migration easy. You should have Postgres already installed and there should be a password for the user, check the guide above. Additionally, your lnbits instance should run once on postgres to implement the database schema before the migration works: + + +# Additional guides + +### SQLite to PostgreSQL migration +If you already have LNbits installed and running, on an SQLite database, we **highly** recommend you migrate to postgres if you are planning to run LNbits on scale. + +There's a script included that can do the migration easy. You should have Postgres already installed and there should be a password for the user (see Postgres install guide above). Additionally, your LNbits instance should run once on postgres to implement the database schema before the migration works: ```sh # STOP LNbits @@ -68,9 +149,6 @@ python3 conv.py Hopefully, everything works and get migrated... Launch LNbits again and check if everything is working properly. - -# Additional guides - ### LNbits as a systemd service Systemd is great for taking care of your LNbits instance. It will start it on boot and restart it in case it crashes. If you want to run LNbits as a systemd service on your Debian/Ubuntu/Raspbian server, create a file at `/etc/systemd/system/lnbits.service` with the following content: From 37c7553c19518c29469aac4265d2a101aa561827 Mon Sep 17 00:00:00 2001 From: Arc <33088785+arcbtc@users.noreply.github.com> Date: Fri, 15 Jul 2022 08:18:07 +0100 Subject: [PATCH 06/33] Update installation.md --- docs/guide/installation.md | 50 +++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/docs/guide/installation.md b/docs/guide/installation.md index cc5a40f44..de391b884 100644 --- a/docs/guide/installation.md +++ b/docs/guide/installation.md @@ -12,31 +12,7 @@ You can choose between two python package managers, `venv` and `pipenv`. Both ar By default, LNbits will use SQLite as its database. You can also use PostgreSQL which is recommended for applications with a high load (see guide below). -## Option 1: venv - -Download this repo and install the dependencies: - -```sh -git clone https://github.com/lnbits/lnbits-legend.git -cd lnbits-legend/ -# ensure you have virtualenv installed, on debian/ubuntu 'apt install python3-venv' -python3 -m venv venv -# If you have problems here, try `sudo apt install -y pkg-config libpq-dev` -./venv/bin/pip install -r requirements.txt -# create the data folder and the .env file -mkdir data && cp .env.example .env -``` - -#### Running the server - -```sh -./venv/bin/uvicorn lnbits.__main__:app --port 5000 -``` - -If you want to host LNbits on the internet, run with the option `--host 0.0.0.0`. - - -## Option 2: pipenv +## Option 1: pipenv You can also use Pipenv to manage your python packages. @@ -67,6 +43,30 @@ pipenv run python -m uvicorn lnbits.__main__:app --port 5000 --host 0.0.0.0 Add the flag `--reload` for development (includes hot-reload). + +## Option 2: venv + +Download this repo and install the dependencies: + +```sh +git clone https://github.com/lnbits/lnbits-legend.git +cd lnbits-legend/ +# ensure you have virtualenv installed, on debian/ubuntu 'apt install python3-venv' +python3 -m venv venv +# If you have problems here, try `sudo apt install -y pkg-config libpq-dev` +./venv/bin/pip install -r requirements.txt +# create the data folder and the .env file +mkdir data && cp .env.example .env +``` + +#### Running the server + +```sh +./venv/bin/uvicorn lnbits.__main__:app --port 5000 +``` + +If you want to host LNbits on the internet, run with the option `--host 0.0.0.0`. + ### Troubleshooting Problems installing? These commands have helped us install LNbits. From 348033da1be0e739d425a041a0550d70d1826b72 Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Fri, 15 Jul 2022 18:11:11 +0100 Subject: [PATCH 07/33] python code styling (#739) --- lnbits/extensions/copilot/tasks.py | 2 +- lnbits/extensions/jukebox/tasks.py | 2 +- lnbits/extensions/livestream/tasks.py | 2 +- lnbits/extensions/lnaddress/tasks.py | 4 ++-- lnbits/extensions/lnticket/tasks.py | 2 +- lnbits/extensions/lnurlp/tasks.py | 3 ++- lnbits/extensions/satspay/tasks.py | 2 +- lnbits/extensions/splitpayments/tasks.py | 2 +- lnbits/extensions/subdomains/tasks.py | 2 +- lnbits/extensions/tpos/tasks.py | 2 +- 10 files changed, 12 insertions(+), 11 deletions(-) diff --git a/lnbits/extensions/copilot/tasks.py b/lnbits/extensions/copilot/tasks.py index 351eb24b6..f3c5cff84 100644 --- a/lnbits/extensions/copilot/tasks.py +++ b/lnbits/extensions/copilot/tasks.py @@ -25,7 +25,7 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: webhook = None data = None - if "copilot" != payment.extra.get("tag"): + if payment.extra.get("tag") != "copilot": # not an copilot invoice return diff --git a/lnbits/extensions/jukebox/tasks.py b/lnbits/extensions/jukebox/tasks.py index 02241c7b4..70a2e65dd 100644 --- a/lnbits/extensions/jukebox/tasks.py +++ b/lnbits/extensions/jukebox/tasks.py @@ -16,7 +16,7 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: - if "jukebox" != payment.extra.get("tag"): + 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/livestream/tasks.py b/lnbits/extensions/livestream/tasks.py index 5273a89e9..85bdd5e0a 100644 --- a/lnbits/extensions/livestream/tasks.py +++ b/lnbits/extensions/livestream/tasks.py @@ -22,7 +22,7 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: - if "livestream" != payment.extra.get("tag"): + if payment.extra.get("tag") != "livestream": # not a livestream invoice return diff --git a/lnbits/extensions/lnaddress/tasks.py b/lnbits/extensions/lnaddress/tasks.py index 9702c70b6..9abe10c3d 100644 --- a/lnbits/extensions/lnaddress/tasks.py +++ b/lnbits/extensions/lnaddress/tasks.py @@ -43,13 +43,13 @@ async def call_webhook_on_paid(payment_hash): async def on_invoice_paid(payment: Payment) -> None: - if "lnaddress" == payment.extra.get("tag"): + if payment.extra.get("tag") == "lnaddress": await payment.set_pending(False) await set_address_paid(payment_hash=payment.payment_hash) await call_webhook_on_paid(payment_hash=payment.payment_hash) - elif "renew lnaddress" == payment.extra.get("tag"): + elif payment.extra.get("tag") == "renew lnaddress": await payment.set_pending(False) await set_address_renewed( diff --git a/lnbits/extensions/lnticket/tasks.py b/lnbits/extensions/lnticket/tasks.py index 23d485b47..7e672115d 100644 --- a/lnbits/extensions/lnticket/tasks.py +++ b/lnbits/extensions/lnticket/tasks.py @@ -18,7 +18,7 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: - if "lnticket" != payment.extra.get("tag"): + if payment.extra.get("tag") != "lnticket": # not a lnticket invoice return diff --git a/lnbits/extensions/lnurlp/tasks.py b/lnbits/extensions/lnurlp/tasks.py index b632fa13f..525d36ce4 100644 --- a/lnbits/extensions/lnurlp/tasks.py +++ b/lnbits/extensions/lnurlp/tasks.py @@ -1,5 +1,6 @@ import asyncio import json + import httpx from lnbits.core import db as core_db @@ -19,7 +20,7 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: - if "lnurlp" != payment.extra.get("tag"): + if payment.extra.get("tag") != "lnurlp": # not an lnurlp invoice return diff --git a/lnbits/extensions/satspay/tasks.py b/lnbits/extensions/satspay/tasks.py index 7ee6298c5..d325405b8 100644 --- a/lnbits/extensions/satspay/tasks.py +++ b/lnbits/extensions/satspay/tasks.py @@ -19,7 +19,7 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: - if "charge" != payment.extra.get("tag"): + if payment.extra.get("tag") != "charge": # not a charge invoice return diff --git a/lnbits/extensions/splitpayments/tasks.py b/lnbits/extensions/splitpayments/tasks.py index 914e9bd29..0948e849a 100644 --- a/lnbits/extensions/splitpayments/tasks.py +++ b/lnbits/extensions/splitpayments/tasks.py @@ -22,7 +22,7 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: - if "splitpayments" == payment.extra.get("tag") or payment.extra.get("splitted"): + if payment.extra.get("tag") == "splitpayments" or payment.extra.get("splitted"): # already splitted, ignore return diff --git a/lnbits/extensions/subdomains/tasks.py b/lnbits/extensions/subdomains/tasks.py index 75223e824..d8f351618 100644 --- a/lnbits/extensions/subdomains/tasks.py +++ b/lnbits/extensions/subdomains/tasks.py @@ -19,7 +19,7 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: - if "lnsubdomain" != payment.extra.get("tag"): + if payment.extra.get("tag") != "lnsubdomain": # not an lnurlp invoice return diff --git a/lnbits/extensions/tpos/tasks.py b/lnbits/extensions/tpos/tasks.py index 0bb8dff92..01c11428d 100644 --- a/lnbits/extensions/tpos/tasks.py +++ b/lnbits/extensions/tpos/tasks.py @@ -20,7 +20,7 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: - if "tpos" == payment.extra.get("tag") and payment.extra.get("tipSplitted"): + if payment.extra.get("tag") == "tpos" and payment.extra.get("tipSplitted"): # already splitted, ignore return From 6a3a72b9445d0d92ebee89cec80cef67481bbebc Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Fri, 15 Jul 2022 19:54:12 +0200 Subject: [PATCH 08/33] Uvicorn loguru format (#741) * use loguru formatting for uvicorn logs * remove depth from logging interceptor * format for uvicorn * black * isort * black again * python3-dev * python3-dev * leaner pipeline Co-authored-by: dni --- .env.example | 2 +- lnbits/app.py | 40 ++++++++++++++++++++++++++++++++-------- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/.env.example b/.env.example index 4d2241e3c..6ef60bc1c 100644 --- a/.env.example +++ b/.env.example @@ -1,7 +1,7 @@ HOST=127.0.0.1 PORT=5000 -DEBUG=true +DEBUG=false LNBITS_ALLOWED_USERS="" LNBITS_ADMIN_USERS="" diff --git a/lnbits/app.py b/lnbits/app.py index 9ab7c75d9..a7c8fdaf3 100644 --- a/lnbits/app.py +++ b/lnbits/app.py @@ -1,11 +1,9 @@ import asyncio import importlib +import logging import sys import traceback import warnings - -from loguru import logger - from http import HTTPStatus from fastapi import FastAPI, Request @@ -14,6 +12,7 @@ from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.gzip import GZipMiddleware from fastapi.responses import JSONResponse from fastapi.staticfiles import StaticFiles +from loguru import logger import lnbits.settings from lnbits.core.tasks import register_task_listeners @@ -199,8 +198,33 @@ def register_exception_handlers(app: FastAPI): def configure_logger() -> None: logger.remove() log_level: str = "DEBUG" if lnbits.settings.DEBUG else "INFO" - if lnbits.settings.DEBUG: - fmt: str = "{time:YYYY-MM-DD HH:mm:ss.SS} | {level: <6} | {name}:{function}:{line} | {message}" - else: - fmt: str = "{time:YYYY-MM-DD HH:mm:ss.SS} | {level} | {message}" - logger.add(sys.stderr, level=log_level, format=fmt) + formatter = Formatter() + logger.add(sys.stderr, level=log_level, format=formatter.format) + + logging.getLogger("uvicorn").handlers = [InterceptHandler()] + logging.getLogger("uvicorn.access").handlers = [InterceptHandler()] + + +class Formatter: + def __init__(self): + self.padding = 0 + self.minimal_fmt: str = "{time:YYYY-MM-DD HH:mm:ss.SS} | {level} | {message}\n" + if lnbits.settings.DEBUG: + self.fmt: str = "{time:YYYY-MM-DD HH:mm:ss.SS} | {level: <4} | {name}:{function}:{line} | {message}\n" + else: + self.fmt: str = self.minimal_fmt + + def format(self, record): + function = "{function}".format(**record) + if function == "emit": # uvicorn logs + return self.minimal_fmt + return self.fmt + + +class InterceptHandler(logging.Handler): + def emit(self, record): + try: + level = logger.level(record.levelname).name + except ValueError: + level = record.levelno + logger.log(level, record.getMessage()) From 99b6b9d71ce7be6261bcbb5f11ea2a3ff33bf198 Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Sat, 16 Jul 2022 14:10:43 +0200 Subject: [PATCH 09/33] CI: regtest with `LndRestWallet` and `CLightningWallet` (#738) * add regtest * test LndRestWallet * test CLightningWallet --- .github/workflows/regtest.yml | 97 +++++++++++++++++++++++++++++++++++ Makefile | 21 ++++++-- tests/mocks.py | 3 +- 3 files changed, 117 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/regtest.yml diff --git a/.github/workflows/regtest.yml b/.github/workflows/regtest.yml new file mode 100644 index 000000000..1df083b9f --- /dev/null +++ b/.github/workflows/regtest.yml @@ -0,0 +1,97 @@ +name: regtest + +on: pull_request + +jobs: + LndRestWallet: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.7] + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Setup Regtest + run: | + docker build -t lnbits-legend . + git clone https://github.com/lnbits/legend-regtest-enviroment.git docker + cd docker + source docker-scripts.sh + lnbits-regtest-start + echo "sleeping 60 seconds" + sleep 60 + echo "continue" + lnbits-regtest-init + bitcoin-cli-sim -generate 1 + lncli-sim 1 listpeers + sudo chmod -R a+rwx . + - name: Install dependencies + env: + VIRTUAL_ENV: ./venv + PATH: ${{ env.VIRTUAL_ENV }}/bin:${{ env.PATH }} + run: | + python -m venv ${{ env.VIRTUAL_ENV }} + ./venv/bin/python -m pip install --upgrade pip + ./venv/bin/pip install -r requirements.txt + ./venv/bin/pip install pylightning + ./venv/bin/pip install pytest pytest-asyncio pytest-cov requests mock + - name: Run tests + env: + PYTHONUNBUFFERED: 1 + PORT: 5123 + LNBITS_DATA_FOLDER: ./data + LNBITS_BACKEND_WALLET_CLASS: LndRestWallet + LND_REST_ENDPOINT: https://localhost:8081/ + LND_REST_CERT: docker/data/lnd-1/tls.cert + LND_REST_MACAROON: docker/data/lnd-1/data/chain/bitcoin/regtest/admin.macaroon + run: | + sudo chmod -R a+rwx . && rm -rf ./data && mkdir -p ./data + make test-real-wallet + CLightningWallet: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.7] + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Setup Regtest + run: | + docker build -t lnbits-legend . + git clone https://github.com/lnbits/legend-regtest-enviroment.git docker + cd docker + source docker-scripts.sh + lnbits-regtest-start + echo "sleeping 60 seconds" + sleep 60 + echo "continue" + lnbits-regtest-init + bitcoin-cli-sim -generate 1 + lncli-sim 1 listpeers + sudo chmod -R a+rwx . + - name: Install dependencies + env: + VIRTUAL_ENV: ./venv + PATH: ${{ env.VIRTUAL_ENV }}/bin:${{ env.PATH }} + run: | + python -m venv ${{ env.VIRTUAL_ENV }} + ./venv/bin/python -m pip install --upgrade pip + ./venv/bin/pip install -r requirements.txt + ./venv/bin/pip install pylightning + ./venv/bin/pip install pytest pytest-asyncio pytest-cov requests mock + - name: Run tests + env: + PYTHONUNBUFFERED: 1 + PORT: 5123 + LNBITS_DATA_FOLDER: ./data + LNBITS_BACKEND_WALLET_CLASS: CLightningWallet + CLIGHTNING_RPC: docker/data/clightning-1/regtest/lightning-rpc + run: | + sudo chmod -R a+rwx . && rm -rf ./data && mkdir -p ./data + make test-real-wallet \ No newline at end of file diff --git a/Makefile b/Makefile index 37c61b66f..5cc3f0509 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ all: format check requirements.txt -format: prettier black +format: prettier isort black check: mypy checkprettier checkblack @@ -17,12 +17,18 @@ mypy: $(shell find lnbits -name "*.py") ./venv/bin/mypy lnbits/core ./venv/bin/mypy lnbits/extensions/* +isort: $(shell find lnbits -name "*.py") + ./venv/bin/isort --profile black lnbits + checkprettier: $(shell find lnbits -name "*.js" -name ".html") ./node_modules/.bin/prettier --check lnbits/static/js/*.js lnbits/core/static/js/*.js lnbits/extensions/*/templates/*/*.html ./lnbits/core/templates/core/*.html lnbits/templates/*.html lnbits/extensions/*/static/js/*.js checkblack: $(shell find lnbits -name "*.py") ./venv/bin/black --check lnbits +checkisort: $(shell find lnbits -name "*.py") + ./venv/bin/isort --profile black --check-only lnbits + Pipfile.lock: Pipfile ./venv/bin/pipenv lock @@ -32,18 +38,27 @@ requirements.txt: Pipfile.lock test: rm -rf ./tests/data mkdir -p ./tests/data + LNBITS_BACKEND_WALLET_CLASS="FakeWallet" \ FAKE_WALLET_SECRET="ToTheMoon1" \ LNBITS_DATA_FOLDER="./tests/data" \ PYTHONUNBUFFERED=1 \ - ./venv/bin/pytest --durations=1 -s --cov=lnbits --cov-report=xml + ./venv/bin/pytest --durations=1 -s --cov=lnbits --cov-report=xml tests + +test-real-wallet: + rm -rf ./tests/data + mkdir -p ./tests/data + LNBITS_DATA_FOLDER="./tests/data" \ + PYTHONUNBUFFERED=1 \ + ./venv/bin/pytest --durations=1 -s --cov=lnbits --cov-report=xml tests test-pipenv: rm -rf ./tests/data mkdir -p ./tests/data + LNBITS_BACKEND_WALLET_CLASS="FakeWallet" \ FAKE_WALLET_SECRET="ToTheMoon1" \ LNBITS_DATA_FOLDER="./tests/data" \ PYTHONUNBUFFERED=1 \ - pipenv run pytest --durations=1 -s --cov=lnbits --cov-report=xml + pipenv run pytest --durations=1 -s --cov=lnbits --cov-report=xml tests bak: # LNBITS_DATABASE_URL=postgres://postgres:postgres@0.0.0.0:5432/postgres diff --git a/tests/mocks.py b/tests/mocks.py index eb08f20b2..c99691cbc 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -27,7 +27,8 @@ WALLET.status = AsyncMock( ) ) -WALLET.create_invoice = generate_mock_invoice +# Note: if this line is uncommented, invoices will always be generated by FakeWallet +# WALLET.create_invoice = generate_mock_invoice # NOTE: This mock fails since it yields the same invoice multiple # times which makes the db throw an error due to uniqueness contraints From 69516bb751610ccbafc2e057a9c176b1cca6fe43 Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Sat, 16 Jul 2022 14:17:45 +0200 Subject: [PATCH 10/33] regtest on push (#742) --- .github/workflows/regtest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/regtest.yml b/.github/workflows/regtest.yml index 1df083b9f..bdce0501b 100644 --- a/.github/workflows/regtest.yml +++ b/.github/workflows/regtest.yml @@ -1,6 +1,6 @@ name: regtest -on: pull_request +on: [push, pull_request] jobs: LndRestWallet: From f4e7d62ca3291e3c3395ee684433350bf721cfdc Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Sat, 16 Jul 2022 14:23:03 +0200 Subject: [PATCH 11/33] `make format` everything (#743) --- .github/workflows/formatting.yml | 12 +++++++++++- lnbits/__main__.py | 8 +++----- lnbits/bolt11.py | 15 ++++++++------- lnbits/commands.py | 13 +++++++------ lnbits/core/crud.py | 10 +++++----- lnbits/core/models.py | 14 +++++++------- lnbits/core/services.py | 4 +--- lnbits/core/tasks.py | 2 +- lnbits/core/views/api.py | 4 +--- lnbits/core/views/generic.py | 3 +-- lnbits/core/views/public_api.py | 3 +-- lnbits/db.py | 1 - lnbits/decorators.py | 4 ++-- lnbits/extensions/bleskomat/exchange_rates.py | 3 ++- lnbits/extensions/bleskomat/lnurl_api.py | 3 +-- lnbits/extensions/bleskomat/models.py | 5 ++--- lnbits/extensions/bleskomat/views_api.py | 3 +-- lnbits/extensions/copilot/models.py | 16 +++++++++------- lnbits/extensions/discordbot/models.py | 2 +- lnbits/extensions/jukebox/models.py | 6 +++--- lnbits/extensions/livestream/views.py | 4 ++-- lnbits/extensions/lnaddress/lnurl.py | 4 +--- lnbits/extensions/lndhub/decorators.py | 6 ++---- lnbits/extensions/lndhub/views.py | 6 ++++-- lnbits/extensions/lndhub/views_api.py | 5 ++--- lnbits/extensions/lnticket/crud.py | 7 ++++--- lnbits/extensions/lnticket/models.py | 1 + lnbits/extensions/lnurldevice/lnurl.py | 14 +++++--------- lnbits/extensions/lnurlp/crud.py | 3 ++- lnbits/extensions/lnurlp/models.py | 14 ++++++++------ lnbits/extensions/lnurlpayout/__init__.py | 1 + lnbits/extensions/lnurlpayout/crud.py | 2 +- lnbits/extensions/lnurlpayout/tasks.py | 2 -- lnbits/extensions/offlineshop/crud.py | 3 ++- lnbits/extensions/offlineshop/helpers.py | 2 +- lnbits/extensions/offlineshop/models.py | 7 ++++--- lnbits/extensions/offlineshop/views.py | 8 ++++---- lnbits/extensions/subdomains/cloudflare.py | 5 ++++- lnbits/extensions/tpos/__init__.py | 2 +- lnbits/extensions/tpos/views.py | 5 +---- lnbits/extensions/tpos/views_api.py | 3 +-- lnbits/extensions/usermanager/models.py | 2 +- lnbits/extensions/withdraw/lnurl.py | 6 ++---- lnbits/proxy_fix.py | 6 +++--- lnbits/tasks.py | 14 ++++++-------- lnbits/utils/exchange_rates.py | 3 +-- lnbits/wallets/base.py | 2 +- lnbits/wallets/clightning.py | 5 +++-- lnbits/wallets/eclair.py | 3 +-- lnbits/wallets/fake.py | 14 +++++++------- lnbits/wallets/lnbits.py | 6 +++--- lnbits/wallets/lnd_grpc_files/lightning_pb2.py | 2 +- lnbits/wallets/lndgrpc.py | 10 +++++----- lnbits/wallets/lndrest.py | 12 ++++++------ lnbits/wallets/lnpay.py | 12 ++++++------ lnbits/wallets/lntxbot.py | 6 +++--- lnbits/wallets/macaroon/__init__.py | 2 +- lnbits/wallets/macaroon/macaroon.py | 8 ++++---- lnbits/wallets/opennode.py | 14 +++++++------- lnbits/wallets/spark.py | 6 +++--- 60 files changed, 182 insertions(+), 186 deletions(-) diff --git a/.github/workflows/formatting.yml b/.github/workflows/formatting.yml index 18c8d5d68..23d7ae3e7 100644 --- a/.github/workflows/formatting.yml +++ b/.github/workflows/formatting.yml @@ -15,6 +15,16 @@ jobs: - run: python3 -m venv venv - run: ./venv/bin/pip install black - run: make checkblack + isort: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + - run: sudo apt-get install python3-venv + - run: python3 -m venv venv + - run: ./venv/bin/pip install isort + - run: make checkisort + prettier: runs-on: ubuntu-latest steps: @@ -23,4 +33,4 @@ jobs: - run: sudo apt-get install python3-venv - run: python3 -m venv venv - run: npm install prettier - - run: ./node_modules/.bin/prettier --check lnbits/static/js/*.js lnbits/core/static/js/*.js lnbits/extensions/*/templates/*/*.html ./lnbits/core/templates/core/*.html lnbits/templates/*.html lnbits/extensions/*/static/js/*.js \ No newline at end of file + - run: ./node_modules/.bin/prettier --check lnbits/static/js/*.js lnbits/core/static/js/*.js lnbits/extensions/*/templates/*/*.html ./lnbits/core/templates/core/*.html lnbits/templates/*.html lnbits/extensions/*/static/js/*.js diff --git a/lnbits/__main__.py b/lnbits/__main__.py index 93e2181c6..90464a64b 100644 --- a/lnbits/__main__.py +++ b/lnbits/__main__.py @@ -1,21 +1,19 @@ import asyncio import uvloop -from starlette.requests import Request - from loguru import logger +from starlette.requests import Request from .commands import bundle_vendored, migrate_databases, transpile_scss from .settings import ( DEBUG, + HOST, LNBITS_COMMIT, LNBITS_DATA_FOLDER, + LNBITS_DATABASE_URL, LNBITS_SITE_TITLE, - HOST, PORT, WALLET, - LNBITS_DATABASE_URL, - LNBITS_DATA_FOLDER, ) uvloop.install() diff --git a/lnbits/bolt11.py b/lnbits/bolt11.py index e52219840..cc8415852 100644 --- a/lnbits/bolt11.py +++ b/lnbits/bolt11.py @@ -1,15 +1,16 @@ -import bitstring # type: ignore -import re import hashlib -from typing import List, NamedTuple, Optional -from bech32 import bech32_encode, bech32_decode, CHARSET -from ecdsa import SECP256k1, VerifyingKey # type: ignore -from ecdsa.util import sigdecode_string # type: ignore -from binascii import unhexlify +import re import time +from binascii import unhexlify from decimal import Decimal +from typing import List, NamedTuple, Optional + +import bitstring # type: ignore import embit import secp256k1 +from bech32 import CHARSET, bech32_decode, bech32_encode +from ecdsa import SECP256k1, VerifyingKey # type: ignore +from ecdsa.util import sigdecode_string # type: ignore class Route(NamedTuple): diff --git a/lnbits/commands.py b/lnbits/commands.py index 13e926e84..0f7454f23 100644 --- a/lnbits/commands.py +++ b/lnbits/commands.py @@ -1,18 +1,19 @@ import asyncio -import warnings -import click import importlib -import re import os +import re +import warnings +import click from loguru import logger -from .db import SQLITE, POSTGRES, COCKROACH -from .core import db as core_db, migrations as core_migrations +from .core import db as core_db +from .core import migrations as core_migrations +from .db import COCKROACH, POSTGRES, SQLITE from .helpers import ( - get_valid_extensions, get_css_vendored, get_js_vendored, + get_valid_extensions, url_for_vendored, ) from .settings import LNBITS_PATH diff --git a/lnbits/core/crud.py b/lnbits/core/crud.py index 1493d4e4d..770e2906a 100644 --- a/lnbits/core/crud.py +++ b/lnbits/core/crud.py @@ -1,15 +1,15 @@ -import json import datetime -from uuid import uuid4 -from typing import List, Optional, Dict, Any +import json +from typing import Any, Dict, List, Optional from urllib.parse import urlparse +from uuid import uuid4 from lnbits import bolt11 -from lnbits.db import Connection, POSTGRES, COCKROACH +from lnbits.db import COCKROACH, POSTGRES, Connection from lnbits.settings import DEFAULT_WALLET_NAME, LNBITS_ADMIN_USERS from . import db -from .models import User, Wallet, Payment, BalanceCheck +from .models import BalanceCheck, Payment, User, Wallet # accounts # -------- diff --git a/lnbits/core/models.py b/lnbits/core/models.py index a6cdb23bd..ab73b7020 100644 --- a/lnbits/core/models.py +++ b/lnbits/core/models.py @@ -1,15 +1,15 @@ -import json -import hmac import hashlib -from lnbits.helpers import url_for +import hmac +import json +from sqlite3 import Row +from typing import Dict, List, NamedTuple, Optional + from ecdsa import SECP256k1, SigningKey # type: ignore from lnurl import encode as lnurl_encode # type: ignore -from typing import List, NamedTuple, Optional, Dict -from sqlite3 import Row +from loguru import logger from pydantic import BaseModel -from loguru import logger - +from lnbits.helpers import url_for from lnbits.settings import WALLET diff --git a/lnbits/core/services.py b/lnbits/core/services.py index 6a24348eb..84bc98e3b 100644 --- a/lnbits/core/services.py +++ b/lnbits/core/services.py @@ -3,14 +3,12 @@ import json from binascii import unhexlify from io import BytesIO from typing import Dict, Optional, Tuple - -from loguru import logger - from urllib.parse import parse_qs, urlparse import httpx from lnurl import LnurlErrorResponse from lnurl import decode as decode_lnurl # type: ignore +from loguru import logger from lnbits import bolt11 from lnbits.db import Connection diff --git a/lnbits/core/tasks.py b/lnbits/core/tasks.py index bb258958a..5fea769d4 100644 --- a/lnbits/core/tasks.py +++ b/lnbits/core/tasks.py @@ -1,7 +1,7 @@ import asyncio -import httpx from typing import List +import httpx from loguru import logger from lnbits.tasks import register_invoice_listener diff --git a/lnbits/core/views/api.py b/lnbits/core/views/api.py index 2a4cc3e80..f5b580414 100644 --- a/lnbits/core/views/api.py +++ b/lnbits/core/views/api.py @@ -7,13 +7,11 @@ from typing import Dict, List, Optional, Union from urllib.parse import ParseResult, parse_qs, urlencode, urlparse, urlunparse import httpx - -from loguru import logger - from fastapi import Header, Query, Request from fastapi.exceptions import HTTPException from fastapi.param_functions import Depends from fastapi.params import Body +from loguru import logger from pydantic import BaseModel from pydantic.fields import Field from sse_starlette.sse import EventSourceResponse diff --git a/lnbits/core/views/generic.py b/lnbits/core/views/generic.py index b6750c95f..4366028d7 100644 --- a/lnbits/core/views/generic.py +++ b/lnbits/core/views/generic.py @@ -7,11 +7,10 @@ from fastapi.exceptions import HTTPException from fastapi.params import Depends, Query from fastapi.responses import FileResponse, RedirectResponse from fastapi.routing import APIRouter +from loguru import logger from pydantic.types import UUID4 from starlette.responses import HTMLResponse, JSONResponse -from loguru import logger - from lnbits.core import db from lnbits.core.models import User from lnbits.decorators import check_user_exists diff --git a/lnbits/core/views/public_api.py b/lnbits/core/views/public_api.py index 0b84243e1..2d2cdd66c 100644 --- a/lnbits/core/views/public_api.py +++ b/lnbits/core/views/public_api.py @@ -4,11 +4,10 @@ from http import HTTPStatus from urllib.parse import urlparse from fastapi import HTTPException +from loguru import logger from starlette.requests import Request from starlette.responses import HTMLResponse -from loguru import logger - from lnbits import bolt11 from .. import core_app diff --git a/lnbits/db.py b/lnbits/db.py index bed9397fa..669817842 100644 --- a/lnbits/db.py +++ b/lnbits/db.py @@ -6,7 +6,6 @@ from contextlib import asynccontextmanager from typing import Optional from loguru import logger - from sqlalchemy import create_engine from sqlalchemy_aio.base import AsyncConnection from sqlalchemy_aio.strategy import ASYNCIO_STRATEGY # type: ignore diff --git a/lnbits/decorators.py b/lnbits/decorators.py index d6f73f406..e65b9041a 100644 --- a/lnbits/decorators.py +++ b/lnbits/decorators.py @@ -14,9 +14,9 @@ from lnbits.core.crud import get_user, get_wallet_for_key from lnbits.core.models import User, Wallet from lnbits.requestvars import g from lnbits.settings import ( - LNBITS_ALLOWED_USERS, - LNBITS_ADMIN_USERS, LNBITS_ADMIN_EXTENSIONS, + LNBITS_ADMIN_USERS, + LNBITS_ALLOWED_USERS, ) diff --git a/lnbits/extensions/bleskomat/exchange_rates.py b/lnbits/extensions/bleskomat/exchange_rates.py index dcdaa2205..e5eb843f7 100644 --- a/lnbits/extensions/bleskomat/exchange_rates.py +++ b/lnbits/extensions/bleskomat/exchange_rates.py @@ -1,7 +1,8 @@ -import httpx import json import os +import httpx + fiat_currencies = json.load( open( os.path.join( diff --git a/lnbits/extensions/bleskomat/lnurl_api.py b/lnbits/extensions/bleskomat/lnurl_api.py index 212f9b4a9..33e33a700 100644 --- a/lnbits/extensions/bleskomat/lnurl_api.py +++ b/lnbits/extensions/bleskomat/lnurl_api.py @@ -3,9 +3,8 @@ import math import traceback from http import HTTPStatus -from starlette.requests import Request - from loguru import logger +from starlette.requests import Request from . import bleskomat_ext from .crud import ( diff --git a/lnbits/extensions/bleskomat/models.py b/lnbits/extensions/bleskomat/models.py index ab952b55e..364cbe223 100644 --- a/lnbits/extensions/bleskomat/models.py +++ b/lnbits/extensions/bleskomat/models.py @@ -3,13 +3,12 @@ import time from typing import Dict from fastapi.params import Query +from loguru import logger from pydantic import BaseModel, validator from starlette.requests import Request -from loguru import logger - from lnbits import bolt11 -from lnbits.core.services import pay_invoice, PaymentFailure +from lnbits.core.services import PaymentFailure, pay_invoice from . import db from .exchange_rates import exchange_rate_providers, fiat_currencies diff --git a/lnbits/extensions/bleskomat/views_api.py b/lnbits/extensions/bleskomat/views_api.py index 81efa4abf..e29e3fe76 100644 --- a/lnbits/extensions/bleskomat/views_api.py +++ b/lnbits/extensions/bleskomat/views_api.py @@ -1,9 +1,8 @@ from http import HTTPStatus from fastapi import Depends, Query -from starlette.exceptions import HTTPException - from loguru import logger +from starlette.exceptions import HTTPException from lnbits.core.crud import get_user from lnbits.decorators import WalletTypeInfo, require_admin_key diff --git a/lnbits/extensions/copilot/models.py b/lnbits/extensions/copilot/models.py index a279879dc..b9b43ccfb 100644 --- a/lnbits/extensions/copilot/models.py +++ b/lnbits/extensions/copilot/models.py @@ -1,12 +1,14 @@ -from urllib.parse import urlparse, urlunparse, parse_qs, urlencode, ParseResult -from starlette.requests import Request -from fastapi.param_functions import Query -from typing import Optional, Dict -from lnbits.lnurl import encode as lnurl_encode # type: ignore -from lnurl.types import LnurlPayMetadata # type: ignore -from pydantic import BaseModel import json from sqlite3 import Row +from typing import Dict, Optional +from urllib.parse import ParseResult, parse_qs, urlencode, urlparse, urlunparse + +from fastapi.param_functions import Query +from lnurl.types import LnurlPayMetadata # type: ignore +from pydantic import BaseModel +from starlette.requests import Request + +from lnbits.lnurl import encode as lnurl_encode # type: ignore class CreateCopilotData(BaseModel): diff --git a/lnbits/extensions/discordbot/models.py b/lnbits/extensions/discordbot/models.py index 985eb096f..8b9cd822a 100644 --- a/lnbits/extensions/discordbot/models.py +++ b/lnbits/extensions/discordbot/models.py @@ -1,8 +1,8 @@ from sqlite3 import Row +from typing import Optional from fastapi.param_functions import Query from pydantic import BaseModel -from typing import Optional class CreateUserData(BaseModel): diff --git a/lnbits/extensions/jukebox/models.py b/lnbits/extensions/jukebox/models.py index 093961e42..90984b036 100644 --- a/lnbits/extensions/jukebox/models.py +++ b/lnbits/extensions/jukebox/models.py @@ -1,9 +1,9 @@ -from typing import NamedTuple from sqlite3 import Row +from typing import NamedTuple, Optional + from fastapi.param_functions import Query -from pydantic.main import BaseModel from pydantic import BaseModel -from typing import Optional +from pydantic.main import BaseModel class CreateJukeLinkData(BaseModel): diff --git a/lnbits/extensions/livestream/views.py b/lnbits/extensions/livestream/views.py index ef0354315..97f803a31 100644 --- a/lnbits/extensions/livestream/views.py +++ b/lnbits/extensions/livestream/views.py @@ -1,7 +1,5 @@ from http import HTTPStatus -# from mmap import MAP_DENYWRITE - from fastapi.param_functions import Depends from fastapi.params import Query from starlette.exceptions import HTTPException @@ -15,6 +13,8 @@ from lnbits.decorators import check_user_exists from . import livestream_ext, livestream_renderer from .crud import get_livestream_by_track, get_track +# from mmap import MAP_DENYWRITE + @livestream_ext.get("/", response_class=HTMLResponse) async def index(request: Request, user: User = Depends(check_user_exists)): diff --git a/lnbits/extensions/lnaddress/lnurl.py b/lnbits/extensions/lnaddress/lnurl.py index 2b064e0a1..e6a1ff486 100644 --- a/lnbits/extensions/lnaddress/lnurl.py +++ b/lnbits/extensions/lnaddress/lnurl.py @@ -3,15 +3,13 @@ import json from datetime import datetime, timedelta import httpx - -from loguru import logger - from fastapi.params import Query from lnurl import ( # type: ignore LnurlErrorResponse, LnurlPayActionResponse, LnurlPayResponse, ) +from loguru import logger from starlette.requests import Request from starlette.responses import HTMLResponse diff --git a/lnbits/extensions/lndhub/decorators.py b/lnbits/extensions/lndhub/decorators.py index 149311643..4698e9b90 100644 --- a/lnbits/extensions/lndhub/decorators.py +++ b/lnbits/extensions/lndhub/decorators.py @@ -1,14 +1,12 @@ from base64 import b64decode -from fastapi.param_functions import Security - -from fastapi.security.api_key import APIKeyHeader from fastapi import Request, status +from fastapi.param_functions import Security +from fastapi.security.api_key import APIKeyHeader from starlette.exceptions import HTTPException from lnbits.decorators import WalletTypeInfo, get_key_type # type: ignore - api_key_header_auth = APIKeyHeader( name="AUTHORIZATION", auto_error=False, diff --git a/lnbits/extensions/lndhub/views.py b/lnbits/extensions/lndhub/views.py index 4b015c09f..38a33a34a 100644 --- a/lnbits/extensions/lndhub/views.py +++ b/lnbits/extensions/lndhub/views.py @@ -1,8 +1,10 @@ -from lnbits.decorators import check_user_exists -from . import lndhub_ext, lndhub_renderer from fastapi import Request from fastapi.params import Depends + from lnbits.core.models import User +from lnbits.decorators import check_user_exists + +from . import lndhub_ext, lndhub_renderer @lndhub_ext.get("/") diff --git a/lnbits/extensions/lndhub/views_api.py b/lnbits/extensions/lndhub/views_api.py index 8cbf5b01c..a3160fa9a 100644 --- a/lnbits/extensions/lndhub/views_api.py +++ b/lnbits/extensions/lndhub/views_api.py @@ -1,6 +1,5 @@ -import time import asyncio - +import time from base64 import urlsafe_b64encode from http import HTTPStatus @@ -13,7 +12,7 @@ from lnbits import bolt11 from lnbits.core.crud import delete_expired_invoices, get_payments from lnbits.core.services import create_invoice, pay_invoice from lnbits.decorators import WalletTypeInfo -from lnbits.settings import WALLET, LNBITS_SITE_TITLE +from lnbits.settings import LNBITS_SITE_TITLE, WALLET from . import lndhub_ext from .decorators import check_wallet, require_admin_key diff --git a/lnbits/extensions/lnticket/crud.py b/lnbits/extensions/lnticket/crud.py index 8fe170905..3254ad438 100644 --- a/lnbits/extensions/lnticket/crud.py +++ b/lnbits/extensions/lnticket/crud.py @@ -1,11 +1,12 @@ -from lnbits.core.models import Wallet from typing import List, Optional, Union +import httpx + +from lnbits.core.models import Wallet from lnbits.helpers import urlsafe_short_hash from . import db -from .models import CreateFormData, CreateTicketData, Tickets, Forms -import httpx +from .models import CreateFormData, CreateTicketData, Forms, Tickets async def create_ticket( diff --git a/lnbits/extensions/lnticket/models.py b/lnbits/extensions/lnticket/models.py index 50ffc1e1d..a7a3cf8c3 100644 --- a/lnbits/extensions/lnticket/models.py +++ b/lnbits/extensions/lnticket/models.py @@ -1,4 +1,5 @@ from typing import Optional + from fastapi.param_functions import Query from pydantic import BaseModel diff --git a/lnbits/extensions/lnurldevice/lnurl.py b/lnbits/extensions/lnurldevice/lnurl.py index 26a127f19..5e25dadbe 100644 --- a/lnbits/extensions/lnurldevice/lnurl.py +++ b/lnbits/extensions/lnurldevice/lnurl.py @@ -1,30 +1,26 @@ import base64 import hashlib +import hmac from http import HTTPStatus +from io import BytesIO from typing import Optional -from embit import bech32 -from embit import compact -import base64 -from io import BytesIO -import hmac - +from embit import bech32, compact from fastapi import Request from fastapi.param_functions import Query from starlette.exceptions import HTTPException from lnbits.core.services import create_invoice -from lnbits.utils.exchange_rates import fiat_amount_as_satoshis 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, - update_lnurldevicepayment, get_lnurlpayload, + update_lnurldevicepayment, ) diff --git a/lnbits/extensions/lnurlp/crud.py b/lnbits/extensions/lnurlp/crud.py index c70465881..9cb01fdef 100644 --- a/lnbits/extensions/lnurlp/crud.py +++ b/lnbits/extensions/lnurlp/crud.py @@ -1,8 +1,9 @@ from typing import List, Optional, Union from lnbits.db import SQLITE + from . import db -from .models import PayLink, CreatePayLinkData +from .models import CreatePayLinkData, PayLink async def create_pay_link(data: CreatePayLinkData, wallet_id: str) -> PayLink: diff --git a/lnbits/extensions/lnurlp/models.py b/lnbits/extensions/lnurlp/models.py index bd121cc84..4bd438a4f 100644 --- a/lnbits/extensions/lnurlp/models.py +++ b/lnbits/extensions/lnurlp/models.py @@ -1,12 +1,14 @@ import json -from urllib.parse import urlparse, urlunparse, parse_qs, urlencode, ParseResult -from starlette.requests import Request -from fastapi.param_functions import Query -from typing import Optional, Dict -from lnbits.lnurl import encode as lnurl_encode # type: ignore -from lnurl.types import LnurlPayMetadata # type: ignore from sqlite3 import Row +from typing import Dict, Optional +from urllib.parse import ParseResult, parse_qs, urlencode, urlparse, urlunparse + +from fastapi.param_functions import Query +from lnurl.types import LnurlPayMetadata # type: ignore from pydantic import BaseModel +from starlette.requests import Request + +from lnbits.lnurl import encode as lnurl_encode # type: ignore class CreatePayLinkData(BaseModel): diff --git a/lnbits/extensions/lnurlpayout/__init__.py b/lnbits/extensions/lnurlpayout/__init__.py index 1626e2e53..9962290cd 100644 --- a/lnbits/extensions/lnurlpayout/__init__.py +++ b/lnbits/extensions/lnurlpayout/__init__.py @@ -1,4 +1,5 @@ import asyncio + from fastapi import APIRouter from lnbits.db import Database diff --git a/lnbits/extensions/lnurlpayout/crud.py b/lnbits/extensions/lnurlpayout/crud.py index 6cbf6c547..0f9f98acb 100644 --- a/lnbits/extensions/lnurlpayout/crud.py +++ b/lnbits/extensions/lnurlpayout/crud.py @@ -3,7 +3,7 @@ from typing import List, Optional, Union from lnbits.helpers import urlsafe_short_hash from . import db -from .models import lnurlpayout, CreateLnurlPayoutData +from .models import CreateLnurlPayoutData, lnurlpayout async def create_lnurlpayout( diff --git a/lnbits/extensions/lnurlpayout/tasks.py b/lnbits/extensions/lnurlpayout/tasks.py index d2b3809b4..b621876cb 100644 --- a/lnbits/extensions/lnurlpayout/tasks.py +++ b/lnbits/extensions/lnurlpayout/tasks.py @@ -2,9 +2,7 @@ import asyncio from http import HTTPStatus import httpx - from loguru import logger - from starlette.exceptions import HTTPException from lnbits.core import db as core_db diff --git a/lnbits/extensions/offlineshop/crud.py b/lnbits/extensions/offlineshop/crud.py index 0ecb3d526..bc4f3f14a 100644 --- a/lnbits/extensions/offlineshop/crud.py +++ b/lnbits/extensions/offlineshop/crud.py @@ -1,9 +1,10 @@ from typing import List, Optional from lnbits.db import SQLITE + from . import db +from .models import Item, Shop from .wordlists import animals -from .models import Shop, Item async def create_shop(*, wallet_id: str) -> int: diff --git a/lnbits/extensions/offlineshop/helpers.py b/lnbits/extensions/offlineshop/helpers.py index 6b56cf559..86a653aa2 100644 --- a/lnbits/extensions/offlineshop/helpers.py +++ b/lnbits/extensions/offlineshop/helpers.py @@ -1,6 +1,6 @@ import base64 -import struct import hmac +import struct import time diff --git a/lnbits/extensions/offlineshop/models.py b/lnbits/extensions/offlineshop/models.py index 06225351c..0128fdb84 100644 --- a/lnbits/extensions/offlineshop/models.py +++ b/lnbits/extensions/offlineshop/models.py @@ -1,14 +1,15 @@ -import json import base64 import hashlib +import json from collections import OrderedDict +from typing import Dict, List, Optional -from typing import Optional, List, Dict from lnurl import encode as lnurl_encode # type: ignore -from lnurl.types import LnurlPayMetadata # type: ignore from lnurl.models import LnurlPaySuccessAction, UrlAction # type: ignore +from lnurl.types import LnurlPayMetadata # type: ignore from pydantic import BaseModel from starlette.requests import Request + from .helpers import totp shop_counters: Dict = {} diff --git a/lnbits/extensions/offlineshop/views.py b/lnbits/extensions/offlineshop/views.py index e1d3a66e3..34bb7a03e 100644 --- a/lnbits/extensions/offlineshop/views.py +++ b/lnbits/extensions/offlineshop/views.py @@ -3,18 +3,18 @@ from datetime import datetime from http import HTTPStatus from typing import List +from fastapi import HTTPException, Request from fastapi.params import Depends, Query from starlette.responses import HTMLResponse -from lnbits.decorators import check_user_exists -from lnbits.core.models import Payment, User from lnbits.core.crud import get_standalone_payment +from lnbits.core.models import Payment, User from lnbits.core.views.api import api_payment +from lnbits.decorators import check_user_exists from . import offlineshop_ext, offlineshop_renderer -from .models import Item from .crud import get_item, get_shop -from fastapi import Request, HTTPException +from .models import Item @offlineshop_ext.get("/", response_class=HTMLResponse) diff --git a/lnbits/extensions/subdomains/cloudflare.py b/lnbits/extensions/subdomains/cloudflare.py index 8ada2a908..679ca8436 100644 --- a/lnbits/extensions/subdomains/cloudflare.py +++ b/lnbits/extensions/subdomains/cloudflare.py @@ -1,5 +1,8 @@ +import json + +import httpx + from lnbits.extensions.subdomains.models import Domains -import httpx, json async def cloudflare_create_subdomain( diff --git a/lnbits/extensions/tpos/__init__.py b/lnbits/extensions/tpos/__init__.py index 1aed95bac..3ce618aa6 100644 --- a/lnbits/extensions/tpos/__init__.py +++ b/lnbits/extensions/tpos/__init__.py @@ -16,8 +16,8 @@ def tpos_renderer(): from .tasks import wait_for_paid_invoices -from .views_api import * # noqa from .views import * # noqa +from .views_api import * # noqa def tpos_start(): diff --git a/lnbits/extensions/tpos/views.py b/lnbits/extensions/tpos/views.py index 21a471c4a..e1f1d21e3 100644 --- a/lnbits/extensions/tpos/views.py +++ b/lnbits/extensions/tpos/views.py @@ -8,10 +8,7 @@ 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 lnbits.settings import LNBITS_CUSTOM_LOGO, LNBITS_SITE_TITLE from . import tpos_ext, tpos_renderer from .crud import get_tpos diff --git a/lnbits/extensions/tpos/views_api.py b/lnbits/extensions/tpos/views_api.py index 6a4e5c43e..9567f98a6 100644 --- a/lnbits/extensions/tpos/views_api.py +++ b/lnbits/extensions/tpos/views_api.py @@ -2,9 +2,8 @@ from http import HTTPStatus from fastapi import Query from fastapi.params import Depends -from starlette.exceptions import HTTPException - from loguru import logger +from starlette.exceptions import HTTPException from lnbits.core.crud import get_user from lnbits.core.services import create_invoice diff --git a/lnbits/extensions/usermanager/models.py b/lnbits/extensions/usermanager/models.py index 67facec68..15f50e288 100644 --- a/lnbits/extensions/usermanager/models.py +++ b/lnbits/extensions/usermanager/models.py @@ -1,8 +1,8 @@ from sqlite3 import Row +from typing import Optional from fastapi.param_functions import Query from pydantic import BaseModel -from typing import Optional class CreateUserData(BaseModel): diff --git a/lnbits/extensions/withdraw/lnurl.py b/lnbits/extensions/withdraw/lnurl.py index 05b3908c2..18a99599c 100644 --- a/lnbits/extensions/withdraw/lnurl.py +++ b/lnbits/extensions/withdraw/lnurl.py @@ -1,15 +1,13 @@ import json import traceback -import httpx - from datetime import datetime from http import HTTPStatus -from loguru import logger - +import httpx import shortuuid # type: ignore 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 diff --git a/lnbits/proxy_fix.py b/lnbits/proxy_fix.py index ec2a85b1a..897835e0d 100644 --- a/lnbits/proxy_fix.py +++ b/lnbits/proxy_fix.py @@ -1,11 +1,11 @@ -from typing import Optional, List, Callable from functools import partial -from urllib.request import parse_http_list as _parse_list_header +from typing import Callable, List, Optional from urllib.parse import urlparse -from werkzeug.datastructures import Headers +from urllib.request import parse_http_list as _parse_list_header from quart import Request from quart_trio.asgi import TrioASGIHTTPConnection +from werkzeug.datastructures import Headers class ASGIProxyFix(TrioASGIHTTPConnection): diff --git a/lnbits/tasks.py b/lnbits/tasks.py index 69aa19066..86863f98f 100644 --- a/lnbits/tasks.py +++ b/lnbits/tasks.py @@ -1,22 +1,20 @@ -import time import asyncio +import time import traceback from http import HTTPStatus -from typing import List, Callable - -from loguru import logger +from typing import Callable, List from fastapi.exceptions import HTTPException +from loguru import logger -from lnbits.settings import WALLET from lnbits.core.crud import ( - get_payments, - get_standalone_payment, delete_expired_invoices, get_balance_checks, + get_payments, + get_standalone_payment, ) from lnbits.core.services import redeem_lnurl_withdraw - +from lnbits.settings import WALLET deferred_async: List[Callable] = [] diff --git a/lnbits/utils/exchange_rates.py b/lnbits/utils/exchange_rates.py index b836a9091..cec0216a7 100644 --- a/lnbits/utils/exchange_rates.py +++ b/lnbits/utils/exchange_rates.py @@ -1,9 +1,8 @@ import asyncio from typing import Callable, NamedTuple -from loguru import logger - import httpx +from loguru import logger currencies = { "AED": "United Arab Emirates Dirham", diff --git a/lnbits/wallets/base.py b/lnbits/wallets/base.py index 39c687594..f35eb3704 100644 --- a/lnbits/wallets/base.py +++ b/lnbits/wallets/base.py @@ -1,5 +1,5 @@ from abc import ABC, abstractmethod -from typing import NamedTuple, Optional, AsyncGenerator, Coroutine +from typing import AsyncGenerator, Coroutine, NamedTuple, Optional class StatusResponse(NamedTuple): diff --git a/lnbits/wallets/clightning.py b/lnbits/wallets/clightning.py index f8c2b16cf..fc79b3e32 100644 --- a/lnbits/wallets/clightning.py +++ b/lnbits/wallets/clightning.py @@ -5,10 +5,12 @@ except ImportError: # pragma: nocover import asyncio import random +import time from functools import partial, wraps from os import getenv from typing import AsyncGenerator, Optional -import time + +from lnbits import bolt11 as lnbits_bolt11 from .base import ( InvoiceResponse, @@ -18,7 +20,6 @@ from .base import ( Unsupported, Wallet, ) -from lnbits import bolt11 as lnbits_bolt11 def async_wrap(func): diff --git a/lnbits/wallets/eclair.py b/lnbits/wallets/eclair.py index 9ae910e93..0ac3fd2a0 100644 --- a/lnbits/wallets/eclair.py +++ b/lnbits/wallets/eclair.py @@ -5,9 +5,8 @@ import urllib.parse from os import getenv from typing import AsyncGenerator, Dict, Optional -from loguru import logger - import httpx +from loguru import logger from websockets import connect from websockets.exceptions import ( ConnectionClosed, diff --git a/lnbits/wallets/fake.py b/lnbits/wallets/fake.py index 635e75108..ff64bd613 100644 --- a/lnbits/wallets/fake.py +++ b/lnbits/wallets/fake.py @@ -1,20 +1,20 @@ import asyncio - -from os import getenv -from datetime import datetime -from typing import Optional, Dict, AsyncGenerator +import hashlib import random +from datetime import datetime +from os import getenv +from typing import AsyncGenerator, Dict, Optional from loguru import logger from lnbits.helpers import urlsafe_short_hash -import hashlib -from ..bolt11 import encode, decode + +from ..bolt11 import decode, encode from .base import ( - StatusResponse, InvoiceResponse, PaymentResponse, PaymentStatus, + StatusResponse, Wallet, ) diff --git a/lnbits/wallets/lnbits.py b/lnbits/wallets/lnbits.py index 7af252983..551861961 100644 --- a/lnbits/wallets/lnbits.py +++ b/lnbits/wallets/lnbits.py @@ -1,16 +1,16 @@ import asyncio import json -import httpx from os import getenv -from typing import Optional, Dict, AsyncGenerator +from typing import AsyncGenerator, Dict, Optional +import httpx from loguru import logger from .base import ( - StatusResponse, InvoiceResponse, PaymentResponse, PaymentStatus, + StatusResponse, Wallet, ) diff --git a/lnbits/wallets/lnd_grpc_files/lightning_pb2.py b/lnbits/wallets/lnd_grpc_files/lightning_pb2.py index 6a1cf8fe3..9065e3f68 100644 --- a/lnbits/wallets/lnd_grpc_files/lightning_pb2.py +++ b/lnbits/wallets/lnd_grpc_files/lightning_pb2.py @@ -2,11 +2,11 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # source: lightning.proto """Generated protocol buffer code.""" -from google.protobuf.internal import enum_type_wrapper from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import enum_type_wrapper # @@protoc_insertion_point(imports) diff --git a/lnbits/wallets/lndgrpc.py b/lnbits/wallets/lndgrpc.py index 137d4e33b..44fee78c3 100644 --- a/lnbits/wallets/lndgrpc.py +++ b/lnbits/wallets/lndgrpc.py @@ -1,30 +1,30 @@ imports_ok = True try: - from google import protobuf import grpc + from google import protobuf except ImportError: # pragma: nocover imports_ok = False -import binascii import base64 +import binascii import hashlib from os import environ, error, getenv -from typing import Optional, Dict, AsyncGenerator +from typing import AsyncGenerator, Dict, Optional from loguru import logger -from .macaroon import load_macaroon, AESCipher +from .macaroon import AESCipher, load_macaroon if imports_ok: import lnbits.wallets.lnd_grpc_files.lightning_pb2 as ln import lnbits.wallets.lnd_grpc_files.lightning_pb2_grpc as lnrpc from .base import ( - StatusResponse, InvoiceResponse, PaymentResponse, PaymentStatus, + StatusResponse, Wallet, ) diff --git a/lnbits/wallets/lndrest.py b/lnbits/wallets/lndrest.py index 3cf5d5b75..56d18dc42 100644 --- a/lnbits/wallets/lndrest.py +++ b/lnbits/wallets/lndrest.py @@ -1,23 +1,23 @@ import asyncio -from pydoc import describe -import httpx -import json import base64 +import json from os import getenv -from typing import Optional, Dict, AsyncGenerator +from pydoc import describe +from typing import AsyncGenerator, Dict, Optional +import httpx from loguru import logger from lnbits import bolt11 as lnbits_bolt11 -from .macaroon import load_macaroon, AESCipher from .base import ( - StatusResponse, InvoiceResponse, PaymentResponse, PaymentStatus, + StatusResponse, Wallet, ) +from .macaroon import AESCipher, load_macaroon class LndRestWallet(Wallet): diff --git a/lnbits/wallets/lnpay.py b/lnbits/wallets/lnpay.py index 7089241e1..807d72538 100644 --- a/lnbits/wallets/lnpay.py +++ b/lnbits/wallets/lnpay.py @@ -1,18 +1,18 @@ -import json import asyncio -from fastapi.exceptions import HTTPException -import httpx -from os import getenv +import json from http import HTTPStatus -from typing import Optional, Dict, AsyncGenerator +from os import getenv +from typing import AsyncGenerator, Dict, Optional +import httpx +from fastapi.exceptions import HTTPException from loguru import logger from .base import ( - StatusResponse, InvoiceResponse, PaymentResponse, PaymentStatus, + StatusResponse, Wallet, ) diff --git a/lnbits/wallets/lntxbot.py b/lnbits/wallets/lntxbot.py index 3ec571ec9..47a1f6c1b 100644 --- a/lnbits/wallets/lntxbot.py +++ b/lnbits/wallets/lntxbot.py @@ -1,16 +1,16 @@ import asyncio import json -import httpx from os import getenv -from typing import Optional, Dict, AsyncGenerator +from typing import AsyncGenerator, Dict, Optional +import httpx from loguru import logger from .base import ( - StatusResponse, InvoiceResponse, PaymentResponse, PaymentStatus, + StatusResponse, Wallet, ) diff --git a/lnbits/wallets/macaroon/__init__.py b/lnbits/wallets/macaroon/__init__.py index 4967c1008..16617aa65 100644 --- a/lnbits/wallets/macaroon/__init__.py +++ b/lnbits/wallets/macaroon/__init__.py @@ -1 +1 @@ -from .macaroon import load_macaroon, AESCipher +from .macaroon import AESCipher, load_macaroon diff --git a/lnbits/wallets/macaroon/macaroon.py b/lnbits/wallets/macaroon/macaroon.py index 5e62da0cf..2183dacb8 100644 --- a/lnbits/wallets/macaroon/macaroon.py +++ b/lnbits/wallets/macaroon/macaroon.py @@ -1,9 +1,9 @@ +import base64 +import getpass +from hashlib import md5 + from Cryptodome import Random from Cryptodome.Cipher import AES -import base64 -from hashlib import md5 -import getpass - from loguru import logger BLOCK_SIZE = 16 diff --git a/lnbits/wallets/opennode.py b/lnbits/wallets/opennode.py index f1008e626..6d3fb02c9 100644 --- a/lnbits/wallets/opennode.py +++ b/lnbits/wallets/opennode.py @@ -1,22 +1,22 @@ import asyncio - -from fastapi.exceptions import HTTPException -from lnbits.helpers import url_for import hmac -import httpx from http import HTTPStatus from os import getenv -from typing import Optional, AsyncGenerator +from typing import AsyncGenerator, Optional +import httpx +from fastapi.exceptions import HTTPException from loguru import logger +from lnbits.helpers import url_for + from .base import ( - StatusResponse, InvoiceResponse, PaymentResponse, PaymentStatus, - Wallet, + StatusResponse, Unsupported, + Wallet, ) diff --git a/lnbits/wallets/spark.py b/lnbits/wallets/spark.py index d12addc4c..142e388d2 100644 --- a/lnbits/wallets/spark.py +++ b/lnbits/wallets/spark.py @@ -1,17 +1,17 @@ import asyncio import json -import httpx import random from os import getenv -from typing import Optional, AsyncGenerator +from typing import AsyncGenerator, Optional +import httpx from loguru import logger from .base import ( - StatusResponse, InvoiceResponse, PaymentResponse, PaymentStatus, + StatusResponse, Wallet, ) From ad2aad05e00ca4457ea008684bfbfb0852fcbfd5 Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Sun, 17 Jul 2022 13:11:13 +0200 Subject: [PATCH 12/33] CI: Migration SQLite to PostgreSQL (#719) * migrate all extensions * errors if migration is missing --- .dockerignore | 2 +- .github/workflows/migrations.yml | 49 ++++++ docs/guide/installation.md | 4 +- lnbits/extensions/lnurldevice/migrations.py | 2 +- .../templates/lnurldevice/_api_docs.html | 2 +- conv.py => tools/conv.py | 139 ++++++++++++++---- 6 files changed, 167 insertions(+), 31 deletions(-) create mode 100644 .github/workflows/migrations.yml rename conv.py => tools/conv.py (84%) diff --git a/.dockerignore b/.dockerignore index c8872f9ed..51cee13c3 100644 --- a/.dockerignore +++ b/.dockerignore @@ -4,6 +4,7 @@ docker docs tests venv +tools *.md *.log @@ -12,7 +13,6 @@ venv .gitignore .prettierrc -conv.py LICENSE Makefile mypy.ini diff --git a/.github/workflows/migrations.yml b/.github/workflows/migrations.yml new file mode 100644 index 000000000..45de97277 --- /dev/null +++ b/.github/workflows/migrations.yml @@ -0,0 +1,49 @@ +name: migrations + +on: [pull_request] + +jobs: + sqlite-to-postgres: + runs-on: ubuntu-latest + services: + postgres: + image: postgres:latest + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: postgres + ports: + # maps tcp port 5432 on service container to the host + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + strategy: + matrix: + python-version: [3.8] + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + env: + VIRTUAL_ENV: ./venv + PATH: ${{ env.VIRTUAL_ENV }}/bin:${{ env.PATH }} + run: | + python -m venv ${{ env.VIRTUAL_ENV }} + ./venv/bin/python -m pip install --upgrade pip + ./venv/bin/pip install -r requirements.txt + ./venv/bin/pip install pytest pytest-asyncio pytest-cov requests mock + - name: Run migrations + run: | + rm -rf ./data + mkdir -p ./data + export LNBITS_DATA_FOLDER="./data" + timeout 5s ./venv/bin/uvicorn lnbits.__main__:app --host 0.0.0.0 --port 5001 || code=$?; if [[ $code -ne 124 && $code -ne 0 ]]; then exit $code; fi + export LNBITS_DATABASE_URL="postgres://postgres:postgres@0.0.0.0:5432/postgres" + timeout 5s ./venv/bin/uvicorn lnbits.__main__:app --host 0.0.0.0 --port 5001 || code=$?; if [[ $code -ne 124 && $code -ne 0 ]]; then exit $code; fi + ./venv/bin/python tools/conv.py --dont-ignore-missing diff --git a/docs/guide/installation.md b/docs/guide/installation.md index de391b884..daa9ae131 100644 --- a/docs/guide/installation.md +++ b/docs/guide/installation.md @@ -142,8 +142,8 @@ LNBITS_DATABASE_URL="postgres://postgres:postgres@localhost/lnbits" # START LNbits # STOP LNbits -# on the LNBits folder, locate and edit 'conv.py' with the relevant credentials -python3 conv.py +# on the LNBits folder, locate and edit 'tools/conv.py' with the relevant credentials +python3 tools/conv.py ``` Hopefully, everything works and get migrated... Launch LNbits again and check if everything is working properly. diff --git a/lnbits/extensions/lnurldevice/migrations.py b/lnbits/extensions/lnurldevice/migrations.py index 67065347c..625949f5c 100644 --- a/lnbits/extensions/lnurldevice/migrations.py +++ b/lnbits/extensions/lnurldevice/migrations.py @@ -42,7 +42,7 @@ async def m002_redux(db): """ try: for row in [ - list(row) for row in await db2.fetchall("SELECT * FROM lnurlpos.lnurlposs") + list(row) for row in await db2.fetchall("SELECT * FROM lnurlpos.lnurlpos") ]: await db.execute( """ diff --git a/lnbits/extensions/lnurldevice/templates/lnurldevice/_api_docs.html b/lnbits/extensions/lnurldevice/templates/lnurldevice/_api_docs.html index d5b4b5b8e..940d4691e 100644 --- a/lnbits/extensions/lnurldevice/templates/lnurldevice/_api_docs.html +++ b/lnbits/extensions/lnurldevice/templates/lnurldevice/_api_docs.html @@ -120,7 +120,7 @@ GET - /lnurldevice/api/v1/lnurlposs
Headers
{"X-Api-Key": <invoice_key>}
diff --git a/conv.py b/tools/conv.py similarity index 84% rename from conv.py rename to tools/conv.py index aa66a998d..24414da15 100644 --- a/conv.py +++ b/tools/conv.py @@ -1,6 +1,13 @@ import psycopg2 import sqlite3 import os +import argparse + + +from environs import Env # type: ignore + +env = Env() +env.read_env() # Python script to migrate an LNbits SQLite DB to Postgres # All credits to @Fritz446 for the awesome work @@ -11,13 +18,27 @@ import os # Change these values as needed + sqfolder = "data/" -pgdb = "lnbits" -pguser = "postgres" -pgpswd = "yourpassword" -pghost = "localhost" -pgport = "5432" -pgschema = "" + +LNBITS_DATABASE_URL = env.str("LNBITS_DATABASE_URL", default=None) +if LNBITS_DATABASE_URL is None: + pgdb = "lnbits" + pguser = "lnbits" + pgpswd = "postgres" + pghost = "localhost" + pgport = "5432" + pgschema = "" +else: + # parse postgres://lnbits:postgres@localhost:5432/lnbits + pgdb = LNBITS_DATABASE_URL.split("/")[-1] + pguser = LNBITS_DATABASE_URL.split("@")[0].split(":")[-2][2:] + pgpswd = LNBITS_DATABASE_URL.split("@")[0].split(":")[-1] + pghost = LNBITS_DATABASE_URL.split("@")[1].split(":")[0] + pgport = LNBITS_DATABASE_URL.split("@")[1].split(":")[1].split("/")[0] + pgschema = "" + +print(pgdb, pguser, pgpswd, pghost, pgport, pgschema) def get_sqlite_cursor(sqdb) -> sqlite3: @@ -35,8 +56,6 @@ def get_postgres_cursor(): def check_db_versions(sqdb): sqlite = get_sqlite_cursor(sqdb) dblite = dict(sqlite.execute("SELECT * FROM dbversions;").fetchall()) - if "lnurlpos" in dblite: - del dblite["lnurlpos"] sqlite.close() postgres = get_postgres_cursor() @@ -128,9 +147,14 @@ def migrate_core(sqlite_db_file): print("Migrated: core") -def migrate_ext(sqlite_db_file, schema): - sq = get_sqlite_cursor(sqlite_db_file) +def migrate_ext(sqlite_db_file, schema, ignore_missing=True): + # skip this file it has been moved to ext_lnurldevices.sqlite3 + if sqlite_db_file == "data/ext_lnurlpos.sqlite3": + return + + print(f"Migrating {sqlite_db_file}.{schema}") + sq = get_sqlite_cursor(sqlite_db_file) if schema == "bleskomat": # BLESKOMAT LNURLS res = sq.execute("SELECT * FROM bleskomat_lnurls;") @@ -515,19 +539,19 @@ def migrate_ext(sqlite_db_file, schema): items = res.fetchall() insert_to_pg(q, items) fix_id("offlineshop.items_id_seq", items) - elif schema == "lnurlpos": - # LNURLPOSS - res = sq.execute("SELECT * FROM lnurlposs;") + elif schema == "lnurlpos" or schema == "lnurldevice": + # lnurldevice + res = sq.execute("SELECT * FROM lnurldevices;") q = f""" - INSERT INTO lnurlpos.lnurlposs (id, key, title, wallet, currency, timestamp) - VALUES (%s, %s, %s, %s, %s, to_timestamp(%s)); + INSERT INTO lnurldevice.lnurldevices (id, key, title, wallet, currency, device, profit) + VALUES (%s, %s, %s, %s, %s, %s, %s); """ insert_to_pg(q, res.fetchall()) - # LNURLPOS PAYMENT - res = sq.execute("SELECT * FROM lnurlpospayment;") + # lnurldevice PAYMENT + res = sq.execute("SELECT * FROM lnurldevicepayment;") q = f""" - INSERT INTO lnurlpos.lnurlpospayment (id, posid, payhash, payload, pin, sats, timestamp) - VALUES (%s, %s, %s, %s, %s, %s, to_timestamp(%s)); + INSERT INTO lnurldevice.lnurldevicepayment (id, deviceid, payhash, payload, pin, sats) + VALUES (%s, %s, %s, %s, %s, %s); """ insert_to_pg(q, res.fetchall()) elif schema == "lnurlp": @@ -546,9 +570,10 @@ def migrate_ext(sqlite_db_file, schema): success_url, currency, comment_chars, - max + max, + fiat_base_multiplier ) - VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s); + VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s); """ pay_links = res.fetchall() insert_to_pg(q, pay_links) @@ -637,17 +662,79 @@ def migrate_ext(sqlite_db_file, schema): tracks = res.fetchall() insert_to_pg(q, tracks) fix_id("livestream.tracks_id_seq", tracks) + elif schema == "lnaddress": + # DOMAINS + res = sq.execute("SELECT * FROM domain;") + q = f""" + INSERT INTO lnaddress.domain( + id, wallet, domain, webhook, cf_token, cf_zone_id, cost, "time") + VALUES (%s, %s, %s, %s, %s, %s, %s, to_timestamp(%s)); + """ + insert_to_pg(q, res.fetchall()) + # ADDRESSES + res = sq.execute("SELECT * FROM address;") + q = f""" + INSERT INTO lnaddress.address( + id, wallet, domain, email, username, wallet_key, wallet_endpoint, sats, duration, paid, "time") + VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s::boolean, to_timestamp(%s)); + """ + insert_to_pg(q, res.fetchall()) + elif schema == "discordbot": + # USERS + res = sq.execute("SELECT * FROM users;") + q = f""" + INSERT INTO discordbot.users( + id, name, admin, discord_id) + VALUES (%s, %s, %s, %s); + """ + insert_to_pg(q, res.fetchall()) + # WALLETS + res = sq.execute("SELECT * FROM wallets;") + q = f""" + INSERT INTO discordbot.wallets( + id, admin, name, "user", adminkey, inkey) + VALUES (%s, %s, %s, %s, %s, %s); + """ + insert_to_pg(q, res.fetchall()) else: - print(f"Not implemented: {schema}") + print(f"❌ Not implemented: {schema}") sq.close() + + if ignore_missing == False: + raise Exception( + f"Not implemented: {schema}. Use --ignore-missing to skip missing extensions." + ) return - print(f"Migrated: {schema}") + print(f"✅ Migrated: {schema}") sq.close() -check_db_versions("data/database.sqlite3") -migrate_core("data/database.sqlite3") +parser = argparse.ArgumentParser(description="Migrate data from SQLite to PostgreSQL") +parser.add_argument( + dest="sqlite_file", + const=True, + nargs="?", + help="SQLite DB to migrate from", + default="data/database.sqlite3", + type=str, +) +parser.add_argument( + "-i", + "--dont-ignore-missing", + help="Error if migration is missing for an extension.", + required=False, + default=False, + const=True, + nargs="?", + type=bool, +) +args = parser.parse_args() + +print(args) + +check_db_versions(args.sqlite_file) +migrate_core(args.sqlite_file) files = os.listdir(sqfolder) for file in files: @@ -655,4 +742,4 @@ for file in files: if file.startswith("ext_"): schema = file.replace("ext_", "").split(".")[0] print(f"Migrating: {schema}") - migrate_ext(path, schema) + migrate_ext(path, schema, ignore_missing=not args.dont_ignore_missing) From 2febb364ca9f416ba36b68f2e482124f87aa6313 Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Sun, 17 Jul 2022 13:22:23 +0200 Subject: [PATCH 13/33] lnurldevice migration: typo fix (#746) * typo fix * fix table name * revert typo --- lnbits/extensions/lnurldevice/migrations.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lnbits/extensions/lnurldevice/migrations.py b/lnbits/extensions/lnurldevice/migrations.py index 625949f5c..c7899282c 100644 --- a/lnbits/extensions/lnurldevice/migrations.py +++ b/lnbits/extensions/lnurldevice/migrations.py @@ -38,11 +38,11 @@ async def m001_initial(db): async def m002_redux(db): """ - Moves everything from lnurlpos to lnurldevices + Moves everything from lnurlpos to lnurldevice """ try: for row in [ - list(row) for row in await db2.fetchall("SELECT * FROM lnurlpos.lnurlpos") + list(row) for row in await db2.fetchall("SELECT * FROM lnurlpos.lnurlposs") ]: await db.execute( """ From d4c30a1091bc985b24b123cdbf25f693fb11c769 Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Sun, 17 Jul 2022 14:04:59 +0200 Subject: [PATCH 14/33] remove old files (#748) --- .editorconfig | 16 ---------------- Procfile | 1 - app.json | 7 ------- 3 files changed, 24 deletions(-) delete mode 100644 .editorconfig delete mode 100644 Procfile delete mode 100644 app.json diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index b6a0d7217..000000000 --- a/.editorconfig +++ /dev/null @@ -1,16 +0,0 @@ -root = true - -[*] -charset = utf-8 -end_of_line = lf -insert_final_newline = true -trim_trailing_whitespace = true -indent_size = 2 -indent_style = space - -[*.md] -trim_trailing_whitespace = false - -[*.py] -indent_size = 4 -indent_style = space diff --git a/Procfile b/Procfile deleted file mode 100644 index c0ca4887a..000000000 --- a/Procfile +++ /dev/null @@ -1 +0,0 @@ -web: hypercorn -k trio --bind 0.0.0.0:5000 'lnbits.app:create_app()' diff --git a/app.json b/app.json deleted file mode 100644 index 5f5d5bb15..000000000 --- a/app.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "scripts": { - "dokku": { - "predeploy": "quart migrate && quart assets" - } - } -} From 6646fce549fe0123bd1fbf0e6adb8ea9e3676b8a Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Sun, 17 Jul 2022 14:34:25 +0200 Subject: [PATCH 15/33] Core: add internal flag for invoice creation to use FakeWallet (#646) * add internal flag for invoice creation to use FakeWallet --- lnbits/core/services.py | 10 ++++--- lnbits/core/templates/core/_api_docs.html | 3 ++- lnbits/core/views/api.py | 2 ++ lnbits/settings.py | 1 + lnbits/wallets/fake.py | 8 +++++- tests/core/views/test_api.py | 33 ++++++++++++++++++----- 6 files changed, 45 insertions(+), 12 deletions(-) diff --git a/lnbits/core/services.py b/lnbits/core/services.py index 84bc98e3b..da0e5a446 100644 --- a/lnbits/core/services.py +++ b/lnbits/core/services.py @@ -14,7 +14,7 @@ from lnbits import bolt11 from lnbits.db import Connection from lnbits.helpers import url_for, urlsafe_short_hash from lnbits.requestvars import g -from lnbits.settings import WALLET +from lnbits.settings import FAKE_WALLET, WALLET from lnbits.wallets.base import PaymentResponse, PaymentStatus from . import db @@ -49,15 +49,19 @@ async def create_invoice( description_hash: Optional[bytes] = None, extra: Optional[Dict] = None, webhook: Optional[str] = None, + internal: Optional[bool] = False, conn: Optional[Connection] = None, ) -> Tuple[str, str]: invoice_memo = None if description_hash else memo - ok, checking_id, payment_request, error_message = await WALLET.create_invoice( + # use the fake wallet if the invoice is for internal use only + wallet = FAKE_WALLET if internal else WALLET + + ok, checking_id, payment_request, error_message = await wallet.create_invoice( amount=amount, memo=invoice_memo, description_hash=description_hash ) if not ok: - raise InvoiceFailure(error_message or "Unexpected backend error.") + raise InvoiceFailure(error_message or "unexpected backend error.") invoice = bolt11.decode(payment_request) diff --git a/lnbits/core/templates/core/_api_docs.html b/lnbits/core/templates/core/_api_docs.html index 271568d44..383f2b121 100644 --- a/lnbits/core/templates/core/_api_docs.html +++ b/lnbits/core/templates/core/_api_docs.html @@ -49,7 +49,8 @@
Body (application/json)
{"out": false, "amount": <int>, "memo": <string>, "unit": - <string>, "webhook": <url:string>}
Returns 201 CREATED (application/json) diff --git a/lnbits/core/views/api.py b/lnbits/core/views/api.py index f5b580414..198b00098 100644 --- a/lnbits/core/views/api.py +++ b/lnbits/core/views/api.py @@ -147,6 +147,7 @@ class CreateInvoiceData(BaseModel): lnurl_balance_check: Optional[str] = None extra: Optional[dict] = None webhook: Optional[str] = None + internal: Optional[bool] = False bolt11: Optional[str] = None @@ -173,6 +174,7 @@ async def api_payments_create_invoice(data: CreateInvoiceData, wallet: Wallet): description_hash=description_hash, extra=data.extra, webhook=data.webhook, + internal=data.internal, conn=conn, ) except InvoiceFailure as e: diff --git a/lnbits/settings.py b/lnbits/settings.py index efa0b8d50..5778b9e23 100644 --- a/lnbits/settings.py +++ b/lnbits/settings.py @@ -51,6 +51,7 @@ LNBITS_THEME_OPTIONS: List[str] = env.list( LNBITS_CUSTOM_LOGO = env.str("LNBITS_CUSTOM_LOGO", default="") WALLET = wallet_class() +FAKE_WALLET = getattr(wallets_module, "FakeWallet")() DEFAULT_WALLET_NAME = env.str("LNBITS_DEFAULT_WALLET_NAME", default="LNbits wallet") PREFER_SECURE_URLS = env.bool("LNBITS_FORCE_HTTPS", default=True) diff --git a/lnbits/wallets/fake.py b/lnbits/wallets/fake.py index ff64bd613..9dd5556bd 100644 --- a/lnbits/wallets/fake.py +++ b/lnbits/wallets/fake.py @@ -5,6 +5,7 @@ from datetime import datetime from os import getenv from typing import AsyncGenerator, Dict, Optional +from environs import Env # type: ignore from loguru import logger from lnbits.helpers import urlsafe_short_hash @@ -18,6 +19,9 @@ from .base import ( Wallet, ) +env = Env() +env.read_env() + class FakeWallet(Wallet): async def status(self) -> StatusResponse: @@ -32,7 +36,9 @@ class FakeWallet(Wallet): memo: Optional[str] = None, description_hash: Optional[bytes] = None, ) -> InvoiceResponse: - secret = getenv("FAKE_WALLET_SECRET") + # we set a default secret since FakeWallet is used for internal=True invoices + # and the user might not have configured a secret yet + secret = env.str("FAKE_WALLET_SECTRET", default="ToTheMoon1") data: Dict = { "out": False, "amount": amount, diff --git a/tests/core/views/test_api.py b/tests/core/views/test_api.py index 726709022..10e659aa4 100644 --- a/tests/core/views/test_api.py +++ b/tests/core/views/test_api.py @@ -25,13 +25,32 @@ async def test_create_invoice(client, inkey_headers_to): response = await client.post( "/api/v1/payments", json=data, headers=inkey_headers_to ) - assert response.status_code < 300 - assert "payment_hash" in response.json() - assert len(response.json()["payment_hash"]) == 64 - assert "payment_request" in response.json() - assert "checking_id" in response.json() - assert len(response.json()["checking_id"]) - return response.json() + assert response.status_code == 201 + invoice = response.json() + assert "payment_hash" in invoice + assert len(invoice["payment_hash"]) == 64 + assert "payment_request" in invoice + assert "checking_id" in invoice + assert len(invoice["checking_id"]) + return invoice + + +# check POST /api/v1/payments: invoice creation for internal payments only +@pytest.mark.asyncio +async def test_create_internal_invoice(client, inkey_headers_to): + data = await get_random_invoice_data() + data["internal"] = True + response = await client.post( + "/api/v1/payments", json=data, headers=inkey_headers_to + ) + invoice = response.json() + assert response.status_code == 201 + assert "payment_hash" in invoice + assert len(invoice["payment_hash"]) == 64 + assert "payment_request" in invoice + assert "checking_id" in invoice + assert len(invoice["checking_id"]) + return invoice # check POST /api/v1/payments: make payment From 8079325ec9fdb03e6a1320888bfa8f996d6c18d3 Mon Sep 17 00:00:00 2001 From: Lee Salminen Date: Sun, 17 Jul 2022 06:38:00 -0600 Subject: [PATCH 16/33] fix `/usermanager/api/v1/extensions` (#730) Requests to `POST /usermanager/api/v1/extensions` would silently fail due to a missing `await`. --- lnbits/extensions/usermanager/views_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lnbits/extensions/usermanager/views_api.py b/lnbits/extensions/usermanager/views_api.py index a36b36bbb..7e7b7653a 100644 --- a/lnbits/extensions/usermanager/views_api.py +++ b/lnbits/extensions/usermanager/views_api.py @@ -75,7 +75,7 @@ async def api_usermanager_activate_extension( raise HTTPException( status_code=HTTPStatus.NOT_FOUND, detail="User does not exist." ) - update_user_extension(user_id=userid, extension=extension, active=active) + await update_user_extension(user_id=userid, extension=extension, active=active) return {"extension": "updated"} From 2b827d37fa112cb5af9ceb34f8782e261a4e4ada Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Sun, 17 Jul 2022 13:39:02 +0100 Subject: [PATCH 17/33] return lnurl in create link (#685) --- lnbits/extensions/lnurlp/views_api.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lnbits/extensions/lnurlp/views_api.py b/lnbits/extensions/lnurlp/views_api.py index 6123043c5..8d4569da9 100644 --- a/lnbits/extensions/lnurlp/views_api.py +++ b/lnbits/extensions/lnurlp/views_api.py @@ -73,6 +73,7 @@ async def api_link_retrieve( @lnurlp_ext.put("/api/v1/links/{link_id}", status_code=HTTPStatus.OK) async def api_link_create_or_update( data: CreatePayLinkData, + request: Request, link_id=None, wallet: WalletTypeInfo = Depends(get_key_type), ): @@ -117,7 +118,7 @@ async def api_link_create_or_update( link = await update_pay_link(**data.dict(), link_id=link_id) else: link = await create_pay_link(data, wallet_id=wallet.wallet.id) - return {**link.dict(), "lnurl": link.lnurl} + return {**link.dict(), "lnurl": link.lnurl(request)} @lnurlp_ext.delete("/api/v1/links/{link_id}") From c8ab2859fd8db726c535ab27f3848905e1d912e2 Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Sun, 17 Jul 2022 19:00:06 +0100 Subject: [PATCH 18/33] Splitpayments: floating point percentage for split value (#690) * allow for float in model * recreate DB with float type * remove rounding in UI * black Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com> --- lnbits/extensions/splitpayments/migrations.py | 38 +++++++++++++++++++ lnbits/extensions/splitpayments/models.py | 4 +- .../splitpayments/static/js/index.js | 2 +- .../templates/splitpayments/index.html | 12 +++--- 4 files changed, 47 insertions(+), 9 deletions(-) diff --git a/lnbits/extensions/splitpayments/migrations.py b/lnbits/extensions/splitpayments/migrations.py index 735afc6c3..b3921c42a 100644 --- a/lnbits/extensions/splitpayments/migrations.py +++ b/lnbits/extensions/splitpayments/migrations.py @@ -14,3 +14,41 @@ async def m001_initial(db): ); """ ) + + +async def m002_float_percent(db): + """ + Add float percent and migrates the existing data. + """ + await db.execute("ALTER TABLE splitpayments.targets RENAME TO splitpayments_old") + await db.execute( + """ + CREATE TABLE splitpayments.targets ( + wallet TEXT NOT NULL, + source TEXT NOT NULL, + percent REAL NOT NULL CHECK (percent >= 0 AND percent <= 100), + alias TEXT, + + UNIQUE (source, wallet) + ); + """ + ) + + for row in [ + list(row) + for row in await db.fetchall("SELECT * FROM splitpayments.splitpayments_old") + ]: + await db.execute( + """ + INSERT INTO splitpayments.targets ( + wallet, + source, + percent, + alias + ) + VALUES (?, ?, ?, ?) + """, + (row[0], row[1], row[2], row[3]), + ) + + await db.execute("DROP TABLE splitpayments.splitpayments_old") diff --git a/lnbits/extensions/splitpayments/models.py b/lnbits/extensions/splitpayments/models.py index 3264bca7c..4b95ed18b 100644 --- a/lnbits/extensions/splitpayments/models.py +++ b/lnbits/extensions/splitpayments/models.py @@ -7,14 +7,14 @@ from pydantic import BaseModel class Target(BaseModel): wallet: str source: str - percent: int + percent: float alias: Optional[str] class TargetPutList(BaseModel): wallet: str = Query(...) alias: str = Query("") - percent: int = Query(..., ge=1) + percent: float = Query(..., ge=0.01) class TargetPut(BaseModel): diff --git a/lnbits/extensions/splitpayments/static/js/index.js b/lnbits/extensions/splitpayments/static/js/index.js index d9750bef1..5d326231d 100644 --- a/lnbits/extensions/splitpayments/static/js/index.js +++ b/lnbits/extensions/splitpayments/static/js/index.js @@ -105,7 +105,7 @@ new Vue({ if (currentTotal > 100 && isPercent) { let diff = (currentTotal - 100) / (100 - this.targets[index].percent) this.targets.forEach((target, t) => { - if (t !== index) target.percent -= Math.round(diff * target.percent) + if (t !== index) target.percent -= +(diff * target.percent).toFixed(2) }) } diff --git a/lnbits/extensions/splitpayments/templates/splitpayments/index.html b/lnbits/extensions/splitpayments/templates/splitpayments/index.html index 1aae4e334..5862abc16 100644 --- a/lnbits/extensions/splitpayments/templates/splitpayments/index.html +++ b/lnbits/extensions/splitpayments/templates/splitpayments/index.html @@ -58,14 +58,14 @@ > - - +
+
Clear - +
- +
Save Targets - - +
+
From f4580955b940b932d853aa7a1c342e29ea33ba50 Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Sun, 17 Jul 2022 22:25:37 +0200 Subject: [PATCH 19/33] loguru warnings (#751) --- lnbits/core/services.py | 2 +- lnbits/core/views/api.py | 2 +- lnbits/utils/exchange_rates.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lnbits/core/services.py b/lnbits/core/services.py index da0e5a446..d802bc4e3 100644 --- a/lnbits/core/services.py +++ b/lnbits/core/services.py @@ -231,7 +231,7 @@ async def redeem_lnurl_withdraw( conn=conn, ) except: - logger.warn( + logger.warning( f"failed to create invoice on redeem_lnurl_withdraw from {lnurl}. params: {res}" ) return None diff --git a/lnbits/core/views/api.py b/lnbits/core/views/api.py index 198b00098..290fd402b 100644 --- a/lnbits/core/views/api.py +++ b/lnbits/core/views/api.py @@ -395,7 +395,7 @@ async def api_payment(payment_hash, X_Api_Key: Optional[str] = Header(None)): wallet = None try: if X_Api_Key.extra: - logger.warn("No key") + logger.warning("No key") except: wallet = await get_wallet_for_key(X_Api_Key) payment = await get_standalone_payment( diff --git a/lnbits/utils/exchange_rates.py b/lnbits/utils/exchange_rates.py index cec0216a7..0432b364a 100644 --- a/lnbits/utils/exchange_rates.py +++ b/lnbits/utils/exchange_rates.py @@ -281,7 +281,7 @@ async def btc_price(currency: str) -> float: if not rates: return 9999999999 elif len(rates) == 1: - logger.warn("Could only fetch one Bitcoin price.") + logger.warning("Could only fetch one Bitcoin price.") return sum([rate for rate in rates]) / len(rates) From b6d01792e2607c03b951ebf343a4b13f4282b313 Mon Sep 17 00:00:00 2001 From: Lee Salminen Date: Mon, 18 Jul 2022 08:56:15 -0600 Subject: [PATCH 20/33] Add NFC Writing support to LNURLw extension (#725) --- lnbits/extensions/withdraw/static/js/index.js | 31 +++++++++++++ .../withdraw/templates/withdraw/display.html | 46 ++++++++++++++++++- .../withdraw/templates/withdraw/index.html | 7 +++ 3 files changed, 82 insertions(+), 2 deletions(-) diff --git a/lnbits/extensions/withdraw/static/js/index.js b/lnbits/extensions/withdraw/static/js/index.js index e54005c69..a2563d84a 100644 --- a/lnbits/extensions/withdraw/static/js/index.js +++ b/lnbits/extensions/withdraw/static/js/index.js @@ -53,6 +53,7 @@ new Vue({ rowsPerPage: 10 } }, + nfcTagWriting: false, formDialog: { show: false, secondMultiplier: 'seconds', @@ -231,6 +232,36 @@ new Vue({ }) }) }, + writeNfcTag: async function (lnurl) { + try { + if (typeof NDEFReader == 'undefined') { + throw { + toString: function () { + return 'NFC not supported on this device and/or browser.' + } + } + } + + const ndef = new NDEFReader() + + this.nfcTagWriting = true + this.$q.notify({ + message: 'Tap your NFC tag now to write the LNURLw to it' + }) + + await ndef.write(lnurl) + + this.nfcTagWriting = false + this.$q.notify({ + message: 'NFC Tag written successfully!' + }) + } catch (error) { + this.nfcTagWriting = false + this.$q.notify({ + message: error ? error.toString() : 'An unexpected error has occurred' + }) + } + }, exportCSV: function () { LNbits.utils.exportCSV(this.paywallsTable.columns, this.paywalls) } diff --git a/lnbits/extensions/withdraw/templates/withdraw/display.html b/lnbits/extensions/withdraw/templates/withdraw/display.html index 5552c77ff..0c523b272 100644 --- a/lnbits/extensions/withdraw/templates/withdraw/display.html +++ b/lnbits/extensions/withdraw/templates/withdraw/display.html @@ -17,10 +17,17 @@ -
+
Copy LNURL +
@@ -51,7 +58,42 @@ mixins: [windowMixin], data: function () { return { - here: location.protocol + '//' + location.host + here: location.protocol + '//' + location.host, + nfcTagWriting: false + } + }, + methods: { + writeNfcTag: async function (lnurl) { + try { + if (typeof NDEFReader == 'undefined') { + throw { + toString: function () { + return 'NFC not supported on this device and/or browser.' + } + } + } + + const ndef = new NDEFReader() + + this.nfcTagWriting = true + this.$q.notify({ + message: 'Tap your NFC tag now to write the LNURLw to it' + }) + + await ndef.write(lnurl) + + this.nfcTagWriting = false + this.$q.notify({ + message: 'NFC Tag written successfully!' + }) + } catch (error) { + this.nfcTagWriting = false + this.$q.notify({ + message: error + ? error.toString() + : 'An unexpected error has occurred' + }) + } } } }) diff --git a/lnbits/extensions/withdraw/templates/withdraw/index.html b/lnbits/extensions/withdraw/templates/withdraw/index.html index 6d3ab374a..99aa03b2d 100644 --- a/lnbits/extensions/withdraw/templates/withdraw/index.html +++ b/lnbits/extensions/withdraw/templates/withdraw/index.html @@ -369,6 +369,13 @@ @click="copyText(qrCodeDialog.data.withdraw_url, 'Link copied to clipboard!')" >Shareable link + Date: Tue, 19 Jul 2022 10:35:28 +0100 Subject: [PATCH 21/33] Fix/lnurl auth (#757) * remove g() and add wallet * wallet type * add wallet object * send wallet as param * make lnurlauth work * remove g() and add wallet * wallet type * add wallet object * send wallet as param * make lnurlauth work * black'ed * blacked Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com> --- lnbits/core/services.py | 13 +++++++++++-- lnbits/core/views/api.py | 28 +++++++++++++--------------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/lnbits/core/services.py b/lnbits/core/services.py index d802bc4e3..0b565ebb9 100644 --- a/lnbits/core/services.py +++ b/lnbits/core/services.py @@ -6,12 +6,19 @@ from typing import Dict, Optional, Tuple from urllib.parse import parse_qs, urlparse import httpx +from fastapi import Depends from lnurl import LnurlErrorResponse from lnurl import decode as decode_lnurl # type: ignore from loguru import logger from lnbits import bolt11 from lnbits.db import Connection +from lnbits.decorators import ( + WalletTypeInfo, + get_key_type, + require_admin_key, + require_invoice_key, +) from lnbits.helpers import url_for, urlsafe_short_hash from lnbits.requestvars import g from lnbits.settings import FAKE_WALLET, WALLET @@ -258,12 +265,14 @@ async def redeem_lnurl_withdraw( async def perform_lnurlauth( - callback: str, conn: Optional[Connection] = None + callback: str, + wallet: WalletTypeInfo = Depends(require_admin_key), + conn: Optional[Connection] = None, ) -> Optional[LnurlErrorResponse]: cb = urlparse(callback) k1 = unhexlify(parse_qs(cb.query)["k1"][0]) - key = g().wallet.lnurlauth_key(cb.netloc) + key = wallet.wallet.lnurlauth_key(cb.netloc) def int_to_bytes_suitable_der(x: int) -> bytes: """for strict DER we need to encode the integer with some quirks""" diff --git a/lnbits/core/views/api.py b/lnbits/core/views/api.py index 290fd402b..9fee6063d 100644 --- a/lnbits/core/views/api.py +++ b/lnbits/core/views/api.py @@ -7,9 +7,8 @@ from typing import Dict, List, Optional, Union from urllib.parse import ParseResult, parse_qs, urlencode, urlparse, urlunparse import httpx -from fastapi import Header, Query, Request +from fastapi import Depends, Header, Query, Request from fastapi.exceptions import HTTPException -from fastapi.param_functions import Depends from fastapi.params import Body from loguru import logger from pydantic import BaseModel @@ -17,18 +16,14 @@ from pydantic.fields import Field from sse_starlette.sse import EventSourceResponse from lnbits import bolt11, lnurl -from lnbits.bolt11 import Invoice from lnbits.core.models import Payment, Wallet from lnbits.decorators import ( - WalletAdminKeyChecker, - WalletInvoiceKeyChecker, WalletTypeInfo, get_key_type, require_admin_key, require_invoice_key, ) from lnbits.helpers import url_for, urlsafe_short_hash -from lnbits.requestvars import g from lnbits.settings import LNBITS_ADMIN_USERS, LNBITS_SITE_TITLE from lnbits.utils.exchange_rates import ( currencies, @@ -435,10 +430,8 @@ async def api_payment(payment_hash, X_Api_Key: Optional[str] = Header(None)): return {"paid": not payment.pending, "preimage": payment.preimage} -@core_app.get( - "/api/v1/lnurlscan/{code}", dependencies=[Depends(WalletInvoiceKeyChecker())] -) -async def api_lnurlscan(code: str): +@core_app.get("/api/v1/lnurlscan/{code}") +async def api_lnurlscan(code: str, wallet: WalletTypeInfo = Depends(get_key_type)): try: url = lnurl.decode(code) domain = urlparse(url).netloc @@ -466,7 +459,7 @@ async def api_lnurlscan(code: str): params.update(kind="auth") params.update(callback=url) # with k1 already in it - lnurlauth_key = g().wallet.lnurlauth_key(domain) + lnurlauth_key = wallet.wallet.lnurlauth_key(domain) params.update(pubkey=lnurlauth_key.verifying_key.to_string("compressed").hex()) else: async with httpx.AsyncClient() as client: @@ -582,14 +575,19 @@ async def api_payments_decode(data: DecodePayment): return {"message": "Failed to decode"} -@core_app.post("/api/v1/lnurlauth", dependencies=[Depends(WalletAdminKeyChecker())]) -async def api_perform_lnurlauth(callback: str): - err = await perform_lnurlauth(callback) +class Callback(BaseModel): + callback: str = Query(...) + + +@core_app.post("/api/v1/lnurlauth") +async def api_perform_lnurlauth( + callback: Callback, wallet: WalletTypeInfo = Depends(require_admin_key) +): + err = await perform_lnurlauth(callback.callback, wallet=wallet) if err: raise HTTPException( status_code=HTTPStatus.SERVICE_UNAVAILABLE, detail=err.reason ) - return "" From fe2cbe87745d2fec5ffcb1e9941043069548ff69 Mon Sep 17 00:00:00 2001 From: blackcoffeexbt <87530449+blackcoffeexbt@users.noreply.github.com> Date: Tue, 19 Jul 2022 11:28:49 +0100 Subject: [PATCH 22/33] Jukebox improvements (#759) * Improved styling of Spotify redirect URI clipboard copy text * Jukebox extension - Moved links to Spotify into buttons to make set up steps more obvious * Jukebox extension - Tweaks to titles of set up steps to clarify * Prettified jukebox template --- .../jukebox/templates/jukebox/index.html | 70 ++++++++++++------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/lnbits/extensions/jukebox/templates/jukebox/index.html b/lnbits/extensions/jukebox/templates/jukebox/index.html index 9b4efbd5c..a67767fb8 100644 --- a/lnbits/extensions/jukebox/templates/jukebox/index.html +++ b/lnbits/extensions/jukebox/templates/jukebox/index.html @@ -117,7 +117,7 @@ > @@ -170,16 +170,25 @@
- + To use this extension you need a Spotify client ID and client secret. - You get these by creating an app in the Spotify developers dashboard - +
+ here
. + >Open the Spotify Developer Dashboard
+ - + - In the app go to edit-settings, set the redirect URI to this link +

+ In the app go to edit-settings, set the redirect URI to this link +

+ + + {% raw %}{{ locationcb }}{{ jukeboxDialog.data.sp_id }}{% endraw + %} + + Click to copy URL +
{% raw %}{{ locationcb }}{{ jukeboxDialog.data.sp_id }}{% endraw - %} Click to copy URL - -
- Settings can be found - here. + >Open the Spotify Application Settings +

+

+ After adding the redirect URI, click the "Authorise access" button + below. +

@@ -281,7 +301,7 @@ Date: Tue, 19 Jul 2022 12:33:28 +0200 Subject: [PATCH 23/33] do not mark payments as failed (#750) --- lnbits/wallets/fake.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lnbits/wallets/fake.py b/lnbits/wallets/fake.py index 9dd5556bd..3859d33c5 100644 --- a/lnbits/wallets/fake.py +++ b/lnbits/wallets/fake.py @@ -91,10 +91,10 @@ class FakeWallet(Wallet): ) async def get_invoice_status(self, checking_id: str) -> PaymentStatus: - return PaymentStatus(False) + return PaymentStatus(None) async def get_payment_status(self, checking_id: str) -> PaymentStatus: - return PaymentStatus(False) + return PaymentStatus(None) async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: self.queue = asyncio.Queue(0) From 0f73501a889701ce8e15fc9a0d7211ecdec64fee Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Tue, 19 Jul 2022 17:20:50 +0200 Subject: [PATCH 24/33] LNURLw: NFC fix uri prefix (#761) * fix uri prefix * prettier --- lnbits/extensions/withdraw/static/js/index.js | 4 +- .../withdraw/templates/withdraw/display.html | 37 +------------------ 2 files changed, 5 insertions(+), 36 deletions(-) diff --git a/lnbits/extensions/withdraw/static/js/index.js b/lnbits/extensions/withdraw/static/js/index.js index a2563d84a..1a811d4ff 100644 --- a/lnbits/extensions/withdraw/static/js/index.js +++ b/lnbits/extensions/withdraw/static/js/index.js @@ -249,7 +249,9 @@ new Vue({ message: 'Tap your NFC tag now to write the LNURLw to it' }) - await ndef.write(lnurl) + await ndef.write({ + records: [{recordType: 'url', data: 'lnurlw://' + lnurl, lang: 'en'}] + }) this.nfcTagWriting = false this.$q.notify({ diff --git a/lnbits/extensions/withdraw/templates/withdraw/display.html b/lnbits/extensions/withdraw/templates/withdraw/display.html index 0c523b272..1e632741c 100644 --- a/lnbits/extensions/withdraw/templates/withdraw/display.html +++ b/lnbits/extensions/withdraw/templates/withdraw/display.html @@ -13,7 +13,8 @@ :value="this.here + '/?lightning={{lnurl }}'" :options="{width: 800}" class="rounded-borders" - > + > +
@@ -61,40 +62,6 @@ here: location.protocol + '//' + location.host, nfcTagWriting: false } - }, - methods: { - writeNfcTag: async function (lnurl) { - try { - if (typeof NDEFReader == 'undefined') { - throw { - toString: function () { - return 'NFC not supported on this device and/or browser.' - } - } - } - - const ndef = new NDEFReader() - - this.nfcTagWriting = true - this.$q.notify({ - message: 'Tap your NFC tag now to write the LNURLw to it' - }) - - await ndef.write(lnurl) - - this.nfcTagWriting = false - this.$q.notify({ - message: 'NFC Tag written successfully!' - }) - } catch (error) { - this.nfcTagWriting = false - this.$q.notify({ - message: error - ? error.toString() - : 'An unexpected error has occurred' - }) - } - } } }) From 45c356cf6c0534de3cd4c85b45f3db6148a8594b Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Tue, 19 Jul 2022 17:35:00 +0200 Subject: [PATCH 25/33] change prefix to lightning: until wallets fix their bugs (#762) --- lnbits/extensions/withdraw/static/js/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lnbits/extensions/withdraw/static/js/index.js b/lnbits/extensions/withdraw/static/js/index.js index 1a811d4ff..a66223eab 100644 --- a/lnbits/extensions/withdraw/static/js/index.js +++ b/lnbits/extensions/withdraw/static/js/index.js @@ -250,7 +250,7 @@ new Vue({ }) await ndef.write({ - records: [{recordType: 'url', data: 'lnurlw://' + lnurl, lang: 'en'}] + records: [{recordType: 'url', data: 'lightning:' + lnurl, lang: 'en'}] }) this.nfcTagWriting = false From 76a5196dbfe779db768ac547796c1419eb2768c5 Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Thu, 21 Jul 2022 12:38:30 +0200 Subject: [PATCH 26/33] LNURLp: Write NFC tags with LNURL-pay links (#766) * NFC for LNURL-pay * notification ui improvements --- lnbits/extensions/lnurlp/static/js/index.js | 37 +++++++++++++++++++ .../lnurlp/templates/lnurlp/display.html | 9 ++++- .../lnurlp/templates/lnurlp/index.html | 23 +++++++++--- lnbits/extensions/withdraw/static/js/index.js | 12 ++++-- 4 files changed, 71 insertions(+), 10 deletions(-) diff --git a/lnbits/extensions/lnurlp/static/js/index.js b/lnbits/extensions/lnurlp/static/js/index.js index e18d6161e..99448802d 100644 --- a/lnbits/extensions/lnurlp/static/js/index.js +++ b/lnbits/extensions/lnurlp/static/js/index.js @@ -35,6 +35,7 @@ new Vue({ rowsPerPage: 10 } }, + nfcTagWriting: false, formDialog: { show: false, fixedAmount: true, @@ -205,6 +206,42 @@ new Vue({ .catch(err => { LNbits.utils.notifyApiError(err) }) + }, + writeNfcTag: async function (lnurl) { + try { + if (typeof NDEFReader == 'undefined') { + throw { + toString: function () { + return 'NFC not supported on this device or browser.' + } + } + } + + const ndef = new NDEFReader() + + this.nfcTagWriting = true + this.$q.notify({ + message: 'Tap your NFC tag to write the LNURL-pay link to it.' + }) + + await ndef.write({ + records: [{recordType: 'url', data: 'lightning:' + lnurl, lang: 'en'}] + }) + + this.nfcTagWriting = false + this.$q.notify({ + type: 'positive', + message: 'NFC Tag written successfully.' + }) + } catch (error) { + this.nfcTagWriting = false + this.$q.notify({ + type: 'negative', + message: error + ? error.toString() + : 'An unexpected error has occurred.' + }) + } } }, created() { diff --git a/lnbits/extensions/lnurlp/templates/lnurlp/display.html b/lnbits/extensions/lnurlp/templates/lnurlp/display.html index 08e4de15c..944e764bf 100644 --- a/lnbits/extensions/lnurlp/templates/lnurlp/display.html +++ b/lnbits/extensions/lnurlp/templates/lnurlp/display.html @@ -14,10 +14,17 @@
-
+
Copy LNURL +
diff --git a/lnbits/extensions/lnurlp/templates/lnurlp/index.html b/lnbits/extensions/lnurlp/templates/lnurlp/index.html index c535f2fb4..9677a0274 100644 --- a/lnbits/extensions/lnurlp/templates/lnurlp/index.html +++ b/lnbits/extensions/lnurlp/templates/lnurlp/index.html @@ -99,7 +99,8 @@ @click="openUpdateDialog(props.row.id)" icon="edit" color="light-blue" - > + > + + > +
+ > +
@@ -200,7 +203,8 @@ type="number" label="Comment maximum characters" hint="Tell wallets to prompt users for a comment that will be sent along with the payment. LNURLp will store the comment and send it in the webhook." - > + > + + > +
Shareable link + + Date: Thu, 21 Jul 2022 13:39:21 +0200 Subject: [PATCH 27/33] LNURLp: NFC UI improvement (#767) --- lnbits/extensions/lnurlp/static/js/index.js | 2 +- lnbits/extensions/withdraw/static/js/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lnbits/extensions/lnurlp/static/js/index.js b/lnbits/extensions/lnurlp/static/js/index.js index 99448802d..1713e77f6 100644 --- a/lnbits/extensions/lnurlp/static/js/index.js +++ b/lnbits/extensions/lnurlp/static/js/index.js @@ -231,7 +231,7 @@ new Vue({ this.nfcTagWriting = false this.$q.notify({ type: 'positive', - message: 'NFC Tag written successfully.' + message: 'NFC tag written successfully.' }) } catch (error) { this.nfcTagWriting = false diff --git a/lnbits/extensions/withdraw/static/js/index.js b/lnbits/extensions/withdraw/static/js/index.js index 6eff4fe99..3f484debf 100644 --- a/lnbits/extensions/withdraw/static/js/index.js +++ b/lnbits/extensions/withdraw/static/js/index.js @@ -256,7 +256,7 @@ new Vue({ this.nfcTagWriting = false this.$q.notify({ type: 'positive', - message: 'NFC Tag written successfully.' + message: 'NFC tag written successfully.' }) } catch (error) { this.nfcTagWriting = false From e4df8c52e20a26a00a1763a3165946d278a9519d Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Thu, 21 Jul 2022 14:01:16 +0200 Subject: [PATCH 28/33] add mkcert instructions (#768) --- docs/guide/installation.md | 49 ++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/docs/guide/installation.md b/docs/guide/installation.md index daa9ae131..8509dcbef 100644 --- a/docs/guide/installation.md +++ b/docs/guide/installation.md @@ -75,10 +75,10 @@ Problems installing? These commands have helped us install LNbits. sudo apt install pkg-config libffi-dev libpq-dev setuptools # if the secp256k1 build fails: -# if you used venv (option 1) -./venv/bin/pip install setuptools wheel -# if you used pipenv (option 2) +# if you used pipenv (option 1) pipenv install setuptools wheel +# if you used venv (option 2) +./venv/bin/pip install setuptools wheel # build essentials for debian/ubuntu sudo apt install python3-dev gcc build-essential ``` @@ -127,7 +127,7 @@ Take a look at [Polar](https://lightningpolar.com/) for an excellent way of spin # Additional guides -### SQLite to PostgreSQL migration +## SQLite to PostgreSQL migration If you already have LNbits installed and running, on an SQLite database, we **highly** recommend you migrate to postgres if you are planning to run LNbits on scale. There's a script included that can do the migration easy. You should have Postgres already installed and there should be a password for the user (see Postgres install guide above). Additionally, your LNbits instance should run once on postgres to implement the database schema before the migration works: @@ -149,7 +149,7 @@ python3 tools/conv.py Hopefully, everything works and get migrated... Launch LNbits again and check if everything is working properly. -### LNbits as a systemd service +## LNbits as a systemd service Systemd is great for taking care of your LNbits instance. It will start it on boot and restart it in case it crashes. If you want to run LNbits as a systemd service on your Debian/Ubuntu/Raspbian server, create a file at `/etc/systemd/system/lnbits.service` with the following content: @@ -188,11 +188,40 @@ sudo systemctl enable lnbits.service sudo systemctl start lnbits.service ``` -### LNbits running on Umbrel behind Tor +## Using https without reverse proxy +The most common way of using LNbits via https is to use a reverse proxy such as Caddy, nginx, or ngriok. However, you can also run LNbits via https without additional software. This is useful for development purposes or if you want to use LNbits in your local network. + +We have to create a self-signed certificate using `mkcert`. Note that this certiciate is not "trusted" by most browsers but that's fine (since you know that you have created it) and encryption is always better than clear text. + +#### Install mkcert +You can find the install instructions for `mkcert` [here](https://github.com/FiloSottile/mkcert). + +Install mkcert on Ubuntu: +```sh +sudo apt install libnss3-tools +curl -JLO "https://dl.filippo.io/mkcert/latest?for=linux/amd64" +chmod +x mkcert-v*-linux-amd64 +sudo cp mkcert-v*-linux-amd64 /usr/local/bin/mkcert +``` +#### Create certificate +To create a certificate, first `cd` into your lnbits folder and execute the following command ([more info](https://kifarunix.com/how-to-create-self-signed-ssl-certificate-with-mkcert-on-ubuntu-18-04/)) +```sh +# add your local IP (192.x.x.x) as well if you want to use it in your local network +mkcert localhost 127.0.0.1 ::1 +``` + +This will create two new files (`localhost-key.pem` and `localhost.pem `) which you can then pass to uvicorn when you start LNbits: + +```sh +./venv/bin/uvicorn lnbits.__main__:app --host 0.0.0.0 --port 5000 --ssl-keyfile ./localhost-key.pem --ssl-certfile ./localhost.pem +``` + + +## LNbits running on Umbrel behind Tor If you want to run LNbits on your Umbrel but want it to be reached through clearnet, _Uxellodunum_ made an extensive [guide](https://community.getumbrel.com/t/guide-lnbits-without-tor/604) on how to do it. -### Docker installation +## Docker installation To install using docker you first need to build the docker image as: @@ -224,9 +253,3 @@ docker run --detach --publish 5000:5000 --name lnbits --volume ${PWD}/.env:/app/ ``` Finally you can access your lnbits on your machine at port 5000. - -# Additional guides - -## LNbits running on Umbrel behind Tor - -If you want to run LNbits on your Umbrel but want it to be reached through clearnet, _Uxellodunum_ made an extensive [guide](https://community.getumbrel.com/t/guide-lnbits-without-tor/604) on how to do it. From 14344c2f03bbc92a9d4f78fa44c7346042679bba Mon Sep 17 00:00:00 2001 From: Arc <33088785+arcbtc@users.noreply.github.com> Date: Fri, 22 Jul 2022 11:23:16 +0100 Subject: [PATCH 29/33] Update FUNDING.yml --- .github/FUNDING.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index ad72b9d51..696d1aa20 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1 +1 @@ -custom: https://lnbits.com/paywall/GAqKguK5S8f6w5VNjS9DfK +custom: https://legend.lnbits.com/paywall/GAqKguK5S8f6w5VNjS9DfK From fd0d6bffcee30de7e1b3cb66f9106d638592d794 Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Fri, 22 Jul 2022 12:23:27 +0200 Subject: [PATCH 30/33] Update FUNDING.yml (#770) From 96af5fc3a7653bed9e7d094b99d64b0c7b5c33cc Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Sat, 23 Jul 2022 10:39:58 +0200 Subject: [PATCH 31/33] CI: Test `core/views/generic.py` (#772) * Adds tests for GET /wallet * Update `httpx` to `0.23.0` and `http-core` to `0.15.0` in `venv` installation path * Fix `secp256k1 = "==0.14.0"` and `cffi = "==1.15.0"` --- .github/workflows/regtest.yml | 4 +- .github/workflows/tests.yml | 12 +- Pipfile | 5 +- Pipfile.lock | 220 +++++++++++++++---------------- docs/guide/installation.md | 2 +- lnbits/core/views/generic.py | 4 +- requirements.txt | 7 +- tests/conftest.py | 47 ++++--- tests/core/views/test_api.py | 21 ++- tests/core/views/test_generic.py | 92 ++++++++++++- 10 files changed, 258 insertions(+), 156 deletions(-) diff --git a/.github/workflows/regtest.yml b/.github/workflows/regtest.yml index bdce0501b..7883cf199 100644 --- a/.github/workflows/regtest.yml +++ b/.github/workflows/regtest.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.7] + python-version: [3.8] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} @@ -54,7 +54,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.7] + python-version: [3.8] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 7b0b38e2e..218a557bc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -3,11 +3,11 @@ name: tests on: [push, pull_request] jobs: - sqlite: + venv-sqlite: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.7, 3.8] + python-version: [3.7, 3.8, 3.9] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} @@ -25,7 +25,7 @@ jobs: ./venv/bin/pip install pytest pytest-asyncio pytest-cov requests mock - name: Run tests run: make test - postgres: + venv-postgres: runs-on: ubuntu-latest services: postgres: @@ -44,7 +44,7 @@ jobs: --health-retries 5 strategy: matrix: - python-version: [3.7] + python-version: [3.8] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} @@ -68,11 +68,11 @@ jobs: uses: codecov/codecov-action@v3 with: file: ./coverage.xml - pipenv: + pipenv-sqlite: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.7] + python-version: [3.7, 3.8, 3.9] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} diff --git a/Pipfile b/Pipfile index 8ef241f12..f8c42a9dd 100644 --- a/Pipfile +++ b/Pipfile @@ -4,7 +4,7 @@ url = "https://pypi.org/simple" verify_ssl = true [requires] -python_version = "3.7" +python_version = "3.8" [packages] bitstring = "*" @@ -30,7 +30,8 @@ uvicorn = {extras = ["standard"], version = "*"} sse-starlette = "*" jinja2 = "==3.0.1" pyngrok = "*" -secp256k1 = "*" +secp256k1 = "==0.14.0" +cffi = "==1.15.0" pycryptodomex = "*" [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock index 6a89abb32..42d471c6f 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,11 +1,11 @@ { "_meta": { "hash": { - "sha256": "81bd288eea338c3bf1b70b8d30c1185b84c13a25a595bcddd77f74f7bc090032" + "sha256": "503e9942306106e40621c59f37a3ab866b483f8c5f27b879c1c6783dca30949f" }, "pipfile-spec": 6, "requires": { - "python_version": "3.7" + "python_version": "3.8" }, "sources": [ { @@ -80,72 +80,59 @@ }, "cffi": { "hashes": [ - "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5", - "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef", - "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104", - "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426", - "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405", - "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375", - "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a", - "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e", - "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc", - "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf", - "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185", - "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497", - "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3", - "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35", - "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c", - "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83", - "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21", - "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca", - "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984", - "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac", - "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd", - "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee", - "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a", - "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2", - "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192", - "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7", - "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585", - "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f", - "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e", - "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27", - "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b", - "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e", - "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e", - "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d", - "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c", - "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415", - "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82", - "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02", - "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314", - "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325", - "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c", - "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3", - "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914", - "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045", - "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d", - "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9", - "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5", - "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2", - "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c", - "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3", - "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2", - "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8", - "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d", - "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d", - "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9", - "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162", - "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76", - "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4", - "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e", - "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9", - "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6", - "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b", - "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01", - "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0" + "sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3", + "sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2", + "sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636", + "sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20", + "sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728", + "sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27", + "sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66", + "sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443", + "sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0", + "sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7", + "sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39", + "sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605", + "sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a", + "sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37", + "sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029", + "sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139", + "sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc", + "sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df", + "sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14", + "sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880", + "sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2", + "sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a", + "sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e", + "sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474", + "sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024", + "sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8", + "sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0", + "sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e", + "sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a", + "sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e", + "sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032", + "sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6", + "sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e", + "sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b", + "sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e", + "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954", + "sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962", + "sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c", + "sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4", + "sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55", + "sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962", + "sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023", + "sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c", + "sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6", + "sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8", + "sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382", + "sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7", + "sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc", + "sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997", + "sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796" ], - "version": "==1.15.1" + "index": "pypi", + "version": "==1.15.0" }, "click": { "hashes": [ @@ -179,11 +166,11 @@ }, "fastapi": { "hashes": [ - "sha256:15fcabd5c78c266fa7ae7d8de9b384bfc2375ee0503463a6febbe3bab69d6f65", - "sha256:3233d4a789ba018578658e2af1a4bb5e38bdd122ff722b313666a9b2c6786a83" + "sha256:cf0ff6db25b91d321050c4112baab0908c90f19b40bf257f9591d2f9780d1f22", + "sha256:d337563424ceada23857f73d5abe8dae0c28e4cccb53b2af06e78b7bb4a1c7d7" ], "index": "pypi", - "version": "==0.78.0" + "version": "==0.79.0" }, "h11": { "hashes": [ @@ -504,10 +491,11 @@ }, "pypng": { "hashes": [ - "sha256:76f8a1539ec56451da7ab7121f12a361969fe0f2d48d703d198ce2a99d6c5afd" + "sha256:4a43e969b8f5aaafb2a415536c1a8ec7e341cd6a3f957fd5b5f32a4cfeed902c", + "sha256:739c433ba96f078315de54c0db975aee537cbc3e1d0ae4ed9aab0ca1e427e2c1" ], "index": "pypi", - "version": "==0.0.21" + "version": "==0.20220715.0" }, "pyqrcode": { "hashes": [ @@ -707,7 +695,6 @@ "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6" ], "index": "pypi", - "markers": "python_version < '3.10'", "version": "==4.3.0" }, "uvicorn": { @@ -741,20 +728,25 @@ }, "watchfiles": { "hashes": [ - "sha256:56abed43e645d1f2d6def83e35999cc5758b051aff54ca1065cbfcaea15b3389", - "sha256:65ca99a94fcab29d00aa406526eb29cf198c0661854d59a315596064fed02141", - "sha256:67d4c66e46a564059df4aeedab78f09cba0b697bf36cc77566b0a7015dfb7f5d", - "sha256:6e0e8829d32b05151e6009570449f44f891e05f518e495d25f960e0d0b2d0064", - "sha256:715733c2ac9da67b2790788657ff6f8b3797eb31565bfc592289b523ae907ca2", - "sha256:7b81c6e404b2aa62482a719eb778e4a16d01728302dce1f1512c1e5354a73fda", - "sha256:82238d08d8a49f1a1ba254278cd4329a154f6100b028393059722ebeddd2ff3d", - "sha256:955e8f840e1996a8a41be57de4c03af7b1515a685b7fb6abe222f859e413a907", - "sha256:cab62510f990d195986302aa6a48ed636d685b099927049120d520c96069fa49", - "sha256:d1f9de6b776b3aff17898a4cf5ac5a2d0a16212ea7aad2bbe0ef6aa3e79a96af", - "sha256:d4f45acd1143db6d3ee77a4ff12d3239bc8083108133e6174e9dcce59c1f9902", - "sha256:f7f71012e096e11256fae3b37617a9777980f281e18deb2e789e85cd5b113935" + "sha256:059bd9596429f8c13604b2eb30888a5661b3c79099edc506f11b63be7afe3ca4", + "sha256:09490d258be8fdd7f5141a39b468dede0b4aa4a52f2b2dbfb0f3835ae7c23eca", + "sha256:1bb5f0117c8b93f8e1b22ac0be60cfeb00332959a72e6bbe2073fea27ed086e5", + "sha256:3d3f0397c9128971398a5cbb0fb45852ab2fa4472ac9724c031071e1e39970c0", + "sha256:43d1d517faffa8955c2da0e6f64268e38442d43b50ca73cb686df25f891e49a1", + "sha256:4f712dbe9d8c0365bf46ffe0dd9c6a62cc0acf05ba951f1a53de2b4d5bb63299", + "sha256:59498853d3214d1e4d9b1cb3a06b0011a11f24d31708b1734d9cd7f5a30fe1af", + "sha256:5e3d4c92091d16bca1d61920575dab5d6dcbceda76dccd5fb91da0b7390b4ee9", + "sha256:5fa786d102e7eabef22b2147af531aa70194aabcb35335be81c07c26382b0050", + "sha256:750e40db5efcf3f5f11602dbc6fdf8e96a0eefdbccd271093efe9fa2e9d02ed2", + "sha256:7c80e3907d21ca3f1689f42632d239fdc40ffc1d5f32f564997480f85e94c474", + "sha256:8d635dcba3aab2909bf568765547696d7465d30e2e9c6f5ab99da877b58d29bb", + "sha256:a5f64674559fac56a6bf2f5e086cb3758740140c80711fe3e016f5443b84ef15", + "sha256:bcd085980389bc64fe509188a9caffa4fe13b2616e2e3e674cde58f916b2a8ee", + "sha256:c9e3756cd2ba17e5042e8c9399a08e4bdbe1a366156a164e8373bda30ca096d0", + "sha256:cbdb7814ca43f85ab8569206ab2c3bcd51dd5d1ba582914246784414e6ada62e", + "sha256:d5fb4f3b5c884d4f22f643b0697edbb04942bcad961a8f9a9bfadb73e7a1e229" ], - "version": "==0.15.0" + "version": "==0.16.0" }, "websockets": { "hashes": [ @@ -923,32 +915,32 @@ }, "mypy": { "hashes": [ - "sha256:006be38474216b833eca29ff6b73e143386f352e10e9c2fbe76aa8549e5554f5", - "sha256:03c6cc893e7563e7b2949b969e63f02c000b32502a1b4d1314cabe391aa87d66", - "sha256:0e9f70df36405c25cc530a86eeda1e0867863d9471fe76d1273c783df3d35c2e", - "sha256:1ece702f29270ec6af25db8cf6185c04c02311c6bb21a69f423d40e527b75c56", - "sha256:3e09f1f983a71d0672bbc97ae33ee3709d10c779beb613febc36805a6e28bb4e", - "sha256:439c726a3b3da7ca84a0199a8ab444cd8896d95012c4a6c4a0d808e3147abf5d", - "sha256:5a0b53747f713f490affdceef835d8f0cb7285187a6a44c33821b6d1f46ed813", - "sha256:5f1332964963d4832a94bebc10f13d3279be3ce8f6c64da563d6ee6e2eeda932", - "sha256:63e85a03770ebf403291ec50097954cc5caf2a9205c888ce3a61bd3f82e17569", - "sha256:64759a273d590040a592e0f4186539858c948302c653c2eac840c7a3cd29e51b", - "sha256:697540876638ce349b01b6786bc6094ccdaba88af446a9abb967293ce6eaa2b0", - "sha256:9940e6916ed9371809b35b2154baf1f684acba935cd09928952310fbddaba648", - "sha256:9f5f5a74085d9a81a1f9c78081d60a0040c3efb3f28e5c9912b900adf59a16e6", - "sha256:a5ea0875a049de1b63b972456542f04643daf320d27dc592d7c3d9cd5d9bf950", - "sha256:b117650592e1782819829605a193360a08aa99f1fc23d1d71e1a75a142dc7e15", - "sha256:b24be97351084b11582fef18d79004b3e4db572219deee0212078f7cf6352723", - "sha256:b88f784e9e35dcaa075519096dc947a388319cb86811b6af621e3523980f1c8a", - "sha256:bdd5ca340beffb8c44cb9dc26697628d1b88c6bddf5c2f6eb308c46f269bb6f3", - "sha256:d5aaf1edaa7692490f72bdb9fbd941fbf2e201713523bdb3f4038be0af8846c6", - "sha256:e999229b9f3198c0c880d5e269f9f8129c8862451ce53a011326cad38b9ccd24", - "sha256:f4a21d01fc0ba4e31d82f0fff195682e29f9401a8bdb7173891070eb260aeb3b", - "sha256:f4b794db44168a4fc886e3450201365c9526a522c46ba089b55e1f11c163750d", - "sha256:f730d56cb924d371c26b8eaddeea3cc07d78ff51c521c6d04899ac6904b75492" + "sha256:02ef476f6dcb86e6f502ae39a16b93285fef97e7f1ff22932b657d1ef1f28655", + "sha256:0d054ef16b071149917085f51f89555a576e2618d5d9dd70bd6eea6410af3ac9", + "sha256:19830b7dba7d5356d3e26e2427a2ec91c994cd92d983142cbd025ebe81d69cf3", + "sha256:1f7656b69974a6933e987ee8ffb951d836272d6c0f81d727f1d0e2696074d9e6", + "sha256:23488a14a83bca6e54402c2e6435467a4138785df93ec85aeff64c6170077fb0", + "sha256:23c7ff43fff4b0df93a186581885c8512bc50fc4d4910e0f838e35d6bb6b5e58", + "sha256:25c5750ba5609a0c7550b73a33deb314ecfb559c350bb050b655505e8aed4103", + "sha256:2ad53cf9c3adc43cf3bea0a7d01a2f2e86db9fe7596dfecb4496a5dda63cbb09", + "sha256:3fa7a477b9900be9b7dd4bab30a12759e5abe9586574ceb944bc29cddf8f0417", + "sha256:40b0f21484238269ae6a57200c807d80debc6459d444c0489a102d7c6a75fa56", + "sha256:4b21e5b1a70dfb972490035128f305c39bc4bc253f34e96a4adf9127cf943eb2", + "sha256:5a361d92635ad4ada1b1b2d3630fc2f53f2127d51cf2def9db83cba32e47c856", + "sha256:77a514ea15d3007d33a9e2157b0ba9c267496acf12a7f2b9b9f8446337aac5b0", + "sha256:855048b6feb6dfe09d3353466004490b1872887150c5bb5caad7838b57328cc8", + "sha256:9796a2ba7b4b538649caa5cecd398d873f4022ed2333ffde58eaf604c4d2cb27", + "sha256:98e02d56ebe93981c41211c05adb630d1d26c14195d04d95e49cd97dbc046dc5", + "sha256:b793b899f7cf563b1e7044a5c97361196b938e92f0a4343a5d27966a53d2ec71", + "sha256:d1ea5d12c8e2d266b5fb8c7a5d2e9c0219fedfeb493b7ed60cd350322384ac27", + "sha256:d2022bfadb7a5c2ef410d6a7c9763188afdb7f3533f22a0a32be10d571ee4bbe", + "sha256:d3348e7eb2eea2472db611486846742d5d52d1290576de99d59edeb7cd4a42ca", + "sha256:d744f72eb39f69312bc6c2abf8ff6656973120e2eb3f3ec4f758ed47e414a4bf", + "sha256:ef943c72a786b0f8d90fd76e9b39ce81fb7171172daf84bf43eaf937e9f220a9", + "sha256:f2899a3cbd394da157194f913a931edfd4be5f274a88041c9dc2d9cdcb1c315c" ], "index": "pypi", - "version": "==0.961" + "version": "==0.971" }, "mypy-extensions": { "hashes": [ @@ -1002,12 +994,11 @@ }, "pytest-asyncio": { "hashes": [ - "sha256:16cf40bdf2b4fb7fc8e4b82bd05ce3fbcd454cbf7b92afc445fe299dabb88213", - "sha256:7659bdb0a9eb9c6e3ef992eef11a2b3e69697800ad02fb06374a210d85b29f91", - "sha256:8fafa6c52161addfd41ee7ab35f11836c5a16ec208f93ee388f752bea3493a84" + "sha256:7a97e37cfe1ed296e2e84941384bdd37c376453912d397ed39293e0916f521fa", + "sha256:ac4ebf3b6207259750bc32f4c1d8fcd7e79739edbc67ad0c58dd150b1d072fed" ], "index": "pypi", - "version": "==0.18.3" + "version": "==0.19.0" }, "pytest-cov": { "hashes": [ @@ -1153,7 +1144,6 @@ "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6" ], "index": "pypi", - "markers": "python_version < '3.10'", "version": "==4.3.0" }, "urllib3": { diff --git a/docs/guide/installation.md b/docs/guide/installation.md index 8509dcbef..591516f1a 100644 --- a/docs/guide/installation.md +++ b/docs/guide/installation.md @@ -72,7 +72,7 @@ If you want to host LNbits on the internet, run with the option `--host 0.0.0.0` Problems installing? These commands have helped us install LNbits. ```sh -sudo apt install pkg-config libffi-dev libpq-dev setuptools +sudo apt install pkg-config libffi-dev libpq-dev # if the secp256k1 build fails: # if you used pipenv (option 1) diff --git a/lnbits/core/views/generic.py b/lnbits/core/views/generic.py index 4366028d7..86f7ecff9 100644 --- a/lnbits/core/views/generic.py +++ b/lnbits/core/views/generic.py @@ -112,7 +112,7 @@ async def wallet( if not user_id: user = await get_user((await create_account()).id) - logger.info(f"Created new account for user {user.id}") + logger.info(f"Create user {user.id}") else: user = await get_user(user_id) if not user: @@ -139,7 +139,7 @@ async def wallet( status_code=status.HTTP_307_TEMPORARY_REDIRECT, ) - logger.info(f"Access wallet {wallet_name} of user {user.id}") + logger.debug(f"Access wallet {wallet_name}{'of user '+ user.id if user else ''}") wallet = user.get_wallet(wallet_id) if not wallet: return template_renderer().TemplateResponse( diff --git a/requirements.txt b/requirements.txt index 8359456ff..f8ccf47cb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,9 +14,9 @@ embit==0.4.9 environs==9.3.3 fastapi==0.68.1 h11==0.12.0 -httpcore==0.13.7 +httpcore==0.15.0 httptools==0.2.0 -httpx==0.19.0 +httpx==0.23.0 idna==3.2 importlib-metadata==4.8.1 jinja2==3.0.1 @@ -36,6 +36,7 @@ pyyaml==5.4.1 represent==1.6.0.post0 rfc3986==1.5.0 secp256k1==0.14.0 +cffi==1.15.0 shortuuid==1.0.1 six==1.16.0 sniffio==1.2.0 @@ -48,4 +49,4 @@ uvicorn==0.15.0 uvloop==0.16.0 watchgod==0.7 websockets==10.0 -zipp==3.5.0 \ No newline at end of file +zipp==3.5.0 diff --git a/tests/conftest.py b/tests/conftest.py index 8ab1ab4b4..adb1fa362 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -51,32 +51,42 @@ async def db(): @pytest_asyncio.fixture(scope="session") -async def from_user_wallet(): +async def from_user(): user = await create_account() + yield user + + +@pytest_asyncio.fixture(scope="session") +async def from_wallet(from_user): + user = from_user wallet = await create_wallet(user_id=user.id, wallet_name="test_wallet_from") await credit_wallet( wallet_id=wallet.id, amount=99999999, ) - # print("new from_user_wallet:", wallet) - yield user, wallet + yield wallet @pytest_asyncio.fixture(scope="session") -async def to_user_wallet(): +async def to_user(): user = await create_account() + yield user + + +@pytest_asyncio.fixture(scope="session") +async def to_wallet(to_user): + user = to_user wallet = await create_wallet(user_id=user.id, wallet_name="test_wallet_to") await credit_wallet( wallet_id=wallet.id, amount=99999999, ) - # print("new to_user_wallet:", wallet) - yield user, wallet + yield wallet @pytest_asyncio.fixture(scope="session") -async def inkey_headers_from(from_user_wallet): - _, wallet = from_user_wallet +async def inkey_headers_from(from_wallet): + wallet = from_wallet yield { "X-Api-Key": wallet.inkey, "Content-type": "application/json", @@ -84,8 +94,8 @@ async def inkey_headers_from(from_user_wallet): @pytest_asyncio.fixture(scope="session") -async def adminkey_headers_from(from_user_wallet): - _, wallet = from_user_wallet +async def adminkey_headers_from(from_wallet): + wallet = from_wallet yield { "X-Api-Key": wallet.adminkey, "Content-type": "application/json", @@ -93,8 +103,8 @@ async def adminkey_headers_from(from_user_wallet): @pytest_asyncio.fixture(scope="session") -async def inkey_headers_to(to_user_wallet): - _, wallet = to_user_wallet +async def inkey_headers_to(to_wallet): + wallet = to_wallet yield { "X-Api-Key": wallet.inkey, "Content-type": "application/json", @@ -102,8 +112,8 @@ async def inkey_headers_to(to_user_wallet): @pytest_asyncio.fixture(scope="session") -async def adminkey_headers_to(to_user_wallet): - _, wallet = to_user_wallet +async def adminkey_headers_to(to_wallet): + wallet = to_wallet yield { "X-Api-Key": wallet.adminkey, "Content-type": "application/json", @@ -111,18 +121,13 @@ async def adminkey_headers_to(to_user_wallet): @pytest_asyncio.fixture(scope="session") -async def invoice(to_user_wallet): - _, wallet = to_user_wallet +async def invoice(to_wallet): + wallet = to_wallet data = await get_random_invoice_data() invoiceData = CreateInvoiceData(**data) - # print("--------- New invoice!") - # print("wallet:") - # print(wallet) stuff_lock = asyncio.Lock() async with stuff_lock: invoice = await api_payments_create_invoice(invoiceData, wallet) await asyncio.sleep(1) - # print("invoice") - # print(invoice) yield invoice del invoice diff --git a/tests/core/views/test_api.py b/tests/core/views/test_api.py index 10e659aa4..6a5f82ecb 100644 --- a/tests/core/views/test_api.py +++ b/tests/core/views/test_api.py @@ -11,11 +11,26 @@ async def test_core_views_generic(client): assert response.status_code == 200 -# check GET /api/v1/wallet: wallet info +# check GET /api/v1/wallet with inkey: wallet info, no balance @pytest.mark.asyncio -async def test_get_wallet(client, inkey_headers_to): +async def test_get_wallet_inkey(client, inkey_headers_to): response = await client.get("/api/v1/wallet", headers=inkey_headers_to) - assert response.status_code < 300 + assert response.status_code == 200 + result = response.json() + assert "name" in result + assert "balance" in result + assert "id" not in result + + +# check GET /api/v1/wallet with adminkey: wallet info with balance +@pytest.mark.asyncio +async def test_get_wallet_adminkey(client, adminkey_headers_to): + response = await client.get("/api/v1/wallet", headers=adminkey_headers_to) + assert response.status_code == 200 + result = response.json() + assert "name" in result + assert "balance" in result + assert "id" in result # check POST /api/v1/payments: invoice creation diff --git a/tests/core/views/test_generic.py b/tests/core/views/test_generic.py index 88f5968b8..1dff6f012 100644 --- a/tests/core/views/test_generic.py +++ b/tests/core/views/test_generic.py @@ -6,4 +6,94 @@ from tests.conftest import client @pytest.mark.asyncio async def test_core_views_generic(client): response = await client.get("/") - assert response.status_code == 200 + assert response.status_code == 200, ( + str(response.url) + " " + str(response.status_code) + ) + + +# check GET /wallet: wallet info +@pytest.mark.asyncio +async def test_get_wallet(client): + response = await client.get("wallet") + assert response.status_code == 307, ( # redirect not modified + str(response.url) + " " + str(response.status_code) + ) + + +# check GET /wallet: do not allow redirects, expect code 307 +@pytest.mark.asyncio +async def test_get_wallet_no_redirect(client): + response = await client.get("wallet", follow_redirects=False) + assert response.status_code == 307, ( + str(response.url) + " " + str(response.status_code) + ) + + # determine the next redirect location + request = client.build_request("GET", "wallet") + i = 0 + while request is not None: + response = await client.send(request) + request = response.next_request + if i == 0: + assert response.status_code == 307, ( # first redirect + str(response.url) + " " + str(response.status_code) + ) + elif i == 1: + assert response.status_code == 200, ( # then get the actual page + str(response.url) + " " + str(response.status_code) + ) + i += 1 + + +# check GET /wallet: wrong user, expect 204 +@pytest.mark.asyncio +async def test_get_wallet_with_nonexistent_user(client): + response = await client.get("wallet", params={"usr": "1"}) + assert response.status_code == 204, ( + str(response.url) + " " + str(response.status_code) + ) + + +# check GET /wallet: with user +@pytest.mark.asyncio +async def test_get_wallet_with_user(client, to_user): + response = await client.get("wallet", params={"usr": to_user.id}) + assert response.status_code == 307, ( + str(response.url) + " " + str(response.status_code) + ) + + # determine the next redirect location + request = client.build_request("GET", "wallet", params={"usr": to_user.id}) + i = 0 + while request is not None: + response = await client.send(request) + request = response.next_request + if i == 0: + assert response.status_code == 307, ( # first redirect + str(response.url) + " " + str(response.status_code) + ) + elif i == 1: + assert response.status_code == 200, ( # then get the actual page + str(response.url) + " " + str(response.status_code) + ) + i += 1 + + +# check GET /wallet: wallet and user +@pytest.mark.asyncio +async def test_get_wallet_with_user_and_wallet(client, to_user, to_wallet): + response = await client.get( + "wallet", params={"usr": to_user.id, "wal": to_wallet.id} + ) + assert response.status_code == 200, ( + str(response.url) + " " + str(response.status_code) + ) + + +# check GET /wallet: wrong wallet and user, expect 204 +@pytest.mark.asyncio +async def test_get_wallet_with_user_and_wrong_wallet(client, to_user, to_wallet): + response = await client.get("wallet", params={"usr": to_user.id, "wal": "1"}) + assert response.status_code == 204, ( + str(response.url) + " " + str(response.status_code) + ) From c0c26fb98ed5b277e3217b903874e8165d392436 Mon Sep 17 00:00:00 2001 From: blackcoffeexbt <87530449+blackcoffeexbt@users.noreply.github.com> Date: Sat, 23 Jul 2022 09:46:30 +0100 Subject: [PATCH 32/33] Extension list UI improvements (#769) * Extensions list is now sorted alphabetically * Added extension list search * Prettified changes * Removed console.log * Code improvements based on motorina0 feedback * Remove console.log from lnbits/templates/base.html Run prettier --- lnbits/core/static/js/extensions.js | 32 ++++++++++++++++++++++ lnbits/core/templates/core/extensions.html | 15 +++++++++- lnbits/static/js/base.js | 8 ++++-- lnbits/templates/base.html | 1 - 4 files changed, 52 insertions(+), 4 deletions(-) diff --git a/lnbits/core/static/js/extensions.js b/lnbits/core/static/js/extensions.js index 85ace775f..ec8f811c6 100644 --- a/lnbits/core/static/js/extensions.js +++ b/lnbits/core/static/js/extensions.js @@ -1,4 +1,36 @@ new Vue({ el: '#vue', + data: function () { + return { + searchTerm: '', + filteredExtensions: null + } + }, + mounted() { + this.filteredExtensions = this.g.extensions + }, + watch: { + searchTerm(term) { + // Reset the filter + this.filteredExtensions = this.g.extensions + if (term !== '') { + // Filter the extensions list + function extensionNameContains(searchTerm) { + return function (extension) { + return ( + extension.name.toLowerCase().includes(searchTerm.toLowerCase()) || + extension.shortDescription + .toLowerCase() + .includes(searchTerm.toLowerCase()) + ) + } + } + + this.filteredExtensions = this.filteredExtensions.filter( + extensionNameContains(term) + ) + } + } + }, mixins: [windowMixin] }) diff --git a/lnbits/core/templates/core/extensions.html b/lnbits/core/templates/core/extensions.html index daeb660fa..1b5279030 100644 --- a/lnbits/core/templates/core/extensions.html +++ b/lnbits/core/templates/core/extensions.html @@ -2,10 +2,23 @@ %} {% block scripts %} {{ window_vars(user) }} {% endblock %} {% block page %} +
+
+ + + +
+
+
diff --git a/lnbits/static/js/base.js b/lnbits/static/js/base.js index 7c0e9958d..cd5fd1c4c 100644 --- a/lnbits/static/js/base.js +++ b/lnbits/static/js/base.js @@ -392,7 +392,7 @@ window.windowMixin = { } if (window.extensions) { var user = this.g.user - this.g.extensions = Object.freeze( + const extensions = Object.freeze( window.extensions .map(function (data) { return window.LNbits.map.extension(data) @@ -413,9 +413,13 @@ window.windowMixin = { return obj }) .sort(function (a, b) { - return a.name > b.name + const nameA = a.name.toUpperCase() + const nameB = b.name.toUpperCase() + return nameA < nameB ? -1 : nameA > nameB ? 1 : 0 }) ) + + this.g.extensions = extensions } } } diff --git a/lnbits/templates/base.html b/lnbits/templates/base.html index 6ab1ec840..acca92e7a 100644 --- a/lnbits/templates/base.html +++ b/lnbits/templates/base.html @@ -228,7 +228,6 @@