1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/django-fmd_ynh.git synced 2024-09-03 18:26:27 +02:00

Merge pull request #22 from YunoHost-Apps/dev

Project update
This commit is contained in:
Jens Diemer 2022-10-04 12:10:03 +02:00 committed by GitHub
commit 6033855adc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 689 additions and 601 deletions

View file

@ -10,7 +10,7 @@ trim_trailing_whitespace = true
insert_final_newline = true insert_final_newline = true
[*.py] [*.py]
max_line_length = 120 max_line_length = 100
[{Makefile,**.mk}] [{Makefile,**.mk}]
indent_style = tab indent_style = tab
@ -18,4 +18,3 @@ insert_final_newline = false
[*.yml] [*.yml]
indent_style = tab indent_style = tab
indent_size = 4

View file

@ -27,6 +27,11 @@ jobs:
with: with:
python-version: '${{ matrix.python-version }}' python-version: '${{ matrix.python-version }}'
- uses: actions/cache@v2
with:
path: ~/.cache/
key: dot-cache-files
- name: 'Install package' - name: 'Install package'
run: | run: |
pip3 install poetry pip3 install poetry
@ -40,6 +45,10 @@ jobs:
run: | run: |
make pytest make pytest
- name: 'Run Safety check'
run: |
make safety
- name: 'Upload coverage report' - name: 'Upload coverage report'
uses: codecov/codecov-action@v2 uses: codecov/codecov-action@v2
with: with:

2
.gitignore vendored
View file

@ -1,9 +1,9 @@
.* .*
!.github !.github
!.gitkeep
!.editorconfig !.editorconfig
!.flake8 !.flake8
!.gitignore !.gitignore
!/doc/screenshots/.gitkeep
__pycache__ __pycache__
secret.txt secret.txt
/local_test/ /local_test/

View file

@ -17,24 +17,21 @@ check-poetry:
fi fi
install-poetry: ## install or update poetry install-poetry: ## install or update poetry
pip3 install -U pip curl -sSL https://install.python-poetry.org | python3 -
pip3 install -U poetry
install: check-poetry ## install project via poetry install: check-poetry ## install project via poetry
poetry install poetry install
update: install-poetry ## update the sources and installation and generate "conf/requirements.txt" update: check-poetry ## update the sources and installation and generate "conf/requirements.txt"
poetry run pip install -U pip poetry self update
poetry update poetry update -v
poetry export -f requirements.txt --output conf/requirements.txt poetry export -f requirements.txt --output conf/requirements.txt
lint: ## Run code formatters and linter lint: ## Run code formatters and linter
poetry run flynt --fail-on-change --line-length=${MAX_LINE_LENGTH} .
poetry run isort --check-only . poetry run isort --check-only .
poetry run flake8 . poetry run flake8 .
fix-code-style: ## Fix code formatting fix-code-style: ## Fix code formatting
poetry run flynt --line-length=${MAX_LINE_LENGTH} .
poetry run black --verbose --safe --line-length=${MAX_LINE_LENGTH} --skip-string-normalization . poetry run black --verbose --safe --line-length=${MAX_LINE_LENGTH} --skip-string-normalization .
poetry run isort . poetry run isort .
@ -53,6 +50,8 @@ local-test: install ## Run local_test.py to run the project locally
local-diff-settings: ## Run "manage.py diffsettings" with local test local-diff-settings: ## Run "manage.py diffsettings" with local test
poetry run python3 local_test/opt_yunohost/manage.py diffsettings poetry run python3 local_test/opt_yunohost/manage.py diffsettings
safety: ## Run https://github.com/pyupio/safety
poetry run safety check --full-report
############################################################################## ##############################################################################

View file

@ -1,212 +1,215 @@
asgiref==3.5.2; python_version >= "3.7" and python_full_version < "4.0.0" \ asgiref==3.5.2 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:1d2880b792ae8757289136f1db2b7b99100ce959b2aa57fd69dab783d05afac4 \ --hash=sha256:1d2880b792ae8757289136f1db2b7b99100ce959b2aa57fd69dab783d05afac4 \
--hash=sha256:4a29362a6acebe09bf1d6640db38c1dc3d9217c68e6f9f6204d72667fc19a424 --hash=sha256:4a29362a6acebe09bf1d6640db38c1dc3d9217c68e6f9f6204d72667fc19a424
async-timeout==4.0.2; python_version >= "3.7" and python_full_version < "4.0.0" \ async-timeout==4.0.2 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15 \ --hash=sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15 \
--hash=sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c --hash=sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c
bleach==5.0.1; python_version >= "3.7" and python_full_version < "4.0.0" \ bleach==5.0.1 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \ --hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \
--hash=sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c --hash=sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c
bx-django-utils==26; python_version >= "3.7" and python_full_version < "4.0.0" \ bx-django-utils==35 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:c04776c4c6b275ddcadae79fd1578e6ae9ba92d8cf752a9ee4f2b70a22f4236e \ --hash=sha256:341b27ad0b72a903acf2f28def0fe371def811c1b2305da9806124869a698fc8 \
--hash=sha256:19349d0a8fa165d87b4fd544efb61418f7d6c41cfabaa46d0153bb6d844262a1 --hash=sha256:5151806d349a9dafc8dba9636239422022bab211b5b02afa52fce1f58ec2e6ab
bx-py-utils==68; python_version >= "3.7" and python_full_version < "4.0.0" \ bx-py-utils==69 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:00c3fbc9b5f48626a0a58141aaa90104349bac9723941c64f528f8742b0961db \ --hash=sha256:728fd575c4d5048e114b502a97d19679f9abcda90889a6896534c48348320460 \
--hash=sha256:fe5808c379db7165a51cbf5e4d947ef783d78bdfb5c47665e85e9cfe0b520ff9 --hash=sha256:b25419e020c9c5ea16938a45cf5120086a5ac29648be78a8eb98ae202515fee1
certifi==2022.6.15; python_version >= "3.7" and python_version < "4" and python_full_version < "4.0.0" \ certifi==2022.9.24 ; python_version >= "3.7" and python_version < "4" \
--hash=sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412 \ --hash=sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14 \
--hash=sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d --hash=sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382
charset-normalizer==2.1.0; python_version >= "3.7" and python_version < "4" and python_full_version < "4.0.0" and python_full_version >= "3.6.0" \ charset-normalizer==2.1.1 ; python_version >= "3.7" and python_version < "4" \
--hash=sha256:575e708016ff3a5e3681541cb9d79312c416835686d054a23accb873b254f413 \ --hash=sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845 \
--hash=sha256:5189b6f22b01957427f35b6a08d9a0bc45b46d3788ef5a92e978433c7a35f8a5 --hash=sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f
colorama==0.4.5; python_version >= "3.7" and python_full_version < "3.0.0" and sys_platform == "win32" or python_version >= "3.7" and python_full_version < "4.0.0" and sys_platform == "win32" and python_full_version >= "3.5.0" \ colorama==0.4.5 ; python_version >= "3.7" and python_full_version < "4.0.0" and sys_platform == "win32" \
--hash=sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da \ --hash=sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da \
--hash=sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4 --hash=sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4
colorlog==6.6.0; python_version >= "3.7" and python_full_version < "4.0.0" \ colorlog==6.7.0 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:351c51e866c86c3217f08e4b067a7974a678be78f07f85fc2d55b8babde6d94e \ --hash=sha256:0d33ca236784a1ba3ff9c532d4964126d8a2c44f1f0cb1d2b0728196f512f662 \
--hash=sha256:344f73204009e4c83c5b6beb00b3c45dc70fcdae3c80db919e0a4171d006fde8 --hash=sha256:bd94bd21c1e13fac7bd3153f4bc3a7dc0eb0974b8bc2fdf1a989e474f6e582e5
deprecated==1.2.13; python_version >= "3.7" and python_full_version < "3.0.0" or python_version >= "3.7" and python_full_version < "4.0.0" and python_full_version >= "3.4.0" \ deprecated==1.2.13 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d \ --hash=sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d \
--hash=sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d --hash=sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d
django-axes==5.36.0; python_version >= "3.7" and python_full_version < "4.0.0" \ django-axes==5.39.0 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:bac08a7047fde26ffb54813c971fd40eeadb4ecb8d342a6e47d53de666d1a792 \ --hash=sha256:8f039f8e98f050f13f654efca599d8a04d0b57d330c590cf89ec2bf731c9a7fb \
--hash=sha256:466e6ed1affd0866c78f245ee658d2619f74250aca5856852d86e61dba400eda --hash=sha256:97702552f7939c81db5bba2ef855ae43f20df92fa261cb79fd4c8633ba3b3955
django-debug-toolbar==3.5.0; python_version >= "3.7" and python_full_version < "4.0.0" \ django-debug-toolbar==3.7.0 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:97965f2630692de316ea0c1ca5bfa81660d7ba13146dbc6be2059cf55b35d0e5 \ --hash=sha256:1e3acad24e3d351ba45c6fa2072e4164820307332a776b16c9f06d1f89503465 \
--hash=sha256:89a52128309eb4da12738801ff0c202d2ff8730d1c3225fac6acf630c303e661 --hash=sha256:80de23066b624d3970fd296cf02d61988e5d56c31aa0dc4a428970b46e2883a8
django-fmd==0.3.2; python_version >= "3.7" and python_full_version < "4.0.0" \ django-fmd==0.3.2 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:52bc6ff3af170b4ea0860f42863f24abccf904c75b6179197caef55cec793295 \ --hash=sha256:52bc6ff3af170b4ea0860f42863f24abccf904c75b6179197caef55cec793295 \
--hash=sha256:eb02e13d68591c657e3c1e9fb8e536140f4736921c94b7aa17dc98480c1eec31 --hash=sha256:eb02e13d68591c657e3c1e9fb8e536140f4736921c94b7aa17dc98480c1eec31
django-ipware==4.0.2; python_version >= "3.7" and python_full_version < "3.0.0" or python_version >= "3.7" and python_full_version < "4.0.0" and python_full_version >= "3.6.0" \ django-ipware==4.0.2 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:602a58325a4808bd19197fef2676a0b2da2df40d0ecf21be414b2ff48c72ad05 \ --hash=sha256:602a58325a4808bd19197fef2676a0b2da2df40d0ecf21be414b2ff48c72ad05 \
--hash=sha256:878dbb06a87e25550798e9ef3204ed70a200dd8b15e47dcef848cf08244f04c9 --hash=sha256:878dbb06a87e25550798e9ef3204ed70a200dd8b15e47dcef848cf08244f04c9
django-redis==5.2.0; python_version >= "3.7" and python_full_version < "4.0.0" \ django-redis==5.2.0 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:8a99e5582c79f894168f5865c52bd921213253b7fd64d16733ae4591564465de \ --hash=sha256:1d037dc02b11ad7aa11f655d26dac3fb1af32630f61ef4428860a2e29ff92026 \
--hash=sha256:1d037dc02b11ad7aa11f655d26dac3fb1af32630f61ef4428860a2e29ff92026 --hash=sha256:8a99e5582c79f894168f5865c52bd921213253b7fd64d16733ae4591564465de
django-tools==0.51.0; python_version >= "3.7" and python_full_version < "4.0.0" \ django-tools==0.54.0 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:ebe69065ae5504e66667125858a7edd1cf6627e2b96cb03aeaab9e0ee3b8b98b \ --hash=sha256:5040a91282be9d1c9d379b0c65da50bcb3691bff03cee54fd4123ace238c3a43 \
--hash=sha256:4fe3768d4d863e7f3fa8bd7a3f014c4320ab320776218641fe760202c08f2d5a --hash=sha256:a7b7bfa5b9c5a81966454d17dffb2403cee25a806c858ee0486a08798227598f
django-yunohost-integration==0.3.0; python_version >= "3.7" and python_full_version < "4.0.0" \ django-yunohost-integration[ynh]==0.4.1 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:f7f8e9d55c50231bb32d3809b240d6ac718aadac1a1f471284baa1bfa6e98dff \ --hash=sha256:3769859db283a6b4d17468aeb1decab2f79d4b3e128b341342948e7bb3121e8a \
--hash=sha256:d0e9cc91d241075613cb54b5da0879ad9b8ad3d22b84130cd7a331025650406e --hash=sha256:e097cd209f3e09cbe325eadea36e3eb64c051690297c38dd89a1cd64bc35d92e
django==3.2.15; python_version >= "3.7" and python_full_version < "4.0.0" \ django==3.2.15 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:115baf5049d5cf4163e43492cdc7139c306ed6d451e7d3571fe9612903903713 \ --hash=sha256:115baf5049d5cf4163e43492cdc7139c306ed6d451e7d3571fe9612903903713 \
--hash=sha256:f71934b1a822f14a86c9ac9634053689279cd04ae69cb6ade4a59471b886582b --hash=sha256:f71934b1a822f14a86c9ac9634053689279cd04ae69cb6ade4a59471b886582b
gunicorn==20.1.0; python_version >= "3.7" and python_full_version < "4.0.0" \ gunicorn==20.1.0 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e \ --hash=sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e \
--hash=sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8 --hash=sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8
icdiff==2.0.5; python_version >= "3.7" and python_full_version < "4.0.0" \ icdiff==2.0.5 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:35d24b728e48b7e0a12bdb69386d3bfc7eef4fe922d0ac1cd70d6e5c11630bae --hash=sha256:35d24b728e48b7e0a12bdb69386d3bfc7eef4fe922d0ac1cd70d6e5c11630bae
idna==3.3; python_version >= "3.7" and python_version < "4" and python_full_version < "4.0.0" \ idna==3.4 ; python_version >= "3.7" and python_version < "4" \
--hash=sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff \ --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \
--hash=sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2
importlib-metadata==4.2.0; python_version >= "3.7" and python_full_version < "4.0.0" and python_version < "3.8" \ importlib-metadata==4.2.0 ; python_version >= "3.7" and python_version < "3.8" \
--hash=sha256:057e92c15bc8d9e8109738a48db0ccb31b4d9d5cfbee5a8670879a30be66304b \ --hash=sha256:057e92c15bc8d9e8109738a48db0ccb31b4d9d5cfbee5a8670879a30be66304b \
--hash=sha256:b7e52a1f8dec14a75ea73e0891f3060099ca1d8e6a462a4dff11c3e119ea1b31 --hash=sha256:b7e52a1f8dec14a75ea73e0891f3060099ca1d8e6a462a4dff11c3e119ea1b31
packaging==21.3; python_version >= "3.7" and python_full_version < "4.0.0" \ packaging==21.3 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522 \ --hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb \
--hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb --hash=sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522
pprintpp==0.4.0; python_version >= "3.7" and python_full_version < "4.0.0" \ pprintpp==0.4.0 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:b6b4dcdd0c0c0d75e4d7b2f21a9e933e5b2ce62b26e1a54537f9651ae5a5c01d \ --hash=sha256:b6b4dcdd0c0c0d75e4d7b2f21a9e933e5b2ce62b26e1a54537f9651ae5a5c01d \
--hash=sha256:ea826108e2c7f49dc6d66c752973c3fc9749142a798d6b254e1e301cfdbc6403 --hash=sha256:ea826108e2c7f49dc6d66c752973c3fc9749142a798d6b254e1e301cfdbc6403
psycopg2==2.9.3; python_version >= "3.6" \ psycopg2==2.9.3 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:06f32425949bd5fe8f625c49f17ebb9784e1e4fe928b7cce72edc36fb68e4c0c \
--hash=sha256:0762c27d018edbcb2d34d51596e4346c983bd27c330218c56c4dc25ef7e819bf \
--hash=sha256:083707a696e5e1c330af2508d8fab36f9700b26621ccbcb538abe22e15485362 \ --hash=sha256:083707a696e5e1c330af2508d8fab36f9700b26621ccbcb538abe22e15485362 \
--hash=sha256:d3ca6421b942f60c008f81a3541e8faf6865a28d5a9b48544b0ee4f40cac7fca \ --hash=sha256:34b33e0162cfcaad151f249c2649fd1030010c16f4bbc40a604c1cb77173dcf7 \
--hash=sha256:4295093a6ae3434d33ec6baab4ca5512a5082cc43c0505293087b8a46d108461 \
--hash=sha256:8cf3878353cc04b053822896bc4922b194792df9df2f1ad8da01fb3043602126 \
--hash=sha256:8e841d1bf3434da985cc5ef13e6f75c8981ced601fd70cc6bf33351b91562981 \
--hash=sha256:9572e08b50aed176ef6d66f15a21d823bb6f6d23152d35e8451d7d2d18fdac56 \ --hash=sha256:9572e08b50aed176ef6d66f15a21d823bb6f6d23152d35e8451d7d2d18fdac56 \
--hash=sha256:a81e3866f99382dfe8c15a151f1ca5fde5815fde879348fe5a9884a7c092a305 \ --hash=sha256:a81e3866f99382dfe8c15a151f1ca5fde5815fde879348fe5a9884a7c092a305 \
--hash=sha256:cb10d44e6694d763fa1078a26f7f6137d69f555a78ec85dc2ef716c37447e4b2 \ --hash=sha256:cb10d44e6694d763fa1078a26f7f6137d69f555a78ec85dc2ef716c37447e4b2 \
--hash=sha256:4295093a6ae3434d33ec6baab4ca5512a5082cc43c0505293087b8a46d108461 \ --hash=sha256:d3ca6421b942f60c008f81a3541e8faf6865a28d5a9b48544b0ee4f40cac7fca
--hash=sha256:34b33e0162cfcaad151f249c2649fd1030010c16f4bbc40a604c1cb77173dcf7 \ pycryptodomex==3.15.0 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:0762c27d018edbcb2d34d51596e4346c983bd27c330218c56c4dc25ef7e819bf \
--hash=sha256:8cf3878353cc04b053822896bc4922b194792df9df2f1ad8da01fb3043602126 \
--hash=sha256:06f32425949bd5fe8f625c49f17ebb9784e1e4fe928b7cce72edc36fb68e4c0c \
--hash=sha256:8e841d1bf3434da985cc5ef13e6f75c8981ced601fd70cc6bf33351b91562981
pycryptodomex==3.15.0; python_version >= "3.7" and python_full_version < "3.0.0" or python_version >= "3.7" and python_full_version < "4.0.0" and python_full_version >= "3.5.0" \
--hash=sha256:6f5b6ba8aefd624834bc177a2ac292734996bb030f9d1b388e7504103b6fcddf \
--hash=sha256:4540904c09704b6f831059c0dfb38584acb82cb97b0125cd52688c1f1e3fffa6 \
--hash=sha256:0fadb9f7fa3150577800eef35f62a8a24b9ddf1563ff060d9bd3af22d3952c8c \
--hash=sha256:fc9bc7a9b79fe5c750fc81a307052f8daabb709bdaabb0fb18fb136b66b653b5 \
--hash=sha256:f8be976cec59b11f011f790b88aca67b4ea2bd286578d0bd3e31bcd19afcd3e4 \
--hash=sha256:78d9621cf0ea35abf2d38fa2ca6d0634eab6c991a78373498ab149953787e5e5 \
--hash=sha256:b6306403228edde6e289f626a3908a2f7f67c344e712cf7c0a508bab3ad9e381 \
--hash=sha256:48697790203909fab02a33226fda546604f4e2653f9d47bc5d3eb40879fa7c64 \
--hash=sha256:18e2ab4813883ae63396c0ffe50b13554b32bb69ec56f0afaf052e7a7ae0d55b \
--hash=sha256:3709f13ca3852b0b07fc04a2c03b379189232b24007c466be0f605dd4723e9d4 \
--hash=sha256:191e73bc84a8064ad1874dba0ebadedd7cce4dedee998549518f2c74a003b2e1 \
--hash=sha256:e3164a18348bd53c69b4435ebfb4ac8a4076291ffa2a70b54f0c4b80c7834b1d \
--hash=sha256:5676a132169a1c1a3712edf25250722ebc8c9102aa9abd814df063ca8362454f \
--hash=sha256:e2b12968522a0358b8917fc7b28865acac002f02f4c4c6020fcb264d76bfd06d \
--hash=sha256:e47bf8776a7e15576887f04314f5228c6527b99946e6638cf2f16da56d260cab \
--hash=sha256:996e1ba717077ce1e6d4849af7a1426f38b07b3d173b879e27d5e26d2e958beb \
--hash=sha256:65204412d0c6a8e3c41e21e93a5e6054a74fea501afa03046a388cf042e3377a \
--hash=sha256:dd452a5af7014e866206d41751886c9b4bf379a339fdf2dbfc7dd16c0fb4f8e0 \
--hash=sha256:b9279adc16e4b0f590ceff581f53a80179b02cba9056010d733eb4196134a870 \
--hash=sha256:46b3f05f2f7ac7841053da4e0f69616929ca3c42f238c405f6c3df7759ad2780 \
--hash=sha256:8eecdf9cdc7343001d047f951b9cc805cd68cb6cd77b20ea46af5bffc5bd3dfb \
--hash=sha256:67e1e6a92151023ccdfcfbc0afb3314ad30080793b4c27956ea06ab1fb9bcd8a \
--hash=sha256:c4cb9cb492ea7dcdf222a8d19a1d09002798ea516aeae8877245206d27326d86 \
--hash=sha256:94c7b60e1f52e1a87715571327baea0733708ab4723346598beca4a3b6879794 \
--hash=sha256:04cc393045a8f19dd110c975e30f38ed7ab3faf21ede415ea67afebd95a22380 \ --hash=sha256:04cc393045a8f19dd110c975e30f38ed7ab3faf21ede415ea67afebd95a22380 \
--hash=sha256:0776bfaf2c48154ab54ea45392847c1283d2fcf64e232e85565f858baedfc1fa \ --hash=sha256:0776bfaf2c48154ab54ea45392847c1283d2fcf64e232e85565f858baedfc1fa \
--hash=sha256:463119d7d22d0fc04a0f9122e9d3e6121c6648bcb12a052b51bd1eed1b996aa2 \ --hash=sha256:0fadb9f7fa3150577800eef35f62a8a24b9ddf1563ff060d9bd3af22d3952c8c \
--hash=sha256:a07a64709e366c2041cd5cfbca592b43998bf4df88f7b0ca73dca37071ccf1bd \ --hash=sha256:18e2ab4813883ae63396c0ffe50b13554b32bb69ec56f0afaf052e7a7ae0d55b \
--hash=sha256:191e73bc84a8064ad1874dba0ebadedd7cce4dedee998549518f2c74a003b2e1 \
--hash=sha256:35a8f7afe1867118330e2e0e0bf759c409e28557fb1fc2fbb1c6c937297dbe9a \ --hash=sha256:35a8f7afe1867118330e2e0e0bf759c409e28557fb1fc2fbb1c6c937297dbe9a \
--hash=sha256:7341f1bb2dadb0d1a0047f34c3a58208a92423cdbd3244d998e4b28df5eac0ed --hash=sha256:3709f13ca3852b0b07fc04a2c03b379189232b24007c466be0f605dd4723e9d4 \
pyparsing==3.0.9; python_version >= "3.7" and python_full_version < "4.0.0" and python_full_version >= "3.6.8" \ --hash=sha256:4540904c09704b6f831059c0dfb38584acb82cb97b0125cd52688c1f1e3fffa6 \
--hash=sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc \ --hash=sha256:463119d7d22d0fc04a0f9122e9d3e6121c6648bcb12a052b51bd1eed1b996aa2 \
--hash=sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb --hash=sha256:46b3f05f2f7ac7841053da4e0f69616929ca3c42f238c405f6c3df7759ad2780 \
python-stdnum==1.17; python_version >= "3.7" and python_full_version < "4.0.0" \ --hash=sha256:48697790203909fab02a33226fda546604f4e2653f9d47bc5d3eb40879fa7c64 \
--hash=sha256:5676a132169a1c1a3712edf25250722ebc8c9102aa9abd814df063ca8362454f \
--hash=sha256:65204412d0c6a8e3c41e21e93a5e6054a74fea501afa03046a388cf042e3377a \
--hash=sha256:67e1e6a92151023ccdfcfbc0afb3314ad30080793b4c27956ea06ab1fb9bcd8a \
--hash=sha256:6f5b6ba8aefd624834bc177a2ac292734996bb030f9d1b388e7504103b6fcddf \
--hash=sha256:7341f1bb2dadb0d1a0047f34c3a58208a92423cdbd3244d998e4b28df5eac0ed \
--hash=sha256:78d9621cf0ea35abf2d38fa2ca6d0634eab6c991a78373498ab149953787e5e5 \
--hash=sha256:8eecdf9cdc7343001d047f951b9cc805cd68cb6cd77b20ea46af5bffc5bd3dfb \
--hash=sha256:94c7b60e1f52e1a87715571327baea0733708ab4723346598beca4a3b6879794 \
--hash=sha256:996e1ba717077ce1e6d4849af7a1426f38b07b3d173b879e27d5e26d2e958beb \
--hash=sha256:a07a64709e366c2041cd5cfbca592b43998bf4df88f7b0ca73dca37071ccf1bd \
--hash=sha256:b6306403228edde6e289f626a3908a2f7f67c344e712cf7c0a508bab3ad9e381 \
--hash=sha256:b9279adc16e4b0f590ceff581f53a80179b02cba9056010d733eb4196134a870 \
--hash=sha256:c4cb9cb492ea7dcdf222a8d19a1d09002798ea516aeae8877245206d27326d86 \
--hash=sha256:dd452a5af7014e866206d41751886c9b4bf379a339fdf2dbfc7dd16c0fb4f8e0 \
--hash=sha256:e2b12968522a0358b8917fc7b28865acac002f02f4c4c6020fcb264d76bfd06d \
--hash=sha256:e3164a18348bd53c69b4435ebfb4ac8a4076291ffa2a70b54f0c4b80c7834b1d \
--hash=sha256:e47bf8776a7e15576887f04314f5228c6527b99946e6638cf2f16da56d260cab \
--hash=sha256:f8be976cec59b11f011f790b88aca67b4ea2bd286578d0bd3e31bcd19afcd3e4 \
--hash=sha256:fc9bc7a9b79fe5c750fc81a307052f8daabb709bdaabb0fb18fb136b66b653b5
pyparsing==3.0.9 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb \
--hash=sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc
python-stdnum==1.17 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:374e2b5e13912ccdbf50b0b23fca2c3e0531174805c32d74e145f37756328340 \ --hash=sha256:374e2b5e13912ccdbf50b0b23fca2c3e0531174805c32d74e145f37756328340 \
--hash=sha256:a46e6cf9652807314d369b654b255c86a59f93d18be2834f3d567ed1a346c547 --hash=sha256:a46e6cf9652807314d369b654b255c86a59f93d18be2834f3d567ed1a346c547
pytz==2022.2.1; python_version >= "3.7" and python_full_version < "4.0.0" \ pytz==2022.4 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:220f481bdafa09c3955dfbdddb7b57780e9a94f5127e35456a48589b9e0c0197 \ --hash=sha256:2c0784747071402c6e99f0bafdb7da0fa22645f06554c7ae06bf6358897e9c91 \
--hash=sha256:cea221417204f2d1a2aa03ddae3e867921971d0d76f14d87abb4414415bbdcf5 --hash=sha256:48ce799d83b6f8aab2020e369b627446696619e79645419610b9facd909b3174
redis==4.3.4; python_version >= "3.7" and python_full_version < "4.0.0" \ redis==4.3.4 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:a52d5694c9eb4292770084fa8c863f79367ca19884b329ab574d5cb2036b3e54 \ --hash=sha256:a52d5694c9eb4292770084fa8c863f79367ca19884b329ab574d5cb2036b3e54 \
--hash=sha256:ddf27071df4adf3821c4f2ca59d67525c3a82e5f268bed97b813cb4fabf87880 --hash=sha256:ddf27071df4adf3821c4f2ca59d67525c3a82e5f268bed97b813cb4fabf87880
requests==2.28.1; python_version >= "3.7" and python_version < "4" and python_full_version < "4.0.0" \ requests==2.28.1 ; python_version >= "3.7" and python_version < "4" \
--hash=sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349 \ --hash=sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983 \
--hash=sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983 --hash=sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349
six==1.16.0; python_version >= "3.7" and python_full_version < "3.0.0" or python_version >= "3.7" and python_full_version < "4.0.0" and python_full_version >= "3.3.0" \ setuptools==65.4.1 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 \ --hash=sha256:1b6bdc6161661409c5f21508763dc63ab20a9ac2f8ba20029aaaa7fdb9118012 \
--hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 --hash=sha256:3050e338e5871e70c72983072fe34f6032ae1cdeeeb67338199c2f74e083a80e
sqlparse==0.4.2; python_version >= "3.7" and python_full_version < "4.0.0" \ six==1.16.0 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:48719e356bb8b42991bdbb1e8b83223757b93789c00910a616a071910ca4a64d \ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
--hash=sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
typing-extensions==4.3.0; python_version >= "3.7" and python_full_version < "4.0.0" and python_version < "3.8" \ sqlparse==0.4.3 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:0323c0ec29cd52bceabc1b4d9d579e311f3e4961b98d174201d5622a23b85e34 \
--hash=sha256:69ca804846bb114d2ec380e4360a8a340db83f0ccf3afceeb1404df028f57268
typing-extensions==4.3.0 ; python_version >= "3.7" and python_version < "3.8" \
--hash=sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02 \ --hash=sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02 \
--hash=sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6 --hash=sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6
urllib3==1.26.11; python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "4" or python_full_version >= "3.6.0" and python_version < "4" and python_version >= "3.7" and python_full_version < "4.0.0" \ urllib3==1.26.12 ; python_version >= "3.7" and python_version < "4" \
--hash=sha256:c33ccba33c819596124764c23a97d25f32b28433ba0dedeb77d873a38722c9bc \ --hash=sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e \
--hash=sha256:ea6e8fb210b19d950fab93b60c9009226c63a28808bc8386e05301e25883ac0a --hash=sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997
webencodings==0.5.1; python_version >= "3.7" and python_full_version < "4.0.0" \ webencodings==0.5.1 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \
--hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923
wrapt==1.14.1; python_version >= "3.7" and python_full_version < "3.0.0" or python_version >= "3.7" and python_full_version < "4.0.0" and python_full_version >= "3.5.0" \ wrapt==1.14.1 ; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3 \
--hash=sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef \
--hash=sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28 \
--hash=sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59 \
--hash=sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87 \
--hash=sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1 \
--hash=sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b \
--hash=sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462 \
--hash=sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1 \
--hash=sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320 \
--hash=sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2 \
--hash=sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4 \
--hash=sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069 \
--hash=sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310 \
--hash=sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f \
--hash=sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656 \
--hash=sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c \
--hash=sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8 \
--hash=sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164 \
--hash=sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907 \
--hash=sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3 \
--hash=sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3 \ --hash=sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3 \
--hash=sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d \
--hash=sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7 \
--hash=sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00 \
--hash=sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4 \
--hash=sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1 \
--hash=sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1 \
--hash=sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff \
--hash=sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d \
--hash=sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1 \
--hash=sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569 \
--hash=sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed \
--hash=sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471 \
--hash=sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248 \
--hash=sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68 \
--hash=sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d \
--hash=sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77 \
--hash=sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7 \
--hash=sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015 \
--hash=sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a \
--hash=sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853 \
--hash=sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c \
--hash=sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456 \
--hash=sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f \
--hash=sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc \
--hash=sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1 \
--hash=sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af \
--hash=sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b \ --hash=sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b \
--hash=sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0 \ --hash=sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4 \
--hash=sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2 \
--hash=sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656 \
--hash=sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3 \
--hash=sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff \
--hash=sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310 \
--hash=sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a \
--hash=sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57 \ --hash=sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57 \
--hash=sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5 \ --hash=sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069 \
--hash=sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d \
--hash=sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383 \ --hash=sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383 \
--hash=sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe \
--hash=sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87 \
--hash=sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d \
--hash=sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b \
--hash=sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907 \
--hash=sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f \
--hash=sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0 \
--hash=sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28 \
--hash=sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1 \
--hash=sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853 \
--hash=sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc \
--hash=sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3 \
--hash=sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3 \
--hash=sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164 \
--hash=sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1 \
--hash=sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c \
--hash=sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1 \
--hash=sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7 \
--hash=sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1 \
--hash=sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320 \
--hash=sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed \
--hash=sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1 \
--hash=sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248 \
--hash=sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c \
--hash=sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456 \
--hash=sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77 \
--hash=sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef \
--hash=sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1 \
--hash=sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7 \ --hash=sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7 \
--hash=sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86 \ --hash=sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86 \
--hash=sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735 \ --hash=sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4 \
--hash=sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b \ --hash=sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d \
--hash=sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d \
--hash=sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8 \
--hash=sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5 \
--hash=sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471 \
--hash=sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00 \
--hash=sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68 \
--hash=sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3 \ --hash=sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3 \
--hash=sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3 \ --hash=sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d \
--hash=sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe \ --hash=sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735 \
--hash=sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d \
--hash=sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569 \
--hash=sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7 \
--hash=sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59 \
--hash=sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5 \ --hash=sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5 \
--hash=sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb \ --hash=sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb \
--hash=sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d --hash=sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b \
zipp==3.8.1; python_version >= "3.7" and python_full_version < "4.0.0" and python_version < "3.8" \ --hash=sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f \
--hash=sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009 \ --hash=sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462 \
--hash=sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2 --hash=sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015 \
--hash=sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af
zipp==3.8.1 ; python_version >= "3.7" and python_version < "3.8" \
--hash=sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2 \
--hash=sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009

View file

@ -11,11 +11,13 @@
from pathlib import Path as __Path from pathlib import Path as __Path
from django.core.validators import EmailValidator as __EmailValidator from django_yunohost_integration.base_settings import * # noqa:F401,F403
from django_yunohost_integration.base_settings import * # noqa
from django_yunohost_integration.secret_key import get_or_create_secret as __get_or_create_secret from django_yunohost_integration.secret_key import get_or_create_secret as __get_or_create_secret
from findmydevice_project.settings.base import * # noqa from findmydevice_project.settings.base import * # noqa:F401,F403
from django_yunohost_integration.base_settings import LOGGING # noqa:F401 isort:skip
FINALPATH = __Path('__FINALPATH__') # /opt/yunohost/$app FINALPATH = __Path('__FINALPATH__') # /opt/yunohost/$app
@ -30,33 +32,16 @@ assert LOG_FILE.is_file(), f'File not exists: {LOG_FILE}'
PATH_URL = '__PATH_URL__' # $YNH_APP_ARG_PATH PATH_URL = '__PATH_URL__' # $YNH_APP_ARG_PATH
PATH_URL = PATH_URL.strip('/') PATH_URL = PATH_URL.strip('/')
ROOT_URLCONF = 'urls' # /opt/yunohost/django-fmd/urls.py
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# config_panel.toml settings: # config_panel.toml settings:
DEBUG_ENABLED = '__DEBUG_ENABLED__' DEBUG_ENABLED = '__DEBUG_ENABLED__'
DEBUG = bool(int(DEBUG_ENABLED))
LOG_LEVEL = '__LOG_LEVEL__' LOG_LEVEL = '__LOG_LEVEL__'
ADMIN_EMAIL = '__ADMIN_EMAIL__' ADMIN_EMAIL = '__ADMIN_EMAIL__'
DEFAULT_FROM_EMAIL = '__DEFAULT_FROM_EMAIL__' DEFAULT_FROM_EMAIL = '__DEFAULT_FROM_EMAIL__'
# -----------------------------------------------------------------------------
# Use/convert/validate config_panel.toml settings:
DEBUG = bool(int(DEBUG_ENABLED))
assert LOG_LEVEL in (
'DEBUG',
'INFO',
'WARNING',
'ERROR',
'CRITICAL',
), f'Invalid LOG_LEVEL: {LOG_LEVEL!r}'
__EmailValidator(
message='ADMIN_EMAIL %(value)r from config panel is not valid!',
)(ADMIN_EMAIL)
__EmailValidator(
message='DEFAULT_FROM_EMAIL %(value)r from config panel is not valid!',
)(DEFAULT_FROM_EMAIL)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@ -95,6 +80,7 @@ LOGIN_URL = '/yunohost/sso/'
LOGOUT_REDIRECT_URL = '/yunohost/sso/' LOGOUT_REDIRECT_URL = '/yunohost/sso/'
# /yunohost/sso/?action=logout # /yunohost/sso/?action=logout
ROOT_URLCONF = 'urls' # .../conf/urls.py
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@ -126,7 +112,10 @@ EMAIL_SUBJECT_PREFIX = f'[{SITE_TITLE}] '
# E-mail address that error messages come from. # E-mail address that error messages come from.
SERVER_EMAIL = 'noreply@__DOMAIN__' SERVER_EMAIL = ADMIN_EMAIL
# Default email address to use for various automated correspondence from
# the site managers. Used for registration emails.
# List of URLs your site is supposed to serve # List of URLs your site is supposed to serve
ALLOWED_HOSTS = ['__DOMAIN__'] ALLOWED_HOSTS = ['__DOMAIN__']
@ -164,54 +153,18 @@ MEDIA_ROOT = str(PUBLIC_PATH / 'media')
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
LOGGING = { # Set log file to e.g.: /var/log/$app/$app.log
'version': 1, LOGGING['handlers']['log_file']['filename'] = str(LOG_FILE)
'disable_existing_loggers': True,
'formatters': { LOGGING['loggers']['findmydevice'] = {
'verbose': { 'handlers': ['syslog', 'log_file', 'mail_admins'],
'format': '{asctime} {levelname} {name} {module}.{funcName} {message}', 'level': 'INFO',
'style': '{',
},
},
'handlers': {
'mail_admins': {
'level': 'ERROR',
'formatter': 'verbose',
'class': 'django.utils.log.AdminEmailHandler',
'include_html': True,
},
'log_file': {
'level': 'DEBUG',
'class': 'logging.handlers.WatchedFileHandler',
'formatter': 'verbose',
'filename': str(LOG_FILE),
},
},
'loggers': {
'': {'handlers': ['log_file', 'mail_admins'], 'level': LOG_LEVEL, 'propagate': False},
'django': {'handlers': ['log_file', 'mail_admins'], 'level': LOG_LEVEL, 'propagate': False},
'axes': {'handlers': ['log_file', 'mail_admins'], 'level': LOG_LEVEL, 'propagate': False},
'django_tools': {
'handlers': ['log_file', 'mail_admins'],
'level': LOG_LEVEL,
'propagate': False, 'propagate': False,
},
'django_yunohost_integration': {
'handlers': ['log_file', 'mail_admins'],
'level': LOG_LEVEL,
'propagate': False,
},
'findmydevice': {
'handlers': ['log_file', 'mail_admins'],
'level': LOG_LEVEL,
'propagate': False,
},
},
} }
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
try: try:
from local_settings import * # noqa from local_settings import * # noqa:F401,F403
except ImportError: except ImportError:
pass pass

View file

@ -1,3 +1,7 @@
"""
urls.py
~~~~~~~
"""
from django.conf import settings from django.conf import settings
from django.urls import include, path from django.urls import include, path
from django.views.static import serve from django.views.static import serve

View file

@ -3,6 +3,8 @@
version = "1.0" version = "1.0"
[main] [main]
name.en = "Main configuration"
name.fr = "Configuration principale"
services = ["__APP__"] services = ["__APP__"]
[main.config] [main.config]
@ -10,13 +12,13 @@ services = ["__APP__"]
[main.config.default_from_email] [main.config.default_from_email]
ask = "from email" ask = "from email"
type = "string" type = "email"
help = "Default email address to use for various automated emails." help = "Default email address to use for various automated emails."
bind = "default_from_email:__FINALPATH__/settings.py" bind = "default_from_email:__FINALPATH__/settings.py"
[main.config.admin_email] [main.config.admin_email]
ask = "ADMIN email" ask = "ADMIN email"
type = "string" type = "email"
help = "EMail address for error emails." help = "EMail address for error emails."
bind = "admin_email:__FINALPATH__/settings.py" bind = "admin_email:__FINALPATH__/settings.py"

View file

@ -24,9 +24,6 @@ def main():
runserver=True, runserver=True,
extra_replacements={ extra_replacements={
'__DEBUG_ENABLED__': '1', '__DEBUG_ENABLED__': '1',
'__LOG_LEVEL__': 'DEBUG',
'__ADMIN_EMAIL__': 'foo-bar@test.tld',
'__DEFAULT_FROM_EMAIL__': 'django_app@test.tld',
}, },
) )

View file

@ -6,7 +6,7 @@
"en": "Web based FritzBox management using Python/Django." "en": "Web based FritzBox management using Python/Django."
}, },
"version": "0.3.2~ynh1", "version": "0.3.2~ynh1",
"url": "https://gitlab.com/jedie/django-find-my-device", "url": "https://github.com/YunoHost-Apps/django-fmd_ynh",
"upstream": { "upstream": {
"license": "GPL-3.0", "license": "GPL-3.0",
"website": "https://gitlab.com/jedie/django-find-my-device", "website": "https://gitlab.com/jedie/django-find-my-device",
@ -19,7 +19,7 @@
}, },
"previous_maintainers": [], "previous_maintainers": [],
"requirements": { "requirements": {
"yunohost": ">= 4.3.0" "yunohost": ">= 4.4"
}, },
"multi_instance": false, "multi_instance": false,
"services": [ "services": [

561
poetry.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,22 +1,27 @@
[tool.poetry] [tool.poetry]
name = "django-fmd_ynh" name = "django-fmd_ynh"
version = "0.3.2~ynh1" version = "0.3.2+ynh1"
description = "Test django-fmd_ynh via local_test.py" description = "Test django-fmd_ynh via local_test.py"
authors = ["JensDiemer <git@jensdiemer.de>"] authors = ["JensDiemer <git@jensdiemer.de>"]
license = "GPL" license = "GPL"
homepage = "https://github.com/YunoHost-Apps/django-fmd_ynh"
[tool.poetry.urls]
"Bug Tracker" = "https://github.com/YunoHost-Apps/django_example_ynh/issues"
[tool.poetry.dependencies] [tool.poetry.dependencies]
# Keep Python 3.7 until Yunohost contains a newer Python Version ;) python = ">=3.7,<4.0.0" # TODO: Update to >=3.8 after YunoHost updates to Bullseye
python = ">=3.7,<4.0.0"
django-fmd = ">=0.3.2" # https://gitlab.com/jedie/django-find-my-device django-fmd = ">=0.3.2" # https://gitlab.com/jedie/django-find-my-device
# Note: "ynh" extras will install gunicorn, psycopg2, django-redis and django-axes # extras "ynh" will install: gunicorn, psycopg2, django-redis and django-axes
django_yunohost_integration = {version = ">=v0.2.0", extras = ["ynh"]} # see: https://github.com/YunoHost-Apps/django_yunohost_integration/blob/main/pyproject.toml
django_yunohost_integration = {version = ">=0.4.1", extras = ["ynh"]} # https://github.com/YunoHost-Apps/django_yunohost_integration
psycopg2 = "*" # https://www.psycopg.org/docs/install.html#build-prerequisites
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
bx_py_utils = "*" bx_py_utils = "*" # https://github.com/boxine/bx_py_utils
bx_django_utils = "*" # https://github.com/boxine/bx_django_utils
tox = "*" tox = "*"
pytest = "*" pytest = "*"
pytest-cov = "*" pytest-cov = "*"
@ -25,13 +30,14 @@ pytest-darker = "*" # https://github.com/akaihola/pytest-darker
coveralls = "*" coveralls = "*"
isort = "*" isort = "*"
flake8 = "*" flake8 = "*"
flynt = "*" EditorConfig = "*" # https://github.com/editorconfig/editorconfig-core-py
darker = "*" # https://github.com/akaihola/darker safety = "*" # https://github.com/pyupio/safety
pyupgrade = "*" requests = "*" # https://github.com/psf/requests
beautifulsoup4 = "*" packaging = "*" # https://github.com/pypa/packagi
beautifulsoup4 = "*" # https://pypi.org/project/beautifulsoup4/
[build-system] [build-system]
requires = ["poetry-core>=1.0.0"] requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api" build-backend = "poetry.core.masonry.api"
@ -51,16 +57,12 @@ lint = [
log_level = "INFO" log_level = "INFO"
[tool.flynt]
line_length = 100
[tool.isort] [tool.isort]
# https://pycqa.github.io/isort/docs/configuration/config_files/#pyprojecttoml-preferred-format # https://pycqa.github.io/isort/docs/configuration/config_files/#pyprojecttoml-preferred-format
atomic=true atomic=true
profile='black' profile='black'
line_length=100 line_length=100
skip_glob=["*/htmlcov/*","*/migrations/*"] skip_glob=["*/htmlcov/*","*/migrations/*","*/local_test/*"]
known_first_party=["findmydevice","findmydevice_project","findmydevice_tests"] known_first_party=["findmydevice","findmydevice_project","findmydevice_tests"]
lines_after_imports=2 lines_after_imports=2
@ -88,22 +90,25 @@ addopts = """
--darker --darker
--doctest-modules --doctest-modules
--failed-first --failed-first
--last-failed-no-failures all
--new-first --new-first
""" """
# TODO: --mypy
[tool.coverage.run]
omit = [".*"]
[tool.tox] [tool.tox]
# https://tox.readthedocs.io/en/latest/example/basic.html#pyproject-toml-tox-legacy-ini # https://tox.readthedocs.io/en/latest/example/basic.html#pyproject-toml-tox-legacy-ini
legacy_tox_ini = """ legacy_tox_ini = """
[tox] [tox]
isolated_build = True isolated_build = True
envlist = px310,py39,py38,py37 envlist = py{37,38,39,310}
skip_missing_interpreters = True skip_missing_interpreters = True
[testenv] [testenv]
passenv = * passenv = *
whitelist_externals = pytest whitelist_externals = make
commands = commands =
pytest findmydevice findmydevice_project make pytest
""" """

View file

@ -43,7 +43,7 @@ log_file="${log_path}/${app}.log"
#================================================= #=================================================
# dependencies used by the app # dependencies used by the app
pkg_dependencies="build-essential python3-dev python3-pip python3-venv git libpq-dev postgresql postgresql-contrib libjpeg-dev" pkg_dependencies="build-essential python3-dev python3-pip python3-venv git libpq-dev postgresql postgresql-contrib"
#================================================= #=================================================
# Redis HELPERS # Redis HELPERS
@ -87,17 +87,3 @@ ynh_redis_remove_db() {
redis-cli -n "$db" flushall redis-cli -n "$db" flushall
} }
#=================================================
# Execute a command as another user
# usage: ynh_exec_as USER COMMAND [ARG ...]
ynh_exec_as() {
local USER=$1
shift 1
if [[ $USER = $(whoami) ]]; then
eval "$@"
else
sudo -u "$USER" "$@"
fi
}

View file

@ -6,6 +6,9 @@
# IMPORT GENERIC HELPERS # IMPORT GENERIC HELPERS
#================================================= #=================================================
YNH_APP_ARG_DOMAIN=$YNH_APP_NEW_DOMAIN
YNH_APP_ARG_PATH=$YNH_APP_NEW_PATH
source _common.sh source _common.sh
source /usr/share/yunohost/helpers source /usr/share/yunohost/helpers
@ -83,7 +86,7 @@ fi
#================================================= #=================================================
# STOP SYSTEMD SERVICE # STOP SYSTEMD SERVICE
#================================================= #=================================================
ynh_script_progression --message="Stopping systemd services..." ynh_script_progression --message="Stopping systemd service '$app'..."
ynh_systemd_action --service_name="$app" --action="stop" ynh_systemd_action --service_name="$app" --action="stop"
@ -123,7 +126,10 @@ fi
#================================================= #=================================================
# MODIFY SETTINGS # MODIFY SETTINGS
#================================================= #=================================================
ynh_script_progression --message="Modify django-fmd's config file..." ynh_script_progression --message="Modify $app config file..."
domain=$YNH_APP_NEW_DOMAIN
path_url=$YNH_APP_NEW_PATH
ynh_add_config --template="settings.py" --destination="$final_path/settings.py" ynh_add_config --template="settings.py" --destination="$final_path/settings.py"
@ -132,7 +138,7 @@ ynh_add_config --template="settings.py" --destination="$final_path/settings.py"
#================================================= #=================================================
# START SYSTEMD SERVICE # START SYSTEMD SERVICE
#================================================= #=================================================
ynh_script_progression --message="Starting systemd services..." --weight=5 ynh_script_progression --message="Starting systemd service '$app'..." --weight=5
ynh_systemd_action --service_name="$app" --action="start" ynh_systemd_action --service_name="$app" --action="start"

View file

@ -72,7 +72,7 @@ ynh_app_setting_set --app="$app" --key=default_from_email --value="$default_from
#================================================= #=================================================
# INSTALL DEPENDENCIES # INSTALL DEPENDENCIES
#================================================= #=================================================
ynh_script_progression --message="Installing dependencies..." --weight=20 ynh_script_progression --message="Installing $app dependencies..." --weight=20
ynh_exec_warn_less ynh_install_app_dependencies "$pkg_dependencies" ynh_exec_warn_less ynh_install_app_dependencies "$pkg_dependencies"
@ -103,7 +103,7 @@ ynh_add_nginx_config "public_path" "port"
#================================================= #=================================================
# CREATE DEDICATED USER # CREATE DEDICATED USER
#================================================= #=================================================
ynh_script_progression --message="Configuring system user..." ynh_script_progression --message="Configuring system user '$app'..."
# A home directory for venv and settings etc. # A home directory for venv and settings etc.
ynh_system_user_create --username="$app" --home_dir="$final_path" --use_shell ynh_system_user_create --username="$app" --home_dir="$final_path" --use_shell
@ -140,7 +140,7 @@ ynh_script_progression --message="Install project via pip..." --weight=45
#================================================= #=================================================
# copy config files # copy config files
# ================================================ # ================================================
ynh_script_progression --message="Create project configuration files..." ynh_script_progression --message="Create $app configuration files..."
ynh_add_config --template="gunicorn.conf.py" --destination="$final_path/gunicorn.conf.py" ynh_add_config --template="gunicorn.conf.py" --destination="$final_path/gunicorn.conf.py"
@ -188,7 +188,7 @@ ynh_use_logrotate "$log_file"
#================================================= #=================================================
ynh_script_progression --message="Integrating service in YunoHost..." ynh_script_progression --message="Integrating service in YunoHost..."
yunohost service add $app --description="Web based management to catalog things" --log="${log_file}" yunohost service add $app --log="${log_file}"
#================================================= #=================================================
# GENERIC FINALIZATION # GENERIC FINALIZATION
@ -208,7 +208,7 @@ chmod o-rwx "$final_path"
#================================================= #=================================================
# SETUP SYSTEMD # SETUP SYSTEMD
#================================================= #=================================================
ynh_script_progression --message="Configuring a systemd service..." ynh_script_progression --message="Configuring systemd service '$app'..." --weight=5
# https://yunohost.org/en/contribute/packaging_apps/helpers # https://yunohost.org/en/contribute/packaging_apps/helpers
# https://github.com/YunoHost/yunohost/blob/dev/helpers/systemd # https://github.com/YunoHost/yunohost/blob/dev/helpers/systemd
@ -219,20 +219,18 @@ ynh_add_systemd_config --service="$app" --template="systemd.service"
#================================================= #=================================================
ynh_script_progression --message="Configuring SSOwat..." ynh_script_progression --message="Configuring SSOwat..."
# Currently there are no public pages: # Make app public if necessary or protect it
# if [ $is_public -eq 1 ]
## Make app public if necessary or protect it then
#if [ $is_public -eq 1 ] # Everyone can access the app.
#then # The "main" permission is automatically created before the install script.
# # Everyone can access the app. ynh_permission_update --permission "main" --add "visitors"
# # The "main" permission is automatically created before the install script. fi
# ynh_permission_update --permission "main" --add "visitors"
#fi
#================================================= #=================================================
# Start the app server via systemd # Start the app server via systemd
#================================================= #=================================================
ynh_script_progression --message="Starting django_example_ynh's services..." --weight=5 ynh_script_progression --message="Starting systemd service '$app'..." --weight=5
ynh_systemd_action --service_name="$app" --action="start" ynh_systemd_action --service_name="$app" --action="start"

View file

@ -36,7 +36,7 @@ fi
#================================================= #=================================================
# STOP PYINVENTORY'S SERVICES # STOP PYINVENTORY'S SERVICES
#================================================= #=================================================
ynh_script_progression --message="Stopping and removing systemd services..." --weight=5 ynh_script_progression --message="Stopping and removing systemd service '$app'..." --weight=5
ynh_remove_systemd_config --service="$app" ynh_remove_systemd_config --service="$app"

View file

@ -48,7 +48,7 @@ ynh_restore_file --origin_path="/etc/nginx/conf.d/$domain.d/$app.conf"
#================================================= #=================================================
# RESTORE THE APP MAIN DIR # RESTORE THE APP MAIN DIR
#================================================= #=================================================
ynh_script_progression --message="Restoring the app main directory..." ynh_script_progression --message="Restoring $app main directory..."
ynh_restore_file --origin_path="$final_path" ynh_restore_file --origin_path="$final_path"
ynh_restore_file --origin_path="$public_path" ynh_restore_file --origin_path="$public_path"
@ -127,7 +127,7 @@ systemctl enable $app.service --quiet
#================================================= #=================================================
ynh_script_progression --message="Integrating service in YunoHost..." ynh_script_progression --message="Integrating service in YunoHost..."
yunohost service add $app --description="Web based management to catalog things" --log="${log_file}" yunohost service add $app --log="${log_file}"
#================================================= #=================================================
# RESTORE THE LOGROTATE CONFIGURATION # RESTORE THE LOGROTATE CONFIGURATION
@ -158,7 +158,7 @@ chmod o-rwx "$final_path"
#================================================= #=================================================
# START PYINVENTORY # START PYINVENTORY
#================================================= #=================================================
ynh_script_progression --message="Starting a systemd service..." --weight=5 ynh_script_progression --message="Starting systemd service '$app'..." --weight=5
ynh_systemd_action --service_name="$app" --action="start" ynh_systemd_action --service_name="$app" --action="start"

View file

@ -58,7 +58,7 @@ fi
#================================================= #=================================================
# BACKUP BEFORE UPGRADE THEN ACTIVE TRAP # BACKUP BEFORE UPGRADE THEN ACTIVE TRAP
#================================================= #=================================================
ynh_script_progression --message="Backing up the app before upgrading (may take a while)..." --weight=40 ynh_script_progression --message="Backing up $app before upgrading (may take a while)..." --weight=40
# Backup the current version of the app # Backup the current version of the app
ynh_backup_before_upgrade ynh_backup_before_upgrade
@ -74,7 +74,7 @@ ynh_abort_if_errors
#================================================= #=================================================
# STOP SYSTEMD SERVICE # STOP SYSTEMD SERVICE
#================================================= #=================================================
ynh_script_progression --message="Stopping systemd services..." --weight=5 ynh_script_progression --message="Stopping systemd service '$app'..." --weight=5
ynh_systemd_action --service_name="$app" --action="stop" ynh_systemd_action --service_name="$app" --action="stop"
@ -108,7 +108,7 @@ ynh_system_user_create --username="$app" --home_dir="$final_path" --use_shell
#================================================= #=================================================
# SETUP SYSTEMD # SETUP SYSTEMD
#================================================= #=================================================
ynh_script_progression --message="Configuring a systemd service..." ynh_script_progression --message="Configuring systemd service '$app'..." --weight=5
ynh_add_systemd_config --service="$app" --template="systemd.service" ynh_add_systemd_config --service="$app" --template="systemd.service"
@ -189,7 +189,7 @@ ynh_use_logrotate --non-append
#================================================= #=================================================
ynh_script_progression --message="Integrating service in YunoHost..." ynh_script_progression --message="Integrating service in YunoHost..."
yunohost service add $app --description="Web based management to catalog things" --log="${log_file}" yunohost service add $app --log="${log_file}"
#================================================= #=================================================
# GENERIC FINALIZATION # GENERIC FINALIZATION
@ -209,7 +209,7 @@ chmod o-rwx "$final_path"
#================================================= #=================================================
# Start the app server via systemd # Start the app server via systemd
#================================================= #=================================================
ynh_script_progression --message="Starting django_example_ynh's services..." --weight=5 ynh_script_progression --message="Starting systemd service '$app'..." --weight=5
ynh_systemd_action --service_name="$app" --action="start" ynh_systemd_action --service_name="$app" --action="start"

View file

@ -1,5 +1,4 @@
from pathlib import Path from axes.models import AccessLog
from bx_django_utils.test_utils.html_assertion import ( from bx_django_utils.test_utils.html_assertion import (
HtmlAssertionMixin, HtmlAssertionMixin,
assert_html_response_snapshot, assert_html_response_snapshot,
@ -9,10 +8,8 @@ from django.contrib.auth.models import User
from django.http import FileResponse, HttpResponse from django.http import FileResponse, HttpResponse
from django.test import override_settings from django.test import override_settings
from django.test.testcases import TestCase from django.test.testcases import TestCase
from django.urls import NoReverseMatch
from django.urls.base import reverse from django.urls.base import reverse
from django_yunohost_integration.test_utils import generate_basic_auth from django_yunohost_integration.test_utils import generate_basic_auth
from django_yunohost_integration.views import request_media_debug_view
from findmydevice import __version__ from findmydevice import __version__
@ -34,31 +31,23 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
assert settings.PATH_URL == 'app_path' assert settings.PATH_URL == 'app_path'
def assert_path(path, end_text): assert str(settings.FINALPATH).endswith('/local_test/opt_yunohost')
assert isinstance(path, Path) assert str(settings.PUBLIC_PATH).endswith('/local_test/var_www')
path = str(path) assert str(settings.LOG_FILE).endswith('/local_test/var_log_django-fmd.log')
assert path.endswith(end_text)
assert_path(settings.FINALPATH, '/local_test/opt_yunohost') assert settings.ROOT_URLCONF == 'urls'
assert_path(settings.PUBLIC_PATH, '/local_test/var_www')
assert_path(settings.LOG_FILE, '/local_test/var_log_django-fmd.log')
assert settings.ROOT_URLCONF == 'urls' # ./conf/urls.py def test_config_panel_settings(self):
# config_panel.toml settings, set via tests.conftest.pytest_configure():
middlewares = [entry.rsplit('.', 1)[-1] for entry in settings.MIDDLEWARE] assert settings.DEBUG_ENABLED == '0' and settings.DEBUG is False
assert 'SSOwatRemoteUserMiddleware' in middlewares assert settings.LOG_LEVEL == 'INFO'
assert settings.ADMIN_EMAIL == 'foo-bar@test.tld'
auth_backends = [entry.rsplit('.', 1)[-1] for entry in settings.AUTHENTICATION_BACKENDS] assert settings.DEFAULT_FROM_EMAIL == 'django_app@test.tld'
assert 'SSOwatUserBackend' in auth_backends
def test_urls(self):
assert reverse('admin:index') == '/app_path/admin/'
# The django_yunohost_integration debug view should not be available:
with self.assertRaises(NoReverseMatch):
reverse(request_media_debug_view)
def test_auth(self): def test_auth(self):
assert settings.PATH_URL == 'app_path'
assert reverse('admin:index') == '/app_path/admin/'
# SecurityMiddleware should redirects all non-HTTPS requests to HTTPS: # SecurityMiddleware should redirects all non-HTTPS requests to HTTPS:
assert settings.SECURE_SSL_REDIRECT is True assert settings.SECURE_SSL_REDIRECT is True
response = self.client.get('/app_path/', secure=False) response = self.client.get('/app_path/', secure=False)
@ -109,7 +98,6 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
) )
assert_html_response_snapshot(response2, query_selector=None, validate=False) assert_html_response_snapshot(response2, query_selector=None, validate=False)
@override_settings(SECURE_SSL_REDIRECT=False)
def test_create_unknown_user(self): def test_create_unknown_user(self):
assert User.objects.count() == 0 assert User.objects.count() == 0
@ -120,13 +108,14 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
HTTP_REMOTE_USER='test', HTTP_REMOTE_USER='test',
HTTP_AUTH_USER='test', HTTP_AUTH_USER='test',
HTTP_AUTHORIZATION='basic dGVzdDp0ZXN0MTIz', HTTP_AUTHORIZATION='basic dGVzdDp0ZXN0MTIz',
secure=True,
) )
assert User.objects.count() == 1 assert User.objects.count() == 1
user = User.objects.first() user = User.objects.first()
assert user.username == 'test' assert user.username == 'test'
assert user.is_active is True assert user.is_active is True
assert user.is_staff is True # Set by: django_yunohost_integration assert user.is_staff is True # Set by: conf.setup_user.setup_project_user
assert user.is_superuser is False assert user.is_superuser is False
assert response.status_code == 200 assert response.status_code == 200
@ -139,9 +128,9 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
), ),
) )
@override_settings(SECURE_SSL_REDIRECT=False)
def test_wrong_auth_user(self): def test_wrong_auth_user(self):
assert User.objects.count() == 0 assert User.objects.count() == 0
assert AccessLog.objects.count() == 0
self.client.cookies['SSOwAuthUser'] = 'test' self.client.cookies['SSOwAuthUser'] = 'test'
@ -150,20 +139,23 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
HTTP_REMOTE_USER='test', HTTP_REMOTE_USER='test',
HTTP_AUTH_USER='foobar', # <<< wrong user name HTTP_AUTH_USER='foobar', # <<< wrong user name
HTTP_AUTHORIZATION='basic dGVzdDp0ZXN0MTIz', HTTP_AUTHORIZATION='basic dGVzdDp0ZXN0MTIz',
secure=True,
) )
assert User.objects.count() == 1 assert User.objects.count() == 1
user = User.objects.first() user = User.objects.first()
assert user.username == 'test' assert user.username == 'test'
assert user.is_active is True assert user.is_active is True
assert user.is_staff is True # Set by: django_yunohost_integration assert user.is_staff is True # Set by: conf.setup_user.setup_project_user
assert user.is_superuser is False assert user.is_superuser is False
assert AccessLog.objects.count() == 1
assert response.status_code == 403 # Forbidden assert response.status_code == 403 # Forbidden
@override_settings(SECURE_SSL_REDIRECT=False)
def test_wrong_cookie(self): def test_wrong_cookie(self):
assert User.objects.count() == 0 assert User.objects.count() == 0
assert AccessLog.objects.count() == 0
self.client.cookies['SSOwAuthUser'] = 'foobar' # <<< wrong user name self.client.cookies['SSOwAuthUser'] = 'foobar' # <<< wrong user name
@ -172,18 +164,20 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
HTTP_REMOTE_USER='test', HTTP_REMOTE_USER='test',
HTTP_AUTH_USER='test', HTTP_AUTH_USER='test',
HTTP_AUTHORIZATION='basic dGVzdDp0ZXN0MTIz', HTTP_AUTHORIZATION='basic dGVzdDp0ZXN0MTIz',
secure=True,
) )
assert User.objects.count() == 1 assert User.objects.count() == 1
user = User.objects.first() user = User.objects.first()
assert user.username == 'test' assert user.username == 'test'
assert user.is_active is True assert user.is_active is True
assert user.is_staff is True # Set by: django_yunohost_integration assert user.is_staff is True # Set by: conf.setup_user.setup_project_user
assert user.is_superuser is False assert user.is_superuser is False
assert AccessLog.objects.count() == 1
assert response.status_code == 403 # Forbidden assert response.status_code == 403 # Forbidden
@override_settings(SECURE_SSL_REDIRECT=False)
def test_wrong_authorization_user(self): def test_wrong_authorization_user(self):
assert User.objects.count() == 0 assert User.objects.count() == 0
@ -194,15 +188,19 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
HTTP_REMOTE_USER='test', HTTP_REMOTE_USER='test',
HTTP_AUTH_USER='test', HTTP_AUTH_USER='test',
HTTP_AUTHORIZATION=generate_basic_auth( HTTP_AUTHORIZATION=generate_basic_auth(
username='foobar', password='test123' username='foobar', # <<< wrong user name
), # <<< wrong user name password='test123',
),
secure=True,
) )
assert User.objects.count() == 1 assert User.objects.count() == 1
user = User.objects.first() user = User.objects.first()
assert user.username == 'test' assert user.username == 'test'
assert user.is_active is True assert user.is_active is True
assert user.is_staff is True # Set by: django_yunohost_integration assert user.is_staff is True # Set by: conf.setup_user.setup_project_user
assert user.is_superuser is False assert user.is_superuser is False
assert AccessLog.objects.count() == 1
assert response.status_code == 403 # Forbidden assert response.status_code == 403 # Forbidden

View file

@ -3,9 +3,14 @@ import os
import shutil import shutil
import subprocess import subprocess
from pathlib import Path from pathlib import Path
from typing import Optional
from urllib.parse import ParseResult, urlparse
import requests
import tomli
from bx_django_utils.filename import clean_filename from bx_django_utils.filename import clean_filename
from bx_py_utils.path import assert_is_dir, assert_is_file from bx_py_utils.path import assert_is_dir, assert_is_file
from packaging.version import Version
import findmydevice import findmydevice
@ -21,24 +26,73 @@ def assert_file_contains_string(file_path, string):
raise AssertionError(f'File {file_path} does not contain {string!r} !') raise AssertionError(f'File {file_path} does not contain {string!r} !')
def get_gitlab_version_tag(gitlab_project_url: str) -> Optional[Version]:
"""
Returns the last non-prerelease Version objects from gitlab tags.
"""
assert gitlab_project_url.startswith(
'https://gitlab.com/'
), f'No gitlab Project url: {gitlab_project_url!r}'
result: ParseResult = urlparse(gitlab_project_url)
path = result.path # e.g.: '/jedie/django-find-my-device/'
path = path.strip('/') # 'jedie/django-find-my-device'
assert path.count('/') == 1, f'Wrong path {path!r} from: {gitlab_project_url!r}'
path_escaped = path.replace('/', '%2F')
tag_url = f'https://gitlab.com/api/v4/projects/{path_escaped}/repository/tags'
tags = requests.get(tag_url).json()
for tag in tags:
version_str = tag['name']
ver_obj = Version(version_str)
if ver_obj.base_version and not ver_obj.is_prerelease:
return ver_obj
raise AssertionError(
f'No version found from gitlab tags: {tag_url} (check: {gitlab_project_url})'
)
def assert_gitlab_project_version(current_version: str, gitlab_project_url: str) -> None:
"""
Check that current version is the last version from gitlab tags.
"""
current_ver_obj = Version(current_version)
gitlab_ver = get_gitlab_version_tag(gitlab_project_url=gitlab_project_url)
assert gitlab_ver <= current_ver_obj, (
f'Current version from {gitlab_project_url} is: {gitlab_ver}'
f' but current package version is: {current_ver_obj}'
)
def test_version(): def test_version():
version = findmydevice.__version__ upstream_version = findmydevice.__version__
assert_gitlab_project_version(
current_version=upstream_version,
gitlab_project_url='https://gitlab.com/jedie/django-find-my-device/',
)
pyproject_toml_path = Path(PACKAGE_ROOT, 'pyproject.toml')
pyproject_toml = tomli.loads(pyproject_toml_path.read_text(encoding='UTF-8'))
pyproject_version = pyproject_toml['tool']['poetry']['version']
assert pyproject_version.startswith(f'{upstream_version}+ynh')
# pyproject.toml needs a PEP 440 conform version and used "+ynh"
# the YunoHost syntax is: "~ynh", just "convert this:
manifest_version = pyproject_version.replace('+', '~')
assert_file_contains_string( assert_file_contains_string(
file_path=Path(PACKAGE_ROOT, 'pyproject.toml'), string=f'version = "{version}~ynh' file_path=Path(PACKAGE_ROOT, 'manifest.json'),
) string=f'"version": "{manifest_version}"',
assert_file_contains_string(
file_path=Path(PACKAGE_ROOT, 'manifest.json'), string=f'"version": "{version}~ynh'
) )
def poetry_check_output(*args): def poetry_check_output(*args):
poerty_bin = shutil.which('poetry') poerty_bin = shutil.which('poetry')
assert poerty_bin, 'Executable "poetry" not found!'
output = subprocess.check_output( output = subprocess.check_output(
(poerty_bin,) + args, (poerty_bin,) + args,
universal_newlines=True, text=True,
env=os.environ, env=os.environ,
stderr=subprocess.STDOUT, stderr=subprocess.STDOUT,
cwd=str(PACKAGE_ROOT), cwd=str(PACKAGE_ROOT),
@ -82,7 +136,7 @@ def test_screenshot_filenames():
renamed = [] renamed = []
for file_path in screenshot_path.iterdir(): for file_path in screenshot_path.iterdir():
file_name = file_path.name file_name = file_path.name
if file_name == '.gitkeep': if file_name.startswith('.'):
continue continue
cleaned_name = clean_filename(file_name) cleaned_name = clean_filename(file_name)
if cleaned_name != file_name: if cleaned_name != file_name: