diff --git a/main.py b/main.py index 6130758..729793b 100644 --- a/main.py +++ b/main.py @@ -14,7 +14,7 @@ app.include_router(router=protected_user_action_routes) @app.get("") -def root()->dict: +async def root()->dict: return {"root":"hello, this is root"} @@ -33,4 +33,4 @@ def main(): uvicorn.run("main:app", reload=True) if __name__=="__main__": - main() \ No newline at end of file + main() \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index 93a08b0..e3db45f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,5 +1,21 @@ # This file is automatically @generated by Poetry 2.4.1 and should not be changed by hand. +[[package]] +name = "aiosqlite" +version = "0.22.1" +description = "asyncio bridge to the standard sqlite3 module" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "aiosqlite-0.22.1-py3-none-any.whl", hash = "sha256:21c002eb13823fad740196c5a2e9d8e62f6243bd9e7e4a1f87fb5e44ecb4fceb"}, + {file = "aiosqlite-0.22.1.tar.gz", hash = "sha256:043e0bd78d32888c0a9ca90fc788b38796843360c855a7262a532813133a0650"}, +] + +[package.extras] +dev = ["attribution (==1.8.0)", "black (==25.11.0)", "build (>=1.2)", "coverage[toml] (==7.10.7)", "flake8 (==7.3.0)", "flake8-bugbear (==24.12.12)", "flit (==3.12.0)", "mypy (==1.19.0)", "ufmt (==2.8.0)", "usort (==1.0.8.post1)"] +docs = ["sphinx (==8.1.3)", "sphinx-mdinclude (==0.6.2)"] + [[package]] name = "alembic" version = "1.18.5" @@ -567,92 +583,91 @@ standard-no-fastapi-cloud-cli = ["email-validator (>=2.0.0)", "fastapi-cli[stand [[package]] name = "greenlet" -version = "3.5.3" +version = "3.5.4" description = "Lightweight in-process concurrent programming" optional = false python-versions = ">=3.10" groups = ["main"] -markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\"" files = [ - {file = "greenlet-3.5.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:c180d22d325fb613956b443c3c6f4406eb70e6defc70d3974da2a7b59e06f48c"}, - {file = "greenlet-3.5.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:483d08c11181c83a6ce1a7a61df0f624a208ec40817a3bb2302714592eee4f04"}, - {file = "greenlet-3.5.3-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1dae6e0091eae084317e411f047f0b7cb241c6db570f7c45fd6b900a274914ce"}, - {file = "greenlet-3.5.3-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0f6ff50ff8dbd51fae9b37f4101648b04ea0df19b3f50ab2beb5061e7716a5c8"}, - {file = "greenlet-3.5.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9bcd2d72ccd70a1ec68ba6ef93e7fbb4420ef9997dabc7010d893bd4015e0bec"}, - {file = "greenlet-3.5.3-cp310-cp310-manylinux_2_39_riscv64.whl", hash = "sha256:37bf9c538f5ae6e63d643f88dec37c0c83bdf0e2ebc62961dedcf458822f7b71"}, - {file = "greenlet-3.5.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:73f152c895e09907e0dbe24f6c2db37beb085cd63db91c3825a0fcd0064124a8"}, - {file = "greenlet-3.5.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8bdb43e1a1d1873721acab2be99c5befd4d2044ddfd52e4d610801019880a702"}, - {file = "greenlet-3.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:0909f9355a9f24845d3299f3112e266a06afb68302041989fd26bd68894933db"}, - {file = "greenlet-3.5.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:aca9b4ce85b152b5524ef7d88170efdff80dc0032aa8b75f9aaf7f3479ea95b4"}, - {file = "greenlet-3.5.3-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f71be4920368fe1fabeeaa53d1e3548337e2b223d9565f8ad5e392a75ba23fc"}, - {file = "greenlet-3.5.3-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d77e67f65f98449e3fb83f795b5d0a8437aead2f874ca89c96576caf4be3af6"}, - {file = "greenlet-3.5.3-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e18619ba655ac05d78d80fc83cac4ba892bd6927b99e3b8237aee861aaacc8bb"}, - {file = "greenlet-3.5.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8540f1e6205bd13ca0ce685581037219ca54a1b41a0a15d228c6c9b8ad5903d7"}, - {file = "greenlet-3.5.3-cp311-cp311-manylinux_2_39_riscv64.whl", hash = "sha256:d27c0c653a60d9535f690226474a5cc1036a8b0d7b57504d1c4f89c44a07a80c"}, - {file = "greenlet-3.5.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7ef56fe650f50575bf843acde967b9c567687f3c22340941a899b7bc56e956a8"}, - {file = "greenlet-3.5.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5121af01cf911e70056c00d4b46d5e9b5d1415550038573d744138bacb59e6b8"}, - {file = "greenlet-3.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:0f41e4a05a3c0cb31b17023eff28dd111e1d16bf7d7d00406cd7df23f31398a7"}, - {file = "greenlet-3.5.3-cp311-cp311-win_arm64.whl", hash = "sha256:ec6f1af59f6b5f3fc9678e2ea062d8377d22ac644f7844cb7a292910cf12ff44"}, - {file = "greenlet-3.5.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:719757059f5a53fd0dde23f78cffeafcdd97b21c850ddb7ca684a3c1a1f122e2"}, - {file = "greenlet-3.5.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:efa9f765dd09f9d0cdac651ffdf631ee59ec5dc6ee7a73e0c012ba9c52fbdf5b"}, - {file = "greenlet-3.5.3-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7faba15ac005376e02a0384504e0243be3370ce010296a44a820feb342b505ab"}, - {file = "greenlet-3.5.3-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5795cd1101371140551c645f2d408b8d3c01a5a29cf8a9bce6e759c983682d23"}, - {file = "greenlet-3.5.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:87142215824be6ac05e2e8e2786eec307ccbc27c36723c3881959df654af6861"}, - {file = "greenlet-3.5.3-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:af4923b3096e26a36d7e9cf24ab88083a20f97d191e3b97f253731ce9b41b28c"}, - {file = "greenlet-3.5.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:215275b1b49320987352e6c1b054acca0064f965a2c66992bed9a6f7d913f149"}, - {file = "greenlet-3.5.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6b1b0eed82364b0e32c4ea0f221452d33e6bb17ae094d9f72aed9851812747ea"}, - {file = "greenlet-3.5.3-cp312-cp312-win_amd64.whl", hash = "sha256:cde8adafa2365676f74a979744629589999093bc86e2484214f58e61df08902c"}, - {file = "greenlet-3.5.3-cp312-cp312-win_arm64.whl", hash = "sha256:c4e7b79d83805475f0102008843f6eb45fd3bb0b2e88c774adab5fbaab27117d"}, - {file = "greenlet-3.5.3-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:c8d87c2134d871df96ecdea9cec7cbaab286dadab0f56476e57aaf9e8ac11550"}, - {file = "greenlet-3.5.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2d185dd1621757e70c3861cceffd5317ab4e7ed7eb09c82994828468527ade5"}, - {file = "greenlet-3.5.3-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1c514a468149bf8fbbab874188a3535cd8a48a3e353eb53a3d424296f8dbacd3"}, - {file = "greenlet-3.5.3-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9ad04dd75458c6300b047c61b8639092433d205a25a14e310d6582a480efcca1"}, - {file = "greenlet-3.5.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:915f887cf2682b66419b879423a2e072634aa7b7dce6f3ada4957cfced3f1e9a"}, - {file = "greenlet-3.5.3-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:afaabdd554cd7ae9bbb3ca070b0d7fdfd207dbf1d16865f7233837709d354bda"}, - {file = "greenlet-3.5.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:766cfd421c13e450feb340cd472a3ed9957d438727b7b4593ad7c76c5d2b0deb"}, - {file = "greenlet-3.5.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2ecda9ec22edf38fa389369eaed8c3d37c05f3c54e69f69438dbb2cc1de1458b"}, - {file = "greenlet-3.5.3-cp313-cp313-win_amd64.whl", hash = "sha256:c82304750f057167ff60d188df1d0cc1764ce9567eadf03e6a7443bcedd0b30b"}, - {file = "greenlet-3.5.3-cp313-cp313-win_arm64.whl", hash = "sha256:dc133a1569ee667b2a6ef56ce551084aeefd87a5acbc4736d336d1e2edc6cfc4"}, - {file = "greenlet-3.5.3-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:fd2e02fa07485778536a036222d616ab957b1d533f36b3ed98ce725d9c9d3117"}, - {file = "greenlet-3.5.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df0a0628d1597eb0897b62f55d1343f772405fd25f3b2a796c76874b0c2e22e8"}, - {file = "greenlet-3.5.3-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ebd933a6adabc298bab47731a130fe6bfb888bd934eee37810f151159544540d"}, - {file = "greenlet-3.5.3-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8d19fe6c39ebff9259f07bcc685d3290f8fa4ea2278e51dd0008e4d6b0f2d814"}, - {file = "greenlet-3.5.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4b9d501b40e80b70e32323c799dd9b420a5577a9601469d362ae1ffb690f3a7c"}, - {file = "greenlet-3.5.3-cp314-cp314-manylinux_2_39_riscv64.whl", hash = "sha256:962c5df2db8cb446da51edf1ca5296c389d93b99c9d8aa2ee4c7d0d8f1218260"}, - {file = "greenlet-3.5.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a1fad1d11e7d6aab184107baa8e4ece11ccba3ec9599cd7efa5ff4d70d43256a"}, - {file = "greenlet-3.5.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:fad5aec764399f1b5cc347ad250a59660f20c8f8888ea6bae1f93b769cce1154"}, - {file = "greenlet-3.5.3-cp314-cp314-win_amd64.whl", hash = "sha256:7669aa24cf2a1041d6f7899575b494a3ab4cf68bfcc8609b1dc0be7272db835e"}, - {file = "greenlet-3.5.3-cp314-cp314-win_arm64.whl", hash = "sha256:5b4807c4082c9d1b6d9eed56fcd041863e37f2228106eef24c30ca096e238605"}, - {file = "greenlet-3.5.3-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:271a8ea7c1024e8a0d7dd2be66dd66dda8a07193f41a17b9e924f7600f5b62be"}, - {file = "greenlet-3.5.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:19131729ae0ddc3c2e1ef85e650169b5e37ee32e400f215f78b94d7b0d567310"}, - {file = "greenlet-3.5.3-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1540dd8e5fc2a5aec40fbb98ef8e149fa47c89a4b4a1cf2575a14d3d1869d7a8"}, - {file = "greenlet-3.5.3-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b897d97759425953f69a9c0fac67f8fe333ec0ce7377ef186fb2b0c3ad5e354d"}, - {file = "greenlet-3.5.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e81fa194a1d20967877bdf9c7794db2bc99063e5be36aee710c08f04c5bb087f"}, - {file = "greenlet-3.5.3-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:3236754d423955ea08e9bb5f6c04a7895f9e22c290b66aa7653fcb922d839eb0"}, - {file = "greenlet-3.5.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:55cf4d777485d43110e47133cbba6d74a8885a87ec1227ef0267f9ee80c5aa21"}, - {file = "greenlet-3.5.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:12a248ba75f6a9a236375f52296c498c89ff1d8badf32deb9eca7abd5853f7da"}, - {file = "greenlet-3.5.3-cp314-cp314t-win_amd64.whl", hash = "sha256:efc6bd60ea02e085862c74a3ef64b147ffc6f1a5ea7d9f26e7a939943f68c1e3"}, - {file = "greenlet-3.5.3-cp315-cp315-macosx_11_0_universal2.whl", hash = "sha256:ea03f2f04367845d6b58eeed276e1e56e51f0b97d8ad5a88a7d20a91dc9056cc"}, - {file = "greenlet-3.5.3-cp315-cp315-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78dbef602fda6d97d957eb7937f70c9ce9e9527330347f8f6b6f9e554a9e7a47"}, - {file = "greenlet-3.5.3-cp315-cp315-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f73857adb8fee13fa56c172bd11262f888c0c648f9fea113e777bb2c7904a81"}, - {file = "greenlet-3.5.3-cp315-cp315-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:cefa9cef4b371f9844c6053db71f1138bc6807bab1578b0dae5149c1f1141357"}, - {file = "greenlet-3.5.3-cp315-cp315-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:232fec92e823addaf02d9472cf7381e24a1d046a6ced1103c5caa4c21b9dfc1d"}, - {file = "greenlet-3.5.3-cp315-cp315-manylinux_2_39_riscv64.whl", hash = "sha256:6219b6d04dbf6ba6084d77dc609e8473060dc55f759cbf626d512122781fa128"}, - {file = "greenlet-3.5.3-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:2421c3564da9429d5586d46ca31ebb26516b5498a802cf65c041a8e8a8980d34"}, - {file = "greenlet-3.5.3-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:e0f0d160f0b2e558e6c75f7930967183255dc9735e5f5b8cae58ee09c9576d8b"}, - {file = "greenlet-3.5.3-cp315-cp315-win_amd64.whl", hash = "sha256:dd99329bbc15ca78dcc583dba05d0b1b0bae01ab6c2174989f5aaee3e41ac930"}, - {file = "greenlet-3.5.3-cp315-cp315-win_arm64.whl", hash = "sha256:499fef2acede88c1864a57bb586b4bf533c81e1b82df7ab93451cdb47dfec227"}, - {file = "greenlet-3.5.3-cp315-cp315t-macosx_11_0_universal2.whl", hash = "sha256:176bc16a721fa5fc294d70b87b4dfa5fbdd251b3da5d5372735ecef9bd7d6d0c"}, - {file = "greenlet-3.5.3-cp315-cp315t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:629b614d2b786e89c50440e246f33eea78f58a962d0bdbbcc809e6d13605903f"}, - {file = "greenlet-3.5.3-cp315-cp315t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2b2e857ae16f5f72142edf75f9f176fe7526ba19a2841df1420516f83831c9f2"}, - {file = "greenlet-3.5.3-cp315-cp315t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:16d192579ed281051396dddd7f7754dac6259e6b1fb26378c87b66622f8e3f91"}, - {file = "greenlet-3.5.3-cp315-cp315t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e515757e2e36bcbf1fad09a46e1557e8b1ae1797d4b44d09da7deed88ad28608"}, - {file = "greenlet-3.5.3-cp315-cp315t-manylinux_2_39_riscv64.whl", hash = "sha256:4399eb8d041f20b68d943918bc55502a93d6fdc0a37c14da7881c04139acee9d"}, - {file = "greenlet-3.5.3-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:b363d46ed1ea431825fdb01471bb024fc08399bad1572a616e853c7684415adb"}, - {file = "greenlet-3.5.3-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:e44da2f5bbdaabaf7d80b73dbb430c7035771e9f244e3c8b769715c9d8fa0a16"}, - {file = "greenlet-3.5.3-cp315-cp315t-win_amd64.whl", hash = "sha256:8ff8bed3e3baa20a3ea261ce00526f1898ad4801d4886fd2220580ee0ad8fadf"}, - {file = "greenlet-3.5.3-cp315-cp315t-win_arm64.whl", hash = "sha256:b7068bd09f761f3f5b4d214c2bed063186b2a86148c740b3873e3f56d79bac31"}, - {file = "greenlet-3.5.3.tar.gz", hash = "sha256:a61efc018fd3eb317eeca31aba90ee9e7f26f22884a79b6c6ec715bf71bb62f1"}, + {file = "greenlet-3.5.4-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:ac5bf81d79d2c8eeb2ef6359b2e1687a1e9ebf46c2b1f970da9a9255df51d190"}, + {file = "greenlet-3.5.4-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:89f3738167bab8c1084b94e23023d41d247117ac149fa0fbcb5bd4cf6262b353"}, + {file = "greenlet-3.5.4-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e9a5e3406e3ed8125ae1a3b37c12f3434e2b1f0fa053197c5557895b4fb09606"}, + {file = "greenlet-3.5.4-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a2d614cb2372c7101a12ea8b96dd56f81c986d247c5a73db67063f3ed1ca4a52"}, + {file = "greenlet-3.5.4-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4ab9f0704bccf6d3b38e0d2130b7b33271cff11453690da074fa280c3aa8e8e7"}, + {file = "greenlet-3.5.4-cp310-cp310-manylinux_2_39_riscv64.whl", hash = "sha256:188e4d142f243051d92a1f5c244a741da02dddc070a0620c842804d7b56d008c"}, + {file = "greenlet-3.5.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2cdaadc3d31445a8f782bde3cd37e49a2c2a9c6da6daf76a3e34c683b271a3c7"}, + {file = "greenlet-3.5.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:70bdfacdc183dac838b2a0aaff2dd6134a457c52fe68a9c6bbab435483d2b9df"}, + {file = "greenlet-3.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:69173331fbc5d64bfac0065d7e22c39cfcd089e9b18d125bdcd5079363b09616"}, + {file = "greenlet-3.5.4-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e883de250e299654b1f1680f72a1a9f9ba62c9bd1bce84099c90657349a8dfbb"}, + {file = "greenlet-3.5.4-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:32802705c2c1ff25e8237b3bdacf2594fa02be80af8a66703eb7853ea7e68686"}, + {file = "greenlet-3.5.4-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:57aa201b351f7c7c75627c60d29e4d5b97a07d37efeb62b903466fca42c097d7"}, + {file = "greenlet-3.5.4-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9667862a2e38ad379f11b845daeda22c8989186def44f06962c9c4c05e556da7"}, + {file = "greenlet-3.5.4-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c3fe76c2cac86b4f7a1e92865ac0a54384deb05c92986287c1a7110d9bd53071"}, + {file = "greenlet-3.5.4-cp311-cp311-manylinux_2_39_riscv64.whl", hash = "sha256:ae53534b5dec0f4c2ec26f898f538dc8ea1ca3ef2927d597a9439e40a09da937"}, + {file = "greenlet-3.5.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1e1a4a684b16c45ba324e60b32a4386a87722bcb815d2a149d2182f9b401ca72"}, + {file = "greenlet-3.5.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e849e6e139b9671adeac505f72fc05f4af7fd1921faef40295e214fc3b361b59"}, + {file = "greenlet-3.5.4-cp311-cp311-win_amd64.whl", hash = "sha256:dc418cf4c873357964d6624445ed09472e50def990c65dd4e76fc3ba8cd9cef6"}, + {file = "greenlet-3.5.4-cp311-cp311-win_arm64.whl", hash = "sha256:c38c902a0986eba1f6e7ba1ab39ad5195926abde90f3fe080e08212db62176da"}, + {file = "greenlet-3.5.4-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3d66250e8b09f182ede05490998c818b5961f7a3640332d44c4927caec7bbfe4"}, + {file = "greenlet-3.5.4-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c90e930c9c192e5b3ee9fb8bcd920ea3926155e2e3ded39fc697323addecee17"}, + {file = "greenlet-3.5.4-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:791fdfeeb9c6e0c7b10fa151bf110d2a6974866f13dcb5b1c7efae698245893a"}, + {file = "greenlet-3.5.4-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b7c895310363f310361e0fe2072af85269d2a2a285cd04c0c59e79a5e3670dcf"}, + {file = "greenlet-3.5.4-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f88193799d43dbf8c8a806d6405c9c52fe2af40bf75072a606357b33cc336c7f"}, + {file = "greenlet-3.5.4-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:13b980043cb1b3134e81ea469da1250ddcc6bfe6d245bbaa59168d9cdc8f228f"}, + {file = "greenlet-3.5.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b7a5f095767c4493afcd06067f2bb3b8716e3f3f9e92b99c88e7e99f885b3d4d"}, + {file = "greenlet-3.5.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:42afdc1ab5f66da8c586c32af9224a74a706b4f0ea0dc3a4188a0860a09c65c9"}, + {file = "greenlet-3.5.4-cp312-cp312-win_amd64.whl", hash = "sha256:60149df8f462d1b230038e6590c23c3b4768bb5d6c022b3b6e82532b34b0b8a3"}, + {file = "greenlet-3.5.4-cp312-cp312-win_arm64.whl", hash = "sha256:77d6ce04fed0d9aeed42e0f37923cc43eba9b027bdd9c34546bb4ccd143d0fe0"}, + {file = "greenlet-3.5.4-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:24e61b88cb7e1b1d794b32a10cc346ac779681d6d74ff137a3e0a444d2bf1f02"}, + {file = "greenlet-3.5.4-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:870d730fec833f5a06906a32596cc099b9161594642a92a520b7a88911c95356"}, + {file = "greenlet-3.5.4-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ec5ff0d1878df6af3bf9b638a5a92a7d5693291de77c91bff10fa48519c604ef"}, + {file = "greenlet-3.5.4-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:07bd44616608d873d06735b63ef1a88191d6ca57c8d291d6559c71bc14c0893c"}, + {file = "greenlet-3.5.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d84d993f6e575c950d91a23c1345d18fe1a4310d447bf630849d7809196b52f0"}, + {file = "greenlet-3.5.4-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:3529a8a933582ad19e224792cac7372489526576b75b4c124e8e4f29948f4861"}, + {file = "greenlet-3.5.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:58023945f421093de5e6fa108c0985a8659d43f49e0216da25099369a121bcbd"}, + {file = "greenlet-3.5.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bae2728e1897aa8df8cb1af38cd48b3a743aefe29372de7b8b7a9f532501e69f"}, + {file = "greenlet-3.5.4-cp313-cp313-win_amd64.whl", hash = "sha256:ca5726c0b08ca35ae873557266a78b2c3f3b2b7d7401aa5ff886c2045dd0111c"}, + {file = "greenlet-3.5.4-cp313-cp313-win_arm64.whl", hash = "sha256:7c1303791d603080cac6fc3b34df51c3b75b723739c282c8029e48a0d241672f"}, + {file = "greenlet-3.5.4-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:7e8afa5eac028f8140ceafe5ceec66e6aa127ddcb21452d2a564dcd2900b5f22"}, + {file = "greenlet-3.5.4-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:73b37afe369021423ea53dd3123e04bffa7e93ac64429b9f50835b2e4fcae7cf"}, + {file = "greenlet-3.5.4-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3ef964f56dfcb6f9bbef2a190d9126795eac408716aeae47b5e7c73c32aafca9"}, + {file = "greenlet-3.5.4-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:cef589bc65fae02d10bca2ac341191c5b33acc2967892ebf4fcbd10eabb7a74c"}, + {file = "greenlet-3.5.4-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c53ff01a5c53a40f2c16820ebc56d7c61a77f5fbe009dadd96292d5682f80f8"}, + {file = "greenlet-3.5.4-cp314-cp314-manylinux_2_39_riscv64.whl", hash = "sha256:dfc41ae893d9ceaf22c824f2153a88b30651b20e8758c2cd9ac143f23640563c"}, + {file = "greenlet-3.5.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ecca4d80d55a01ad6b23b33262662956149fbb7b2c6be2910f1705921958cbf3"}, + {file = "greenlet-3.5.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2ffbc533e0eaf8e80d8471411646ab88fe58f641d508c0b02b24494479f4d9ec"}, + {file = "greenlet-3.5.4-cp314-cp314-win_amd64.whl", hash = "sha256:305f69e6c4523d7f6979ed001cff4e5853c063e5da04880296603aa0227e544c"}, + {file = "greenlet-3.5.4-cp314-cp314-win_arm64.whl", hash = "sha256:f260930bbbbcf9caee661211235a5111c86dfe5832fdf6ae4570da1e0995320f"}, + {file = "greenlet-3.5.4-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:41ddab54e4b238f4a6c323f39b4e59e176affd5a94d461a9fb7583dac74240a3"}, + {file = "greenlet-3.5.4-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b3dabe3e2809013052c68bdf0b7fa5f5f2859c43a80803131ad61af9cabd7867"}, + {file = "greenlet-3.5.4-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:27d3f00718634d4520a3a150154ac5da36f257869d41321953375b90bfbbc72c"}, + {file = "greenlet-3.5.4-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:39169a11d87a6a263afda3e9a27d1df16d0f919d40a4837cc73986c9884c0dd8"}, + {file = "greenlet-3.5.4-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cbd60b5763c6543c1827e48faaf14ea9bfbad245f52b1a4d76a2a2d8884c6c66"}, + {file = "greenlet-3.5.4-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:bd3d1145f603b2db19feb9078c2e6855eb7c67e15580c010ed815cee519b86fd"}, + {file = "greenlet-3.5.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f00f910f0e7b35416c63b23ad78b769aeccfc1775f712b43c4ee525624a2eef7"}, + {file = "greenlet-3.5.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:91c26423753b92caf41ab3f98fd547d7374d4d9fc2d85be041886c1579d9255e"}, + {file = "greenlet-3.5.4-cp314-cp314t-win_amd64.whl", hash = "sha256:ee032b91fd8ec29ec6c4cea2b8c561b178435134bd0752c7334b94e9c736c132"}, + {file = "greenlet-3.5.4-cp315-cp315-macosx_11_0_universal2.whl", hash = "sha256:178111881dd7a6c946471fda85485ec796e1043c2b939f694b096e2ecf986809"}, + {file = "greenlet-3.5.4-cp315-cp315-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d92df08dd65fede97fc37aad36c2e9dcda3b31c467f8e0c2c096456cb818e927"}, + {file = "greenlet-3.5.4-cp315-cp315-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:99e8f8c4ebc4fd80aa26c1280ae9ad43a0976e786349703a181cf0bae60413e5"}, + {file = "greenlet-3.5.4-cp315-cp315-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1f17e362d78e37559e0506c5a7d066bdd45073c36a0127a543e8a0df27242ff3"}, + {file = "greenlet-3.5.4-cp315-cp315-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:394de08dad5ffcb1f50c2159d93e398d9d2da3ed437645eaa54771fa720db9f0"}, + {file = "greenlet-3.5.4-cp315-cp315-manylinux_2_39_riscv64.whl", hash = "sha256:cd320d998cbaa032932830448e39abf3c6a12901295e386e8114db926e10cffb"}, + {file = "greenlet-3.5.4-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:c883d61f2282d72c767a14936641b3efcbde9d82f1080712aaea0b1d3126cb88"}, + {file = "greenlet-3.5.4-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:2a924f15d17957e252a810acefcb5942f5ca712298e8b6fcaed9a307d357522c"}, + {file = "greenlet-3.5.4-cp315-cp315-win_amd64.whl", hash = "sha256:ed17e5f3420360d5b459de8462efb52060399a5326a613d4cde31cef63ef95da"}, + {file = "greenlet-3.5.4-cp315-cp315-win_arm64.whl", hash = "sha256:f908898d6fa484ce4b6f447ce70ea99b52c503fee419e53cf74d60a16bc9e667"}, + {file = "greenlet-3.5.4-cp315-cp315t-macosx_11_0_universal2.whl", hash = "sha256:1833637f17d5e7472548a48575c394fe39f1b1890d676d162d86593610f44d8c"}, + {file = "greenlet-3.5.4-cp315-cp315t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:12cda9122e03341f1cb6b8207a19d7a9d375e52f1b4e9243918375f40fd7b4b9"}, + {file = "greenlet-3.5.4-cp315-cp315t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d83ae0e32d14957ab7170785a20f582635c8474deab1bfbb552b17e769a6ce25"}, + {file = "greenlet-3.5.4-cp315-cp315t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:123aa379c962ed5fe90a880327e0c3066124ac64ec99e12a238be9fd8eb3db3d"}, + {file = "greenlet-3.5.4-cp315-cp315t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9f1467de1bb767f75db0aa34c195e3a496d8d1278c796e70c24ce205d3e99cde"}, + {file = "greenlet-3.5.4-cp315-cp315t-manylinux_2_39_riscv64.whl", hash = "sha256:adf2244d7f69409925a8f22ed22cc5f93cdfe5c9dc87ff3476be2c2aaae61a05"}, + {file = "greenlet-3.5.4-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:0fa53040b78b578120eecdc0265e3f1051487cc425d11a2b7c761daadf4feaa8"}, + {file = "greenlet-3.5.4-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:60e0bc961d367df506660e9ac0177a76bc6d81305300704b0977d1634f76efe2"}, + {file = "greenlet-3.5.4-cp315-cp315t-win_amd64.whl", hash = "sha256:f680e549edb3eaf21eea4e7fe101e15ec180c74b7879ab46adc080f22d4015d2"}, + {file = "greenlet-3.5.4-cp315-cp315t-win_arm64.whl", hash = "sha256:08fc36de8442d5c3e95b044550dbea9bf144d31ec0cc58e36fb241cb6ef6a994"}, + {file = "greenlet-3.5.4.tar.gz", hash = "sha256:0232ae1de90a8e07867bb127d7a6ba2301e859145489f25cda8a6096dabe1d20"}, ] [package.extras] @@ -1684,6 +1699,25 @@ pygments = ">=2.7.2" [package.extras] dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] +[[package]] +name = "pytest-asyncio" +version = "1.4.0" +description = "Pytest support for asyncio" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "pytest_asyncio-1.4.0-py3-none-any.whl", hash = "sha256:933ca923a23075a87fb7070c0ec272a6848489824d887c85c812670932835aa1"}, + {file = "pytest_asyncio-1.4.0.tar.gz", hash = "sha256:c6c0d2259945122819f171a32ecea2c349ead889ee28176caaf492143424be42"}, +] + +[package.dependencies] +pytest = ">=8.4,<10" + +[package.extras] +docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1)", "sphinx-tabs (>=3.5)"] +testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] + [[package]] name = "pytest-cov" version = "7.1.0" @@ -2151,4 +2185,4 @@ files = [ [metadata] lock-version = "2.1" python-versions = ">=3.13" -content-hash = "ebbba0a60f3f121f79117d05b5a6dbd8914ca1d971776808c7d1cfd146b562bc" +content-hash = "9f5afa235b9e6861253603be40e4b5c3ae8d59b6d8bff7669d4e7670183ff336" diff --git a/pyproject.toml b/pyproject.toml index eab38de..08181ad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,10 @@ dependencies = [ "httpie (>=3.2.4,<4.0.0)", "pytest-cov (>=7.1.0,<8.0.0)", "allure-pytest (>=2.16.0,<3.0.0)", - "pytest-mock (>=3.15.1,<4.0.0)" + "pytest-mock (>=3.15.1,<4.0.0)", + "aiosqlite (>=0.22.1,<0.23.0)", + "greenlet (>=3.5.4,<4.0.0)", + "pytest-asyncio (>=1.4.0,<2.0.0)" ] diff --git a/pytest.ini b/pytest.ini index 24d2291..d943f13 100644 --- a/pytest.ini +++ b/pytest.ini @@ -10,3 +10,5 @@ markers= integra: integrations test e2e: e2e tests smoke: smoke tests + +asyncio_mode = auto diff --git a/src/database/auth/refresh_tokens.py b/src/database/auth/refresh_tokens.py index 95adfe8..51e3e36 100644 --- a/src/database/auth/refresh_tokens.py +++ b/src/database/auth/refresh_tokens.py @@ -2,6 +2,7 @@ from uuid import UUID from sqlalchemy import and_, not_, select, update +from sqlalchemy.ext.asyncio import async_sessionmaker from sqlalchemy.orm import sessionmaker from src.models.database_models.model import RefreshTokens, engine @@ -10,32 +11,32 @@ from src.models.pydantic_models.model import RefreshTokensOut class JwtCrudActions: def __init__(self) -> None: - self.Session=sessionmaker(bind=engine) + self.Session=async_sessionmaker(bind=engine) - def get_token_by_user_id(self, user_id:UUID)->RefreshTokensOut|None: - with self.Session() as session, session.begin(): + async def get_token_by_user_id(self, user_id:UUID)->RefreshTokensOut|None: + async with self.Session() as session, session.begin(): query=select(RefreshTokens).where(and_(RefreshTokens.user_id==user_id, not_(RefreshTokens.is_revoked))) - response=session.scalars(query).first() + response= (await session.scalars(query)).first() if response is None: return None return RefreshTokensOut.model_validate(response) - def get_token_by_id(self, token_id:UUID)->RefreshTokensOut|None: - with self.Session() as session, session.begin(): + async def get_token_by_id(self, token_id:UUID)->RefreshTokensOut|None: + async with self.Session() as session, session.begin(): query=select(RefreshTokens).where(RefreshTokens.id==token_id) - response=session.scalars(query).one_or_none() + response= (await session.scalars(query)).one_or_none() if response is None: return None return RefreshTokensOut.model_validate(response) - def create_token(self, data:dict)->None: - with self.Session() as session, session.begin(): + async def create_token(self, data:dict)->None: + async with self.Session() as session, session.begin(): new_token=RefreshTokens(**data) session.add(new_token) - def create_and_update_token(self, data: dict, old_jti: UUID, new_jti: UUID) -> bool: - with self.Session() as session, session.begin(): + async def create_and_update_token(self, data: dict, old_jti: UUID, new_jti: UUID) -> bool: + async with self.Session() as session, session.begin(): new_token = RefreshTokens(**data) query = ( @@ -44,7 +45,7 @@ class JwtCrudActions: .values(is_revoked=True, replaced_by=new_jti) .returning(RefreshTokens.id) ) - updated_id = session.execute(query).scalar_one_or_none() + updated_id = (await session.execute(query)).scalar_one_or_none() if updated_id is None: return False @@ -53,15 +54,15 @@ class JwtCrudActions: return True - def revoke_all(self, user_id:UUID)->bool: - with self.Session() as session, session.begin(): - session.execute(update(RefreshTokens).where(RefreshTokens.user_id==user_id).values(is_revoked=True)) #bulk update + async def revoke_all(self, user_id:UUID)->bool: + async with self.Session() as session, session.begin(): + await session.execute(update(RefreshTokens).where(RefreshTokens.user_id==user_id).values(is_revoked=True)) #bulk update return True - def logout(self,token_id:UUID)->bool: - with self.Session() as session, session.begin(): + async def logout(self,token_id:UUID)->bool: + async with self.Session() as session, session.begin(): query=select(RefreshTokens).where(RefreshTokens.id == token_id) - response=session.scalars(query).one_or_none() + response= (await session.scalars(query)).one_or_none() if response is None: return False else: diff --git a/src/database/users/crud.py b/src/database/users/crud.py index d23c79d..891af65 100644 --- a/src/database/users/crud.py +++ b/src/database/users/crud.py @@ -1,7 +1,7 @@ from uuid import UUID from sqlalchemy import select -from sqlalchemy.orm import sessionmaker +from sqlalchemy.ext.asyncio import async_sessionmaker from src.models.database_models.model import User, engine from src.models.pydantic_models.model import UserOutDB @@ -10,20 +10,20 @@ from src.models.pydantic_models.model import UserOutDB class UsersCrudActions: def __init__(self) -> None: - self.Session=sessionmaker(bind=engine) + self.Session=async_sessionmaker(bind=engine) - def get_user_by_email(self, email:str)->UserOutDB|None: - with self.Session() as session, session.begin(): + async def get_user_by_email(self, email:str)->UserOutDB|None: + async with self.Session() as session, session.begin(): query=select(User).where(User.email==email) - response=session.scalars(query).one_or_none() + response=(await session.scalars(query)).one_or_none() if response is None: return None return UserOutDB.model_validate(response) - def get_user_by_id(self, id:UUID)->UserOutDB|None: - with self.Session() as session, session.begin(): + async def get_user_by_id(self, id:UUID)->UserOutDB|None: + async with self.Session() as session, session.begin(): query=select(User).where(User.id==id) - response=session.scalars(query).one_or_none() + response=(await session.scalars(query)).one_or_none() if response is None: return None return UserOutDB.model_validate(response) \ No newline at end of file diff --git a/src/models/database_models/model.py b/src/models/database_models/model.py index 9ca2ae0..0bca485 100644 --- a/src/models/database_models/model.py +++ b/src/models/database_models/model.py @@ -10,12 +10,12 @@ from sqlalchemy import ( String, Table, Uuid, - create_engine, func, ) +from sqlalchemy.ext.asyncio import create_async_engine from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship -engine = create_engine("sqlite:///DB/database.db", echo=True) +engine = create_async_engine("sqlite+aiosqlite:///DB/database.db", echo=True) '''remember as a boilerplate, or just cp/pst''' class Model(DeclarativeBase): diff --git a/src/service/auth/auth.py b/src/service/auth/auth.py index f216314..25e4019 100644 --- a/src/service/auth/auth.py +++ b/src/service/auth/auth.py @@ -1,3 +1,4 @@ +import asyncio from datetime import UTC, datetime, timedelta from uuid import UUID @@ -21,14 +22,14 @@ class CurrentUserService: self.jwt_db_actions=JwtCrudActions() self.error=Errors() - def _check(self, form_data_email:str, form_data_password:str,): + async def _check(self, form_data_email:str, form_data_password:str,): '''check user by email''' - user=self.crud_db_actions.get_user_by_email(form_data_email) + user=await self.crud_db_actions.get_user_by_email(form_data_email) if user is None: raise self.error.credentials_error(detail="Wrong credentials") - if not self.hash.verify_password(plain_password=form_data_password, hashed_password=user.hashed_password): + if not await asyncio.to_thread(self.hash.verify_password, plain_password=form_data_password, hashed_password=user.hashed_password): raise self.error.credentials_error(detail="Wrong credentials") if user.status is False: @@ -36,7 +37,7 @@ class CurrentUserService: return user - def _token_record_create(self, jti:UUID,user_id:UUID,token:str, request:Request)->RefreshTokensCreate: + async def _token_record_create(self, jti:UUID,user_id:UUID,token:str, request:Request)->RefreshTokensCreate: return RefreshTokensCreate( id=jti, @@ -48,9 +49,9 @@ class CurrentUserService: ) - def get_current_user(self, token:str)->UserOut: + async def get_current_user(self, token:str)->UserOut: - payload=self.jwt_service.jwt_decode(token) + payload= await self.jwt_service.jwt_decode(token) sub=payload.get("sub") try: @@ -61,7 +62,7 @@ class CurrentUserService: if not (payload.get("token_type")=="access"): raise self.error.credentials_error(detail="Jwt token type is incorrect") - user=self.crud_db_actions.get_user_by_id(sub) + user=await self.crud_db_actions.get_user_by_id(sub) if user is None: raise self.error.not_found_error(detail="User with this email address not found") @@ -72,15 +73,15 @@ class CurrentUserService: - def create_access_token(self, user_id:UUID)->str: + async def create_access_token(self, user_id:UUID)->str: '''create new access token if all the checks are successful''' - return self.jwt_service.create_access_token({"sub":str(user_id)}) + return await self.jwt_service.create_access_token({"sub":str(user_id)}) - def create_refresh_token(self,user_id:UUID, request:Request)->str: + async def create_refresh_token(self,user_id:UUID, request:Request)->str: - token, jti=self.jwt_service.create_refresh_token({"sub":str(user_id)}) + token, jti= await self.jwt_service.create_refresh_token({"sub":str(user_id)}) try: jti=UUID(jti) @@ -88,18 +89,18 @@ class CurrentUserService: raise self.error.credentials_error(detail="Jwt token is incorrect") from e '''create new refresh token if all the checks are successful''' - token_record=self._token_record_create(jti=jti, user_id=user_id, token=token, request=request) + token_record=await self._token_record_create(jti=jti, user_id=user_id, token=token, request=request) - self.jwt_db_actions.create_token(RefreshTokensCreate.model_dump(token_record)) + await self.jwt_db_actions.create_token(RefreshTokensCreate.model_dump(token_record)) return token - def refresh_token(self, refresh_token:str, request:Request)->tuple[str, str]: + async def refresh_token(self, refresh_token:str, request:Request)->tuple[str, str]: '''decode old refresh token''' - old_refresh_token=self.jwt_service.jwt_decode(refresh_token) + old_refresh_token= await self.jwt_service.jwt_decode(refresh_token) sub=old_refresh_token.get("sub") if (old_jti:=old_refresh_token.get("jti")) is None: @@ -118,7 +119,7 @@ class CurrentUserService: raise self.error.credentials_error(detail="Jwt token type is incorrect") - old_record=self.jwt_db_actions.get_token_by_id(old_jti) + old_record=await self.jwt_db_actions.get_token_by_id(old_jti) if old_record is None: raise self.error.not_found_error(detail="Token not found") @@ -131,7 +132,7 @@ class CurrentUserService: raise self.error.credentials_error(detail="Token expired") '''user check''' - user = self.crud_db_actions.get_user_by_id(sub) + user = await self.crud_db_actions.get_user_by_id(sub) if user is None: raise self.error.not_found_error(detail="User not found") if user.status is False: @@ -139,8 +140,8 @@ class CurrentUserService: '''create new refresh token if all the checks are successful''' - new_refresh_token, new_jti=self.jwt_service.create_refresh_token({"sub":str(sub)}) - new_access_token=self.create_access_token(user_id=sub) + new_refresh_token, new_jti= await self.jwt_service.create_refresh_token({"sub":str(sub)}) + new_access_token=await self.create_access_token(user_id=sub) try: new_jti=UUID(new_jti) @@ -149,9 +150,9 @@ class CurrentUserService: '''create database record with the new token''' - new_token_record=self._token_record_create(jti=new_jti, user_id=sub, token=new_refresh_token, request=request) + new_token_record=await self._token_record_create(jti=new_jti, user_id=sub, token=new_refresh_token, request=request) - success = self.jwt_db_actions.create_and_update_token(RefreshTokensCreate.model_dump(new_token_record), old_jti, new_jti) + success = await self.jwt_db_actions.create_and_update_token(RefreshTokensCreate.model_dump(new_token_record), old_jti, new_jti) if not success: raise self.error.not_found_error(detail="Token not found") @@ -160,10 +161,10 @@ class CurrentUserService: - def logout(self, refresh_token:str)->bool: + async def logout(self, refresh_token:str)->bool: '''decode current refresh token''' - payload=self.jwt_service.jwt_decode(refresh_token) + payload=await self.jwt_service.jwt_decode(refresh_token) if (jti:=payload.get("jti")) is None: raise self.error.credentials_error(detail="Jwt token is incorrect") @@ -174,23 +175,23 @@ class CurrentUserService: raise self.error.credentials_error(detail="Jwt token is incorrect") from e '''logout by assigning revoked flag''' - if self.jwt_db_actions.logout(jti): + if await self.jwt_db_actions.logout(jti): return True else: raise self.error.not_found_error(detail="Refresh Token Not Found") - def login(self, form_data_email:str, form_data_password:str, request:Request)->tuple[str, str]: + async def login(self, form_data_email:str, form_data_password:str, request:Request)->tuple[str, str]: '''revoke all the old refresh tokens''' - user = self._check(form_data_email, form_data_password) - self.jwt_db_actions.revoke_all(user_id=user.id) + user = await self._check(form_data_email, form_data_password) + await self.jwt_db_actions.revoke_all(user_id=user.id) '''create access and refresh tokens''' - access_token=self.create_access_token(user_id=user.id) - refresh_token=self.create_refresh_token(user_id=user.id,request=request) + access_token=await self.create_access_token(user_id=user.id) + refresh_token=await self.create_refresh_token(user_id=user.id,request=request) return (access_token, refresh_token) -def auth_service()->CurrentUserService: +async def auth_service()->CurrentUserService: return CurrentUserService() \ No newline at end of file diff --git a/src/service/auth/jwt.py b/src/service/auth/jwt.py index 4767275..25368c8 100644 --- a/src/service/auth/jwt.py +++ b/src/service/auth/jwt.py @@ -31,27 +31,27 @@ class JwtService: self.error=Errors() - def _validate_sub(self,data:dict)->None: + async def _validate_sub(self,data:dict)->None: if not (data.get("sub")) or data.get("sub") == "": raise self.error.credentials_error(detail="Jwt token is incorrect") - def create_access_token(self, data:dict)->str: + async def create_access_token(self, data:dict)->str: user_info=data.copy() - self._validate_sub(user_info) + await self._validate_sub(user_info) user_info.update({"exp": datetime.now(UTC)+timedelta(minutes=env_settings.ACCESS_TOKEN_EXPIRE_MINUTES), "token_type":"access"}) return jwt.encode(user_info, env_settings.SECRET_KEY, env_settings.ALGORITHM) - def create_refresh_token(self, data:dict)->tuple[str, str]: + async def create_refresh_token(self, data:dict)->tuple[str, str]: user_info=data.copy() jti=str(uuid4()) - self._validate_sub(user_info) + await self._validate_sub(user_info) user_info.update({"exp":datetime.now(UTC)+timedelta(days=env_settings.REFRESH_TOKEN_EXPIRE_DAYS), "token_type":"refresh", @@ -62,7 +62,7 @@ class JwtService: - def jwt_decode(self, token:str)->dict: + async def jwt_decode(self, token:str)->dict: try: payload=jwt.decode(token, env_settings.SECRET_KEY, algorithms=[env_settings.ALGORITHM], options={"require_exp": True} ) diff --git a/src/service/users_crud/users_crud.py b/src/service/users_crud/users_crud.py index 4588318..3ec2bb4 100644 --- a/src/service/users_crud/users_crud.py +++ b/src/service/users_crud/users_crud.py @@ -9,10 +9,11 @@ class CrudService: self.errors=Errors() self.crud_db_actions=UsersCrudActions() - def get_user_by_email(self, email:str)->UserOut: - user_entity=self.crud_db_actions.get_user_by_email(email) + async def get_user_by_email(self, email:str)->UserOut: + user_entity=await self.crud_db_actions.get_user_by_email(email) if not user_entity: raise self.errors.not_found_error(detail="User wasn't found") return UserOut.model_validate(user_entity) -crud_service=CrudService() \ No newline at end of file +async def crud_service()->CrudService: + return CrudService() \ No newline at end of file diff --git a/src/web/protected_routes/auth_routes.py b/src/web/protected_routes/auth_routes.py index 57299a9..87e5b5d 100644 --- a/src/web/protected_routes/auth_routes.py +++ b/src/web/protected_routes/auth_routes.py @@ -11,7 +11,7 @@ oauth2_schema=OAuth2PasswordBearer(tokenUrl="/protected/token", refreshUrl="/pro @router.post("/token") async def get_access_token(request: Request,response:Response,auth:CurrentUserService=Depends(auth_service), form_data:OAuth2PasswordRequestForm=Depends())->dict: # noqa: B008 - access_token, refresh_token=auth.login(form_data_email=form_data.username, form_data_password=form_data.password, request=request) + access_token, refresh_token=await auth.login(form_data_email=form_data.username, form_data_password=form_data.password, request=request) response.set_cookie( key="refresh_token", @@ -27,7 +27,7 @@ async def get_access_token(request: Request,response:Response,auth:CurrentUserSe @router.post("/refresh") async def get_refresh_token(request:Request,response:Response, refresh_token: str = Cookie(), auth:CurrentUserService=Depends(auth_service))->dict: # noqa: B008 - access_token, refresh_token= auth.refresh_token(refresh_token=refresh_token,request=request) + access_token, refresh_token= await auth.refresh_token(refresh_token=refresh_token,request=request) response.set_cookie( key="refresh_token", @@ -42,13 +42,13 @@ async def get_refresh_token(request:Request,response:Response, refresh_token: st async def get_current_user(token:str = Depends(oauth2_schema), auth:CurrentUserService=Depends(auth_service)) -> UserOut: # noqa: B008 - return UserOut.model_validate(auth.get_current_user(token)) + return UserOut.model_validate(await auth.get_current_user(token)) @router.get("/logout") async def logout(response:Response,refresh_token: str = Cookie(),auth:CurrentUserService=Depends(auth_service),current_user:UserOut=Depends(get_current_user))->bool: # noqa: B008 response.delete_cookie("refresh_token") - return auth.logout(refresh_token) + return await auth.logout(refresh_token) @router.get("") async def protected(current_user:UserOut=Depends(get_current_user))->dict: # noqa: B008 diff --git a/src/web/protected_routes/protected_user_action_routes.py b/src/web/protected_routes/protected_user_action_routes.py index 5d315a6..6a157bb 100644 --- a/src/web/protected_routes/protected_user_action_routes.py +++ b/src/web/protected_routes/protected_user_action_routes.py @@ -1,12 +1,11 @@ from fastapi import APIRouter, Depends from src.models.pydantic_models.model import UserOut -from src.service.users_crud.users_crud import crud_service +from src.service.users_crud.users_crud import CrudService, crud_service from src.web.protected_routes.auth_routes import get_current_user router=APIRouter(prefix="/user") - @router.get("/get_by_email") -async def get_current_user_by_email(email:str, current_user=Depends(get_current_user))->UserOut: # noqa: B008 - return crud_service.get_user_by_email(email) \ No newline at end of file +async def get_current_user_by_email(email:str, crud:CrudService=Depends(crud_service), current_user=Depends(get_current_user))->UserOut: # noqa: B008 + return await crud.get_user_by_email(email) \ No newline at end of file diff --git a/tests/conftest.py b/tests/conftest.py index 2009467..663e14f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,14 +1,14 @@ -import pytest +import pytest_asyncio from src.service.auth.jwt import HashService, JwtService -@pytest.fixture -def jwt_service()->JwtService: +@pytest_asyncio.fixture +async def jwt_service()->JwtService: jwt_service=JwtService() return jwt_service -@pytest.fixture -def hash_service()->HashService: +@pytest_asyncio.fixture +async def hash_service()->HashService: hash_service=HashService() return hash_service \ No newline at end of file diff --git a/tests/integrated/conftest.py b/tests/integrated/conftest.py index d925e5c..7d8a7d2 100644 --- a/tests/integrated/conftest.py +++ b/tests/integrated/conftest.py @@ -1,16 +1,16 @@ -import pytest +import pytest_asyncio from fastapi import Request from src.service.auth.auth import CurrentUserService -@pytest.fixture -def current_user_service()->CurrentUserService: +@pytest_asyncio.fixture +async def current_user_service()->CurrentUserService: current_user_service=CurrentUserService() return current_user_service -@pytest.fixture -def requests(mocker): +@pytest_asyncio.fixture +async def requests(mocker): fake_request = mocker.MagicMock(spec=Request) fake_request.headers = {"user-agent": "pytest-agent", "x-forwarded-for":"127.0.0.1"} return fake_request \ No newline at end of file diff --git a/tests/integrated/test_auth.py b/tests/integrated/test_auth.py index 6c3c576..99bc99b 100644 --- a/tests/integrated/test_auth.py +++ b/tests/integrated/test_auth.py @@ -11,7 +11,9 @@ from pydantic import ValidationError from src.models.configs_read.env import env_settings from src.service.auth.auth import CurrentUserService from src.service.auth.jwt import HashService, JwtService +from unittest.mock import AsyncMock +current_user_service=CurrentUserService() @pytest.mark.integra class TestAuth: @@ -19,19 +21,19 @@ class TestAuth: @pytest.mark.parametrize("user_data",[ pytest.param(SimpleNamespace(first_name="test",last_name="test",middle_name="test",email="d@d.d",direct_permissions=[],group=[],status=True), id="correct_data") ]) - def test_get_current_user_positive(self,current_user_service:CurrentUserService, jwt_service:JwtService, monkeypatch, user_data:SimpleNamespace)->None: + async def test_get_current_user_positive(self,current_user_service:CurrentUserService, jwt_service:JwtService, monkeypatch, user_data:SimpleNamespace)->None: with allure.step("create token"): - token=jwt_service.create_access_token({"sub":str(uuid4())}) + token=await jwt_service.create_access_token({"sub":str(uuid4())}) with allure.step("patching db call functions"): - monkeypatch.setattr(current_user_service.crud_db_actions, "get_user_by_id", lambda user:user_data) + monkeypatch.setattr(current_user_service.crud_db_actions, "get_user_by_id", AsyncMock(return_value=user_data)) with allure.step("test get_current_user_with_fake_token"): - test_result= current_user_service.get_current_user(token) + test_result= await current_user_service.get_current_user(token) assert test_result.first_name==user_data.first_name assert test_result.last_name==user_data.last_name @@ -46,37 +48,37 @@ class TestAuth: pytest.param(SimpleNamespace(first_name="test",last_name="test",middle_name="test",email="d@d.d",direct_permissions=[],group=[],status=True),1234, HTTPException, id="wrong_id"), pytest.param(SimpleNamespace(status=True),uuid4(), ValidationError,id="empty_model_data") ]) - def test_get_current_user_negative(self,current_user_service:CurrentUserService, jwt_service:JwtService, monkeypatch, user_data:SimpleNamespace, expected_exception, uuid)->None: + async def test_get_current_user_negative(self,current_user_service:CurrentUserService, jwt_service:JwtService, monkeypatch, user_data:SimpleNamespace, expected_exception, uuid)->None: with allure.step("create token"): - token=jwt_service.create_access_token({"sub":str(uuid)}) + token=await jwt_service.create_access_token({"sub":str(uuid)}) with allure.step("patching db call functions"): - monkeypatch.setattr(current_user_service.crud_db_actions, "get_user_by_id", lambda user:user_data) + monkeypatch.setattr(current_user_service.crud_db_actions, "get_user_by_id", AsyncMock(return_value=user_data)) with allure.step("test get_current_user_with_fake_token"), pytest.raises(expected_exception): - current_user_service.get_current_user(token) + await current_user_service.get_current_user(token) @pytest.mark.parametrize("user_data, form_data_email,form_data_password",[ pytest.param(SimpleNamespace(id=uuid4(),hashed_password="1234", first_name="test",last_name="test",middle_name="test",email="d@d.d",direct_permissions=[],group=[],status=True), "d@d.d", "1234", id="correct_data"), ]) - def test_login_positive(self, jwt_service:JwtService,current_user_service:CurrentUserService, monkeypatch, user_data:SimpleNamespace, hash_service:HashService, form_data_email:str, form_data_password:str, requests)->None: + async def test_login_positive(self, jwt_service:JwtService,current_user_service:CurrentUserService, monkeypatch, user_data:SimpleNamespace, hash_service:HashService, form_data_email:str, form_data_password:str, requests)->None: with allure.step("patching db call functions"): user_data.hashed_password=hash_service.plain_to_hash(user_data.hashed_password) - monkeypatch.setattr(current_user_service.crud_db_actions, "get_user_by_email", lambda user:user_data) - monkeypatch.setattr(current_user_service.jwt_db_actions, "revoke_all", lambda user_id: True) - monkeypatch.setattr(current_user_service.jwt_db_actions, "create_token", lambda token: True ) + monkeypatch.setattr(current_user_service.crud_db_actions, "get_user_by_email", AsyncMock(return_value=user_data)) + monkeypatch.setattr(current_user_service.jwt_db_actions, "revoke_all", AsyncMock(return_value=True)) + monkeypatch.setattr(current_user_service.jwt_db_actions, "create_token", AsyncMock(return_value=True)) fake_request = requests with allure.step("test login_with_fake_data"): - access, refresh=current_user_service.login(form_data_email, form_data_password,fake_request) + access, refresh=await current_user_service.login(form_data_email, form_data_password,fake_request) parts_a=access.split(".") parts_b=refresh.split(".") assert isinstance(access, str) @@ -90,36 +92,36 @@ class TestAuth: pytest.param(SimpleNamespace(id=uuid4(),hashed_password="1234", first_name="test",last_name="test",middle_name="test",email="d@d.d",direct_permissions=[],group=[],status=False), "d@d.d", "1234",HTTPException, id="false_status"), pytest.param(SimpleNamespace(id=1234,hashed_password="1234", first_name="test",last_name="test",middle_name="test",email="d@d.d",direct_permissions=[],group=[],status=True), "d@d.d", "1234",ValidationError, id="wrong_id"), ]) - def test_login_negative(self, current_user_service:CurrentUserService, user_data:SimpleNamespace, jwt_service:JwtService, monkeypatch, requests, hash_service:HashService, form_data_email:str, form_data_password:str, expected_exception): + async def test_login_negative(self, current_user_service:CurrentUserService, user_data:SimpleNamespace, jwt_service:JwtService, monkeypatch, requests, hash_service:HashService, form_data_email:str, form_data_password:str, expected_exception): with allure.step("patching db call functions"): user_data.hashed_password=hash_service.plain_to_hash(user_data.hashed_password) - monkeypatch.setattr(current_user_service.crud_db_actions, "get_user_by_email", lambda user:user_data) - monkeypatch.setattr(current_user_service.jwt_db_actions, "revoke_all", lambda user_id: True) - monkeypatch.setattr(current_user_service.jwt_db_actions, "create_token", lambda token: True ) + monkeypatch.setattr(current_user_service.crud_db_actions, "get_user_by_email", AsyncMock(return_value=user_data)) + monkeypatch.setattr(current_user_service.jwt_db_actions, "revoke_all", AsyncMock(return_value=True)) + monkeypatch.setattr(current_user_service.jwt_db_actions, "create_token", AsyncMock(return_value=True)) fake_request = requests with allure.step("test login_with_fake_data"), pytest.raises(expected_exception): - current_user_service.login(form_data_email, form_data_password,fake_request) + await current_user_service.login(form_data_email, form_data_password,fake_request) - def test_logout_positive(self, jwt_service:JwtService, monkeypatch, current_user_service:CurrentUserService)->None: + async def test_logout_positive(self, jwt_service:JwtService, monkeypatch, current_user_service:CurrentUserService)->None: with allure.step("create fake refresh token"): - token=jwt_service.create_refresh_token({"sub":str(uuid4())}) + token=await jwt_service.create_refresh_token({"sub":str(uuid4())}) with allure.step("patching db call functions"): - monkeypatch.setattr(current_user_service.jwt_db_actions, "logout", lambda jti: True ) + monkeypatch.setattr(current_user_service.jwt_db_actions, "logout", AsyncMock(return_value=True)) with allure.step("test logout with fake data"): - status=current_user_service.logout(token[0]) + status=await current_user_service.logout(token[0]) assert status is True @pytest.mark.parametrize("jti,db_result, expected_exception",[ @@ -127,13 +129,13 @@ class TestAuth: pytest.param(1234, True, HTTPException, id="jti_int"), pytest.param(str(uuid4()), False, HTTPException, id="db_result_none"), ]) - def test_logout_negative(self, jwt_service:JwtService, monkeypatch, current_user_service:CurrentUserService, expected_exception, jti, db_result)->None: + async def test_logout_negative(self, jwt_service:JwtService, monkeypatch, current_user_service:CurrentUserService, expected_exception, jti, db_result)->None: with allure.step("patching db call functions"): - monkeypatch.setattr(current_user_service.jwt_db_actions, "logout", lambda jti: db_result ) + monkeypatch.setattr(current_user_service.jwt_db_actions, "logout", AsyncMock(return_value=db_result) ) - def fake_create_refresh_token(data:dict)->str: + async def fake_create_refresh_token(data:dict)->str: return jwt.encode(data, env_settings.SECRET_KEY, env_settings.ALGORITHM) monkeypatch.setattr(jwt_service, "create_refresh_token", fake_create_refresh_token) @@ -141,39 +143,39 @@ class TestAuth: with allure.step("create fake refresh token"): - token=fake_create_refresh_token({"sub":str(uuid4()), "jti":jti, "token_type":"refresh", "exp":datetime.now(UTC)+timedelta(days=45)}) + token=await fake_create_refresh_token({"sub":str(uuid4()), "jti":jti, "token_type":"refresh", "exp":datetime.now(UTC)+timedelta(days=45)}) with allure.step("test logout with fake data"), pytest.raises(expected_exception): - current_user_service.logout(token) + await current_user_service.logout(token) @pytest.mark.parametrize("db_result_token, user_data_result_db", [ pytest.param(SimpleNamespace(is_revoked=False, expires_at=datetime.now(UTC)+timedelta(days=15)),SimpleNamespace(status=True), id="correct_data") ]) - def test_refresh_token_positive(self, monkeypatch, current_user_service:CurrentUserService, db_result_token, requests:Request, jwt_service:JwtService,user_data_result_db )->None: + async def test_refresh_token_positive(self, monkeypatch, current_user_service:CurrentUserService, db_result_token, requests:Request, jwt_service:JwtService,user_data_result_db )->None: with allure.step("patching db call functions"): - monkeypatch.setattr(current_user_service.jwt_db_actions,"get_token_by_id", lambda jti: db_result_token) - monkeypatch.setattr(current_user_service.jwt_db_actions, "revoke_all", lambda data:True) - monkeypatch.setattr(current_user_service.crud_db_actions, "get_user_by_id", lambda user:user_data_result_db) - monkeypatch.setattr(current_user_service.jwt_db_actions,"create_and_update_token", lambda data0, data1, data2: True) + monkeypatch.setattr(current_user_service.jwt_db_actions,"get_token_by_id", AsyncMock(return_value=db_result_token)) + monkeypatch.setattr(current_user_service.jwt_db_actions, "revoke_all", AsyncMock(return_value=True)) + monkeypatch.setattr(current_user_service.crud_db_actions, "get_user_by_id", AsyncMock(return_value=user_data_result_db)) + monkeypatch.setattr(current_user_service.jwt_db_actions,"create_and_update_token", AsyncMock(return_value=True)) fake_request = requests - def fake_create_refresh_token(data:dict)->str: + async def fake_create_refresh_token(data:dict)->str: return jwt.encode(data, env_settings.SECRET_KEY, env_settings.ALGORITHM) monkeypatch.setattr(jwt_service, "create_refresh_token", fake_create_refresh_token) with allure.step("create fake refresh token"): - token=fake_create_refresh_token({"sub":str(uuid4()), "jti":str(uuid4()), "token_type":"refresh", "exp":datetime.now(UTC)+timedelta(days=45)}) + token=await fake_create_refresh_token({"sub":str(uuid4()), "jti":str(uuid4()), "token_type":"refresh", "exp":datetime.now(UTC)+timedelta(days=45)}) with allure.step("test refresh token with fake data"): - new_access_token, new_refresh_token = current_user_service.refresh_token(token, fake_request) + new_access_token, new_refresh_token = await current_user_service.refresh_token(token, fake_request) parts_a=new_access_token.split(".") parts_b=new_refresh_token.split(".") assert isinstance(new_access_token, str) @@ -192,22 +194,22 @@ class TestAuth: pytest.param(SimpleNamespace(is_revoked=False, user_id="123",expires_at=datetime.now(UTC)+timedelta(days=15)),None,True,{"sub":str(uuid4()), "jti":str(uuid4()), "token_type":"refresh", "exp":datetime.now(UTC)+timedelta(days=45)}, HTTPException,id="user_missing"), pytest.param(SimpleNamespace(is_revoked=False,user_id="123", expires_at=datetime.now(UTC)-timedelta(days=15)),SimpleNamespace(status=True),True,{"sub":str(uuid4()), "jti":str(uuid4()), "token_type":"refresh", "exp":datetime.now(UTC)+timedelta(days=45)}, HTTPException,id="wrong_exp") ]) - def test_refresh_token_negative(self, monkeypatch, current_user_service:CurrentUserService, db_result_token, requests, jwt_service:JwtService,user_data_result_db, expected_exception, fake_token_data, update_result)->None: + async def test_refresh_token_negative(self, monkeypatch, current_user_service:CurrentUserService, db_result_token, requests, jwt_service:JwtService,user_data_result_db, expected_exception, fake_token_data, update_result)->None: with allure.step("patching db call functions"): - monkeypatch.setattr(current_user_service.jwt_db_actions,"get_token_by_id", lambda jti: db_result_token) - monkeypatch.setattr(current_user_service.jwt_db_actions, "revoke_all", lambda user_id:True) - monkeypatch.setattr(current_user_service.crud_db_actions, "get_user_by_id", lambda user:user_data_result_db) - monkeypatch.setattr(current_user_service.jwt_db_actions, "create_and_update_token", lambda old_jti, new_jti, new_token_record:update_result) + monkeypatch.setattr(current_user_service.jwt_db_actions,"get_token_by_id", AsyncMock(return_value=db_result_token)) + monkeypatch.setattr(current_user_service.jwt_db_actions, "revoke_all", AsyncMock(return_value=True)) + monkeypatch.setattr(current_user_service.crud_db_actions, "get_user_by_id", AsyncMock(return_value=user_data_result_db)) + monkeypatch.setattr(current_user_service.jwt_db_actions, "create_and_update_token", AsyncMock(return_value=update_result)) fake_request = requests - def fake_create_refresh_token(data:dict)->str: + async def fake_create_refresh_token(data:dict)->str: return jwt.encode(data, env_settings.SECRET_KEY, env_settings.ALGORITHM) monkeypatch.setattr(jwt_service, "create_refresh_token", fake_create_refresh_token) with allure.step("create fake refresh token"): - token=fake_create_refresh_token(fake_token_data) + token=await fake_create_refresh_token(fake_token_data) with allure.step("test refresh token with fake data"), pytest.raises(expected_exception): - current_user_service.refresh_token(token, fake_request) \ No newline at end of file + await current_user_service.refresh_token(token, fake_request) \ No newline at end of file diff --git a/tests/unit/test_jwt.py b/tests/unit/test_jwt.py index ca54248..be8e0e5 100644 --- a/tests/unit/test_jwt.py +++ b/tests/unit/test_jwt.py @@ -15,10 +15,10 @@ class TestJwt: @pytest.mark.parametrize("data", [ pytest.param({"sub": "123"}, id="full_sub") ]) - def test_access_create_positive(self, jwt_service:JwtService, data:dict)->None: + async def test_access_create_positive(self, jwt_service:JwtService, data:dict)->None: with allure.step("create correct access token"): - token = jwt_service.create_access_token(data) + token = await jwt_service.create_access_token(data) parts=token.split(".") assert isinstance(token, str) assert len(parts)==3 @@ -30,19 +30,19 @@ class TestJwt: pytest.param({"sub":""},HTTPException, id="empty_value"), pytest.param({"":""},HTTPException, id="empty_key_value") ]) - def test_access_create_negative(self, jwt_service:JwtService, data:dict, expected_exception)->None: + async def test_access_create_negative(self, jwt_service:JwtService, data:dict, expected_exception)->None: with allure.step("create invalid access token"),pytest.raises(expected_exception): - jwt_service.create_access_token(data) + await jwt_service.create_access_token(data) @pytest.mark.parametrize("data", [ pytest.param({"sub": "123"}, id="full_sub") ]) - def test_refresh_create_positive(self, jwt_service:JwtService, data:dict)->None: + async def test_refresh_create_positive(self, jwt_service:JwtService, data:dict)->None: with allure.step("create correct access token"): - token = jwt_service.create_refresh_token(data) + token = await jwt_service.create_refresh_token(data) parts=token[0].split(".") assert isinstance(token[0], str) assert isinstance(token[1], str) @@ -54,24 +54,24 @@ class TestJwt: pytest.param({"sub":""},HTTPException, id="empty_value"), pytest.param({"":""},HTTPException, id="empty_key_value") ]) - def test_refresh_create_negative(self, jwt_service:JwtService, data, expected_exception)->None: + async def test_refresh_create_negative(self, jwt_service:JwtService, data, expected_exception)->None: with allure.step("create invalid access token"), pytest.raises(expected_exception): - jwt_service.create_refresh_token(data) + await jwt_service.create_refresh_token(data) @pytest.mark.parametrize("data", [ pytest.param({"sub": "123", "exp":datetime.now(UTC)+timedelta(minutes=15), "token_type":"access"}, id="correct_data"), ]) - def test_jwt_decode_positive(self, data:dict, monkeypatch, jwt_service:JwtService)->None: + async def test_jwt_decode_positive(self, data:dict, monkeypatch, jwt_service:JwtService)->None: with allure.step("patch a create token function"): - def fake_create_access_token(data:dict)->str: + async def fake_create_access_token(data:dict)->str: return jwt.encode(data, env_settings.SECRET_KEY, env_settings.ALGORITHM) monkeypatch.setattr(jwt_service, "create_access_token", fake_create_access_token) with allure.step("create and decode correct token"): - fake_token = jwt_service.create_access_token(data) - payload=jwt_service.jwt_decode(fake_token) + fake_token = await jwt_service.create_access_token(data) + payload=await jwt_service.jwt_decode(fake_token) assert payload.get("sub") assert payload.get("exp") assert payload.get("token_type") @@ -83,15 +83,15 @@ class TestJwt: pytest.param({}, HTTPException, id="empty_data"), pytest.param("", AttributeError, id="not_dict_data") ]) - def test_jwt_decode_invalid(self,jwt_service:JwtService, expected_exception, data, monkeypatch)->None: + async def test_jwt_decode_invalid(self,jwt_service:JwtService, expected_exception, data, monkeypatch)->None: with allure.step("patch a create token function"): - def fake_create_access_token(data:dict)->str: + async def fake_create_access_token(data:dict)->str: return jwt.encode(data, env_settings.SECRET_KEY, env_settings.ALGORITHM) monkeypatch.setattr(jwt_service, "create_access_token", fake_create_access_token) with allure.step("create and decode invalid token"), pytest.raises(expected_exception): - fake_token=jwt_service.create_access_token(data) - jwt_service.jwt_decode(fake_token) + fake_token=await jwt_service.create_access_token(data) + await jwt_service.jwt_decode(fake_token) @pytest.mark.parametrize("time, key, algorithm", [ @@ -99,23 +99,23 @@ class TestJwt: pytest.param(-15, "correct_key", "HS256", id="wrong_time"), pytest.param(15, "correct_key", "HS512", id="wrong_algorithm"), ]) - def test_jwt_decode_wrong_env(self, monkeypatch, time:int, key:str, algorithm:str, jwt_service)->None: + async def test_jwt_decode_wrong_env(self, monkeypatch, time:int, key:str, algorithm:str, jwt_service)->None: with allure.step("patch a create token function"): - def fake_create_access_token(data:dict, key:str, algorithm:str)->str: + async def fake_create_access_token(data:dict, key:str, algorithm:str)->str: data.update({"exp":datetime.now(UTC)+timedelta(minutes=time)}) return jwt.encode(data, key, algorithm) monkeypatch.setattr(jwt_service, "create_access_token", fake_create_access_token) with allure.step("create and decode token with wrong data inside"), pytest.raises(HTTPException): - fake_token=jwt_service.create_access_token({"sub": "123", "token_type":"access"}, key, algorithm) - jwt_service.jwt_decode(fake_token) + fake_token=await jwt_service.create_access_token({"sub": "123", "token_type":"access"}, key, algorithm) + await jwt_service.jwt_decode(fake_token) @pytest.mark.parametrize("password",[ pytest.param("plain_password", id="correct_plain_password") ]) - def test_hash_and_veryfy_positive(self, password:str, hash_service:HashService)->None: + async def test_hash_and_veryfy_positive(self, password:str, hash_service:HashService)->None: with allure.step("encode password"): encoded_password=hash_service.plain_to_hash(password) @@ -127,7 +127,7 @@ class TestJwt: - def test_verify_wrong_password(self, hash_service:HashService)->None: + async def test_verify_wrong_password(self, hash_service:HashService)->None: with allure.step("encode password"): encoded_password=hash_service.plain_to_hash("plain_password") @@ -136,9 +136,9 @@ class TestJwt: assert hash_service.verify_password("wrong_password", encoded_password) is False - def test_token_to_hash_determistic(self, hash_service:HashService)->None: + async def test_token_to_hash_determistic(self, hash_service:HashService)->None: assert hash_service.token_to_hash("abc")==hash_service.token_to_hash("abc") - def test_token_to_hash_different_input(self, hash_service:HashService)->None: + async def test_token_to_hash_different_input(self, hash_service:HashService)->None: assert hash_service.token_to_hash("abc")!=hash_service.token_to_hash("xyz")