From f6990e6d2304d65686f22852e35e231d162278bd Mon Sep 17 00:00:00 2001 From: Rodrigo Colao Merlo Date: Mon, 9 Dec 2024 17:30:21 -0300 Subject: [PATCH 01/10] feature: New endpoint to return total counters for subject (M2-7889) (#1669) * feature: New endpoint to return total counters for subject (M2- 7889) * Refactoring to better understading code * Improvments on tests * Fix change in old endpoint response * Fix duplicate acitivity ids and activities counts * Update src/apps/activities/router.py Co-authored-by: Farmer Paul * Change to union to be more clear * fix: refactory code to count correctly * fix lint * Refactoring code * Fix in related endpoint * Filtering out soft deleted subjects in submissions * fix: use internal classes * fix: counting submissions when have soft deleted subjects * fix lint * Add counting for deleted activities * Filtering out deleted subject for submissions queries to avoid wroing activity listing * Update src/apps/activities/api/activities.py Co-authored-by: Farmer Paul * Update src/apps/activities/api/activities.py Co-authored-by: Farmer Paul * Removing limited account from auto-assigned activites * Rename endpoint to Metadata * fix: use `submit_id`s for flow submission counts * fix: exclude flows that have not been completed For all the PDP queries, a "submission" for a flow should only be **completed** ones. A flow that has only been partially completed (say, only the 1st activity of 5 activities have been submitted) should not count towards having any submissions, and thus should NOT be: - listed on the PDP pages for the associated subjects - included in the tallying of activities/flows for that tab - included in the submissions count on the flow level within each tab - included in that flow's expanded view's submissions counts * Add more tests --------- Co-authored-by: Farmer Paul --- Pipfile | 33 +- Pipfile.lock | 1001 ++++++++--------- src/apps/activities/api/activities.py | 115 +- src/apps/activities/crud/activity.py | 6 + src/apps/activities/domain/activity.py | 17 + src/apps/activities/router.py | 15 + src/apps/activities/services/activity.py | 10 + src/apps/activities/tests/test_activities.py | 236 ++++ .../activity_assignments/crud/assignments.py | 56 +- .../domain/assignments.py | 15 +- src/apps/activity_assignments/service.py | 32 + src/apps/activity_flows/crud/flow.py | 7 + src/apps/answers/crud/answers.py | 77 +- src/apps/answers/domain/answers.py | 12 + src/apps/answers/service.py | 69 +- 15 files changed, 1146 insertions(+), 555 deletions(-) diff --git a/Pipfile b/Pipfile index 2b90f57fd3d..804cd0b2329 100644 --- a/Pipfile +++ b/Pipfile @@ -4,24 +4,20 @@ verify_ssl = true name = "pypi" [packages] -aio-pika = "==9.4.3" +aio-pika = "==9.5.3" aiofiles = "==24.1.0" -aiohttp = "==3.10.10" +aiohttp = "==3.11.9" alembic = "==1.13.3" asyncpg = "==0.30.0" azure-storage-blob = "==12.23.1" bcrypt = "==4.2.0" -boto3 = "==1.35.47" -fastapi = "==0.115.3" -# The latest version of the fastapi is not taken because of the issue -# starlette version for those deps ==0.21.0 -# with fastapi-mail that requires 0.21 < starlette < 0.22 - +boto3 = "==1.35.54" +fastapi = "==0.115.4" fastapi-mail = "==1.2.9" firebase-admin = "==6.5.0" -httpx = "==0.27.2" +httpx = "==0.28.0" jinja2 = "==3.1.4" -nh3 = "==0.2.18" +nh3 = "==0.2.19" opentelemetry-api = "==1.27.0" opentelemetry-distro = "==0.48b0" opentelemetry-exporter-otlp = "==1.27.0" @@ -44,8 +40,8 @@ opentelemetry-util-http = "==0.48b0" pyOpenSSL = "==24.2.1" pydantic = { extras = ["email"], version = "==1.10.18" } pymongo = "*" -python-multipart = "==0.0.12" -redis = "==5.1.1" +python-multipart = "==0.0.19" +redis = "==5.2.0" sentry-sdk = "~=2.13" sqlalchemy = { extras = ["asyncio"], version = "==1.4.53" } sqlalchemy-utils = "==0.41.2" @@ -55,23 +51,24 @@ taskiq-fastapi = "==0.3.2" taskiq-redis = "==1.0.2" typer = "==0.12.5" uvicorn = { extras = ["standard"], version = "==0.32.0" } -pyjwt = "==2.9.0" +pyjwt = "==2.10.1" +more-itertools = "==10.5.0" [dev-packages] ipdb = "==0.13.13" pudb = "==2024.1.3" pre-commit = "==4.0.1" -ruff = "==0.7.0" +ruff = "==0.7.2" allure-pytest = "==2.13.5" pydantic-factories = "==1.17.3" -pytest = "==8.3.3" +pytest = "==8.3.4" pytest-asyncio = "~=0.19" -pytest-cov = "==5.0.0" +pytest-cov = "==6.0.0" pytest-env = "==1.1.5" pytest-lazy-fixtures = "==1.1.1" pytest-mock = "==3.14.0" nest-asyncio = "==1.6.0" -gevent = "==24.2.1" +gevent = "==24.11.1" mypy = "==1.13.0" types-python-dateutil = "==2.9.0.20241003" typing-extensions = "==4.12.2" @@ -80,7 +77,7 @@ types-pytz = "==2024.2.0.20241003" types-aiofiles = "==24.1.0.20240626" types-cachetools = "==5.5.0.20240820" greenlet = "==3.1.0" -reproschema = "*" +reproschema = "0.9.0" cachetools = "==5.3.0" pyld = "==2.0.4" diff --git a/Pipfile.lock b/Pipfile.lock index 9f1ed75fa45..0cea16b642c 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "c14ff55e7786bd20e65c9dae3fdbefaa81d3cfd6800b78a020325c8efb68d27b" + "sha256": "578bf8ce82875f3bc65c46c8dada7a184f74af54b6b702f5ed24f949e13f0177" }, "pipfile-spec": 6, "requires": { @@ -18,12 +18,12 @@ "default": { "aio-pika": { "hashes": [ - "sha256:f1423d2d5a8b7315d144efe1773763bf687ac17aa1535385982687e9e5ed49bb", - "sha256:fd2b1fce25f6ed5203ef1dd554dc03b90c9a46a64aaf758d032d78dc31e5295d" + "sha256:95c19605ad2918e46ae39ead9a4991d5a8738dceedef11ff352b62eb3f935f36", + "sha256:9cdbc3350a76a04947348f07fa606bb76bb2d1bcb36523cc5452210e32a5041b" ], "index": "pypi", - "markers": "python_version >= '3.8' and python_version < '4.0'", - "version": "==9.4.3" + "markers": "python_version >= '3.9' and python_version < '4.0'", + "version": "==9.5.3" }, "aiofiles": { "hashes": [ @@ -36,109 +36,94 @@ }, "aiohappyeyeballs": { "hashes": [ - "sha256:75cf88a15106a5002a8eb1dab212525c00d1f4c0fa96e551c9fbe6f09a621586", - "sha256:8a7a83727b2756f394ab2895ea0765a0a8c475e3c71e98d43d76f22b4b435572" + "sha256:5fdd7d87889c63183afc18ce9271f9b0a7d32c2303e394468dd45d514a757745", + "sha256:a980909d50efcd44795c4afeca523296716d50cd756ddca6af8c65b996e27de8" ], "markers": "python_version >= '3.8'", - "version": "==2.4.3" + "version": "==2.4.4" }, "aiohttp": { "hashes": [ - "sha256:007ec22fbc573e5eb2fb7dec4198ef8f6bf2fe4ce20020798b2eb5d0abda6138", - "sha256:00819de9e45d42584bed046314c40ea7e9aea95411b38971082cad449392b08c", - "sha256:01948b1d570f83ee7bbf5a60ea2375a89dfb09fd419170e7f5af029510033d24", - "sha256:038f514fe39e235e9fef6717fbf944057bfa24f9b3db9ee551a7ecf584b5b480", - "sha256:03a42ac7895406220124c88911ebee31ba8b2d24c98507f4a8bf826b2937c7f2", - "sha256:05646ebe6b94cc93407b3bf34b9eb26c20722384d068eb7339de802154d61bc5", - "sha256:0631dd7c9f0822cc61c88586ca76d5b5ada26538097d0f1df510b082bad3411a", - "sha256:0b00807e2605f16e1e198f33a53ce3c4523114059b0c09c337209ae55e3823a8", - "sha256:0e1b370d8007c4ae31ee6db7f9a2fe801a42b146cec80a86766e7ad5c4a259cf", - "sha256:15ecd889a709b0080f02721255b3f80bb261c2293d3c748151274dfea93ac871", - "sha256:1b66ccafef7336a1e1f0e389901f60c1d920102315a56df85e49552308fc0486", - "sha256:1bbb122c557a16fafc10354b9d99ebf2f2808a660d78202f10ba9d50786384b9", - "sha256:1eb89d3d29adaf533588f209768a9c02e44e4baf832b08118749c5fad191781d", - "sha256:258c5dd01afc10015866114e210fb7365f0d02d9d059c3c3415382ab633fcbcb", - "sha256:2609e9ab08474702cc67b7702dbb8a80e392c54613ebe80db7e8dbdb79837c68", - "sha256:274cfa632350225ce3fdeb318c23b4a10ec25c0e2c880eff951a3842cf358ac1", - "sha256:28529e08fde6f12eba8677f5a8608500ed33c086f974de68cc65ab218713a59d", - "sha256:2b606353da03edcc71130b52388d25f9a30a126e04caef1fd637e31683033abd", - "sha256:30ca7c3b94708a9d7ae76ff281b2f47d8eaf2579cd05971b5dc681db8caac6e1", - "sha256:333cf6cf8e65f6a1e06e9eb3e643a0c515bb850d470902274239fea02033e9a8", - "sha256:3455522392fb15ff549d92fbf4b73b559d5e43dc522588f7eb3e54c3f38beee7", - "sha256:362f641f9071e5f3ee6f8e7d37d5ed0d95aae656adf4ef578313ee585b585959", - "sha256:3bcd391d083f636c06a68715e69467963d1f9600f85ef556ea82e9ef25f043f7", - "sha256:3dffb610a30d643983aeb185ce134f97f290f8935f0abccdd32c77bed9388b42", - "sha256:3fe407bf93533a6fa82dece0e74dbcaaf5d684e5a51862887f9eaebe6372cd79", - "sha256:413251f6fcf552a33c981c4709a6bba37b12710982fec8e558ae944bfb2abd38", - "sha256:438cd072f75bb6612f2aca29f8bd7cdf6e35e8f160bc312e49fbecab77c99e3a", - "sha256:4470c73c12cd9109db8277287d11f9dd98f77fc54155fc71a7738a83ffcc8ea8", - "sha256:45c3b868724137f713a38376fef8120c166d1eadd50da1855c112fe97954aed8", - "sha256:486f7aabfa292719a2753c016cc3a8f8172965cabb3ea2e7f7436c7f5a22a151", - "sha256:4f05e9727ce409358baa615dbeb9b969db94324a79b5a5cea45d39bdb01d82e6", - "sha256:50aed5155f819873d23520919e16703fc8925e509abbb1a1491b0087d1cd969e", - "sha256:50edbcad60d8f0e3eccc68da67f37268b5144ecc34d59f27a02f9611c1d4eec7", - "sha256:54ca74df1be3c7ca1cf7f4c971c79c2daf48d9aa65dea1a662ae18926f5bc8ce", - "sha256:578a4b875af3e0daaf1ac6fa983d93e0bbfec3ead753b6d6f33d467100cdc67b", - "sha256:597a079284b7ee65ee102bc3a6ea226a37d2b96d0418cc9047490f231dc09fe8", - "sha256:59bb3c54aa420521dc4ce3cc2c3fe2ad82adf7b09403fa1f48ae45c0cbde6628", - "sha256:5c6a5b8c7926ba5d8545c7dd22961a107526562da31a7a32fa2456baf040939f", - "sha256:64f6c17757251e2b8d885d728b6433d9d970573586a78b78ba8929b0f41d045a", - "sha256:679abe5d3858b33c2cf74faec299fda60ea9de62916e8b67e625d65bf069a3b7", - "sha256:741a46d58677d8c733175d7e5aa618d277cd9d880301a380fd296975a9cdd7bc", - "sha256:7789050d9e5d0c309c706953e5e8876e38662d57d45f936902e176d19f1c58ab", - "sha256:77abf6665ae54000b98b3c742bc6ea1d1fb31c394bcabf8b5d2c1ac3ebfe7f3b", - "sha256:79019094f87c9fb44f8d769e41dbb664d6e8fcfd62f665ccce36762deaa0e911", - "sha256:7b06b7843929e41a94ea09eb1ce3927865387e3e23ebe108e0d0d09b08d25be9", - "sha256:7e338c0523d024fad378b376a79faff37fafb3c001872a618cde1d322400a572", - "sha256:7ea7ffc6d6d6f8a11e6f40091a1040995cdff02cfc9ba4c2f30a516cb2633554", - "sha256:8105fd8a890df77b76dd3054cddf01a879fc13e8af576805d667e0fa0224c35d", - "sha256:84afcdea18eda514c25bc68b9af2a2b1adea7c08899175a51fe7c4fb6d551257", - "sha256:9294bbb581f92770e6ed5c19559e1e99255e4ca604a22c5c6397b2f9dd3ee42c", - "sha256:93429602396f3383a797a2a70e5f1de5df8e35535d7806c9f91df06f297e109b", - "sha256:9627cc1a10c8c409b5822a92d57a77f383b554463d1884008e051c32ab1b3742", - "sha256:998f3bd3cfc95e9424a6acd7840cbdd39e45bc09ef87533c006f94ac47296090", - "sha256:9c72109213eb9d3874f7ac8c0c5fa90e072d678e117d9061c06e30c85b4cf0e6", - "sha256:9fc1500fd2a952c5c8e3b29aaf7e3cc6e27e9cfc0a8819b3bce48cc1b849e4cc", - "sha256:a3f00003de6eba42d6e94fabb4125600d6e484846dbf90ea8e48a800430cc142", - "sha256:a45d85cf20b5e0d0aa5a8dca27cce8eddef3292bc29d72dcad1641f4ed50aa16", - "sha256:a7d8d14fe962153fc681f6366bdec33d4356f98a3e3567782aac1b6e0e40109a", - "sha256:a8fa23fe62c436ccf23ff930149c047f060c7126eae3ccea005f0483f27b2e28", - "sha256:aa6658732517ddabe22c9036479eabce6036655ba87a0224c612e1ae6af2087e", - "sha256:aafc8ee9b742ce75044ae9a4d3e60e3d918d15a4c2e08a6c3c3e38fa59b92d94", - "sha256:ab5a5a0c7a7991d90446a198689c0535be89bbd6b410a1f9a66688f0880ec026", - "sha256:acd48d5b80ee80f9432a165c0ac8cbf9253eaddb6113269a5e18699b33958dbb", - "sha256:ad7593bb24b2ab09e65e8a1d385606f0f47c65b5a2ae6c551db67d6653e78c28", - "sha256:baa42524a82f75303f714108fea528ccacf0386af429b69fff141ffef1c534f9", - "sha256:bdfcf6443637c148c4e1a20c48c566aa694fa5e288d34b20fcdc58507882fed3", - "sha256:be7443669ae9c016b71f402e43208e13ddf00912f47f623ee5994e12fc7d4b3f", - "sha256:c02a30b904282777d872266b87b20ed8cc0d1501855e27f831320f471d54d983", - "sha256:c1277cd707c465cd09572a774559a3cc7c7a28802eb3a2a9472588f062097205", - "sha256:c30a0eafc89d28e7f959281b58198a9fa5e99405f716c0289b7892ca345fe45f", - "sha256:c5ce2ce7c997e1971b7184ee37deb6ea9922ef5163c6ee5aa3c274b05f9e12fa", - "sha256:c823bc3971c44ab93e611ab1a46b1eafeae474c0c844aff4b7474287b75fe49c", - "sha256:ce0cdc074d540265bfeb31336e678b4e37316849d13b308607efa527e981f5c2", - "sha256:d1720b4f14c78a3089562b8875b53e36b51c97c51adc53325a69b79b4b48ebcb", - "sha256:d183cf9c797a5291e8301790ed6d053480ed94070637bfaad914dd38b0981f67", - "sha256:d9010c31cd6fa59438da4e58a7f19e4753f7f264300cd152e7f90d4602449762", - "sha256:d9e5e4a85bdb56d224f412d9c98ae4cbd032cc4f3161818f692cd81766eee65a", - "sha256:da1dee8948d2137bb51fbb8a53cce6b1bcc86003c6b42565f008438b806cccd8", - "sha256:df9270660711670e68803107d55c2b5949c2e0f2e4896da176e1ecfc068b974a", - "sha256:e00e3505cd80440f6c98c6d69269dcc2a119f86ad0a9fd70bccc59504bebd68a", - "sha256:e48d5021a84d341bcaf95c8460b152cfbad770d28e5fe14a768988c461b821bc", - "sha256:e7f8b04d83483577fd9200461b057c9f14ced334dcb053090cea1da9c8321a91", - "sha256:edfe3341033a6b53a5c522c802deb2079eee5cbfbb0af032a55064bd65c73a23", - "sha256:ef9c33cc5cbca35808f6c74be11eb7f5f6b14d2311be84a15b594bd3e58b5527", - "sha256:f2d4324a98062be0525d16f768a03e0bbb3b9fe301ceee99611dc9a7953124e6", - "sha256:f3935f82f6f4a3820270842e90456ebad3af15810cf65932bd24da4463bc0a4c", - "sha256:f614ab0c76397661b90b6851a030004dac502e48260ea10f2441abd2207fbcc7", - "sha256:f7db54c7914cc99d901d93a34704833568d86c20925b2762f9fa779f9cd2e70f", - "sha256:fbc6264158392bad9df19537e872d476f7c57adf718944cc1e4495cbabf38e2a", - "sha256:fe2fb38c2ed905a2582948e2de560675e9dfbee94c6d5ccdb1301c6d0a5bf092", - "sha256:ffe595f10566f8276b76dc3a11ae4bb7eba1aac8ddd75811736a15b0d5311414" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==3.10.10" + "sha256:0411777249f25d11bd2964a230b3ffafcbed6cd65d0f2b132bc2b8f5b8c347c7", + "sha256:0a97d657f6cf8782a830bb476c13f7d777cfcab8428ac49dde15c22babceb361", + "sha256:0b5a5009b0159a8f707879dc102b139466d8ec6db05103ec1520394fdd8ea02c", + "sha256:0bcb7f6976dc0b6b56efde13294862adf68dd48854111b422a336fa729a82ea6", + "sha256:14624d96f0d69cf451deed3173079a68c322279be6030208b045ab77e1e8d550", + "sha256:15c4e489942d987d5dac0ba39e5772dcbed4cc9ae3710d1025d5ba95e4a5349c", + "sha256:176f8bb8931da0613bb0ed16326d01330066bb1e172dd97e1e02b1c27383277b", + "sha256:17af09d963fa1acd7e4c280e9354aeafd9e3d47eaa4a6bfbd2171ad7da49f0c5", + "sha256:1a8b13b9950d8b2f8f58b6e5842c4b842b5887e2c32e3f4644d6642f1659a530", + "sha256:202f40fb686e5f93908eee0c75d1e6fbe50a43e9bd4909bf3bf4a56b560ca180", + "sha256:21cbe97839b009826a61b143d3ca4964c8590d7aed33d6118125e5b71691ca46", + "sha256:27935716f8d62c1c73010428db310fd10136002cfc6d52b0ba7bdfa752d26066", + "sha256:282e0a7ddd36ebc411f156aeaa0491e8fe7f030e2a95da532cf0c84b0b70bc66", + "sha256:28f29bce89c3b401a53d6fd4bee401ee943083bf2bdc12ef297c1d63155070b0", + "sha256:2ac9fd83096df36728da8e2f4488ac3b5602238f602706606f3702f07a13a409", + "sha256:30f9f89ae625d412043f12ca3771b2ccec227cc93b93bb1f994db6e1af40a7d3", + "sha256:317251b9c9a2f1a9ff9cd093775b34c6861d1d7df9439ce3d32a88c275c995cd", + "sha256:31de2f10f63f96cc19e04bd2df9549559beadd0b2ee2da24a17e7ed877ca8c60", + "sha256:36df00e0541f264ce42d62280281541a47474dfda500bc5b7f24f70a7f87be7a", + "sha256:39625703540feb50b6b7f938b3856d1f4886d2e585d88274e62b1bd273fae09b", + "sha256:3f5461c77649358610fb9694e790956b4238ac5d9e697a17f63619c096469afe", + "sha256:4313f3bc901255b22f01663eeeae167468264fdae0d32c25fc631d5d6e15b502", + "sha256:442356e8924fe1a121f8c87866b0ecdc785757fd28924b17c20493961b3d6697", + "sha256:44cb1a1326a0264480a789e6100dc3e07122eb8cd1ad6b784a3d47d13ed1d89c", + "sha256:44d323aa80a867cb6db6bebb4bbec677c6478e38128847f2c6b0f70eae984d72", + "sha256:499368eb904566fbdf1a3836a1532000ef1308f34a1bcbf36e6351904cced771", + "sha256:4b01d9cfcb616eeb6d40f02e66bebfe7b06d9f2ef81641fdd50b8dd981166e0b", + "sha256:5720ebbc7a1b46c33a42d489d25d36c64c419f52159485e55589fbec648ea49a", + "sha256:5cc5e0d069c56645446c45a4b5010d4b33ac6c5ebfd369a791b5f097e46a3c08", + "sha256:618b18c3a2360ac940a5503da14fa4f880c5b9bc315ec20a830357bcc62e6bae", + "sha256:6435a66957cdba1a0b16f368bde03ce9c79c57306b39510da6ae5312a1a5b2c1", + "sha256:647ec5bee7e4ec9f1034ab48173b5fa970d9a991e565549b965e93331f1328fe", + "sha256:6e1e9e447856e9b7b3d38e1316ae9a8c92e7536ef48373de758ea055edfd5db5", + "sha256:6ef1550bb5f55f71b97a6a395286db07f7f2c01c8890e613556df9a51da91e8d", + "sha256:6ffa45cc55b18d4ac1396d1ddb029f139b1d3480f1594130e62bceadf2e1a838", + "sha256:77f31cebd8c27a36af6c7346055ac564946e562080ee1a838da724585c67474f", + "sha256:7a3b5b2c012d70c63d9d13c57ed1603709a4d9d7d473e4a9dfece0e4ea3d5f51", + "sha256:7a7ddf981a0b953ade1c2379052d47ccda2f58ab678fca0671c7c7ca2f67aac2", + "sha256:84de955314aa5e8d469b00b14d6d714b008087a0222b0f743e7ffac34ef56aff", + "sha256:8dcfd14c712aa9dd18049280bfb2f95700ff6a8bde645e09f17c3ed3f05a0130", + "sha256:928f92f80e2e8d6567b87d3316c1fd9860ccfe36e87a9a7f5237d4cda8baa1ba", + "sha256:9384b07cfd3045b37b05ed002d1c255db02fb96506ad65f0f9b776b762a7572e", + "sha256:96726839a42429318017e67a42cca75d4f0d5248a809b3cc2e125445edd7d50d", + "sha256:96bbec47beb131bbf4bae05d8ef99ad9e5738f12717cfbbf16648b78b0232e87", + "sha256:9bcf97b971289be69638d8b1b616f7e557e1342debc7fc86cf89d3f08960e411", + "sha256:a0cf4d814689e58f57ecd5d8c523e6538417ca2e72ff52c007c64065cef50fb2", + "sha256:a7c6147c6306f537cff59409609508a1d2eff81199f0302dd456bb9e7ea50c39", + "sha256:a9266644064779840feec0e34f10a89b3ff1d2d6b751fe90017abcad1864fa7c", + "sha256:afbe85b50ade42ddff5669947afde9e8a610e64d2c80be046d67ec4368e555fa", + "sha256:afcda759a69c6a8be3aae764ec6733155aa4a5ad9aad4f398b52ba4037942fe3", + "sha256:b2fab23003c4bb2249729a7290a76c1dda38c438300fdf97d4e42bf78b19c810", + "sha256:bd3f711f4c99da0091ced41dccdc1bcf8be0281dc314d6d9c6b6cf5df66f37a9", + "sha256:be0c7c98e38a1e3ad7a6ff64af8b6d6db34bf5a41b1478e24c3c74d9e7f8ed42", + "sha256:c1f2d7fd583fc79c240094b3e7237d88493814d4b300d013a42726c35a734bc9", + "sha256:c5bba6b83fde4ca233cfda04cbd4685ab88696b0c8eaf76f7148969eab5e248a", + "sha256:c6beeac698671baa558e82fa160be9761cf0eb25861943f4689ecf9000f8ebd0", + "sha256:c7333e7239415076d1418dbfb7fa4df48f3a5b00f8fdf854fca549080455bc14", + "sha256:c8a02f74ae419e3955af60f570d83187423e42e672a6433c5e292f1d23619269", + "sha256:c9c23e62f3545c2216100603614f9e019e41b9403c47dd85b8e7e5015bf1bde0", + "sha256:cca505829cdab58c2495ff418c96092d225a1bbd486f79017f6de915580d3c44", + "sha256:d3108f0ad5c6b6d78eec5273219a5bbd884b4aacec17883ceefaac988850ce6e", + "sha256:d4b8a1b6c7a68c73191f2ebd3bf66f7ce02f9c374e309bdb68ba886bbbf1b938", + "sha256:d6e274661c74195708fc4380a4ef64298926c5a50bb10fbae3d01627d7a075b7", + "sha256:db2914de2559809fdbcf3e48f41b17a493b58cb7988d3e211f6b63126c55fe82", + "sha256:e738aabff3586091221044b7a584865ddc4d6120346d12e28e788307cd731043", + "sha256:e7f6173302f8a329ca5d1ee592af9e628d3ade87816e9958dcf7cdae2841def7", + "sha256:e9d036a9a41fc78e8a3f10a86c2fc1098fca8fab8715ba9eb999ce4788d35df0", + "sha256:ea142255d4901b03f89cb6a94411ecec117786a76fc9ab043af8f51dd50b5313", + "sha256:ebd3e6b0c7d4954cca59d241970011f8d3327633d555051c430bd09ff49dc494", + "sha256:ec656680fc53a13f849c71afd0c84a55c536206d524cbc831cde80abbe80489e", + "sha256:ec8df0ff5a911c6d21957a9182402aad7bf060eaeffd77c9ea1c16aecab5adbf", + "sha256:ed95d66745f53e129e935ad726167d3a6cb18c5d33df3165974d54742c373868", + "sha256:ef2c9499b7bd1e24e473dc1a85de55d72fd084eea3d8bdeec7ee0720decb54fa", + "sha256:f5252ba8b43906f206048fa569debf2cd0da0316e8d5b4d25abe53307f573941", + "sha256:f737fef6e117856400afee4f17774cdea392b28ecf058833f5eca368a18cf1bf", + "sha256:fc726c3fa8f606d07bd2b500e5dc4c0fd664c59be7788a16b9e34352c50b6b6b" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==3.11.9" }, "aiormq": { "hashes": [ @@ -255,11 +240,11 @@ }, "azure-core": { "hashes": [ - "sha256:22954de3777e0250029360ef31d80448ef1be13b80a459bff80ba7073379e2cd", - "sha256:656a0dd61e1869b1506b7c6a3b31d62f15984b1a573d6326f6aa2f3e4123284b" + "sha256:22b3c35d6b2dae14990f6c1be2912bf23ffe50b220e708a28ab1bb92b1c730e5", + "sha256:eac191a0efb23bfa83fddf321b27b122b4ec847befa3091fa736a5c32c50d7b4" ], "markers": "python_version >= '3.8'", - "version": "==1.31.0" + "version": "==1.32.0" }, "azure-storage-blob": { "hashes": [ @@ -314,20 +299,20 @@ }, "boto3": { "hashes": [ - "sha256:0b307f685875e9c7857ce21c0d3050d8d4f3778455a6852d5f98ac75194b400e", - "sha256:65b808e4cf1af8c2f405382d53656a0d92eee8f85c7388c43d64c7a5571b065f" + "sha256:2d5e160b614db55fbee7981001c54476cb827c441cef65b2fcb2c52a62019909", + "sha256:7d9c359bbbc858a60b51c86328db813353c8bd1940212cdbd0a7da835291c2e1" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==1.35.47" + "version": "==1.35.54" }, "botocore": { "hashes": [ - "sha256:05f4493119a96799ff84d43e78691efac3177e1aec8840cca99511de940e342a", - "sha256:f8f703463d3cd8b6abe2bedc443a7ab29f0e2ff1588a2e83164b108748645547" + "sha256:131bb59ce59c8a939b31e8e647242d70cf11d32d4529fa4dca01feea1e891a76", + "sha256:9cca1811094b6cdc144c2c063a3ec2db6d7c88194b04d4277cd34fc8e3473aff" ], "markers": "python_version >= '3.8'", - "version": "==1.35.47" + "version": "==1.35.54" }, "cachecontrol": { "hashes": [ @@ -423,7 +408,7 @@ "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87", "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b" ], - "markers": "platform_python_implementation != 'PyPy'", + "markers": "python_version >= '3.8'", "version": "==1.17.1" }, "charset-normalizer": { @@ -602,14 +587,22 @@ "markers": "python_version >= '3.5'", "version": "==1.3.1" }, + "exceptiongroup": { + "hashes": [ + "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", + "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" + ], + "markers": "python_version >= '3.7'", + "version": "==1.2.2" + }, "fastapi": { "hashes": [ - "sha256:8035e8f9a2b0aa89cea03b6c77721178ed5358e1aea4cd8570d9466895c0638c", - "sha256:c091c6a35599c036d676fa24bd4a6e19fa30058d93d950216cdc672881f6f7db" + "sha256:0b504a063ffb3cf96a5e27dc1bc32c80ca743a2528574f9cdc77daa2d31b4742", + "sha256:db653475586b091cb8b2fec2ac54a680ac6a158e07406e1abae31679e8826349" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==0.115.3" + "version": "==0.115.4" }, "fastapi-mail": { "hashes": [ @@ -996,11 +989,11 @@ }, "httpcore": { "hashes": [ - "sha256:27b59625743b85577a8c0e10e55b50b5368a4f2cfe8cc7bcfa9cf00829c2682f", - "sha256:73f6dbd6eb8c21bbf7ef8efad555481853f5f6acdeaff1edb0694289269ee17f" + "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c", + "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd" ], "markers": "python_version >= '3.8'", - "version": "==1.0.6" + "version": "==1.0.7" }, "httplib2": { "hashes": [ @@ -1056,16 +1049,17 @@ "sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f", "sha256:fc411e1c0a7dcd2f902c7c48cf079947a7e65b5485dea9decb82b9105ca71a43" ], + "markers": "python_full_version >= '3.8.0'", "version": "==0.6.4" }, "httpx": { "hashes": [ - "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0", - "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2" + "sha256:0858d3bab51ba7e386637f22a61d8ccddaeec5f3fe4209da3a6168dbb91573e0", + "sha256:dc0b419a0cfeb6e8b34e85167c0da2671206f5095f1baa9663d23bcfd6b535fc" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==0.27.2" + "version": "==0.28.0" }, "idna": { "hashes": [ @@ -1199,6 +1193,15 @@ "markers": "python_version >= '3.7'", "version": "==0.1.2" }, + "more-itertools": { + "hashes": [ + "sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef", + "sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==10.5.0" + }, "msgpack": { "hashes": [ "sha256:06f5fd2f6bb2a7914922d935d3b8bb4a7fff3a9a91cfce6d06c13bc42bec975b", @@ -1369,25 +1372,33 @@ }, "nh3": { "hashes": [ - "sha256:0411beb0589eacb6734f28d5497ca2ed379eafab8ad8c84b31bb5c34072b7164", - "sha256:14c5a72e9fe82aea5fe3072116ad4661af5cf8e8ff8fc5ad3450f123e4925e86", - "sha256:19aaba96e0f795bd0a6c56291495ff59364f4300d4a39b29a0abc9cb3774a84b", - "sha256:34c03fa78e328c691f982b7c03d4423bdfd7da69cd707fe572f544cf74ac23ad", - "sha256:36c95d4b70530b320b365659bb5034341316e6a9b30f0b25fa9c9eff4c27a204", - "sha256:3a157ab149e591bb638a55c8c6bcb8cdb559c8b12c13a8affaba6cedfe51713a", - "sha256:42c64511469005058cd17cc1537578eac40ae9f7200bedcfd1fc1a05f4f8c200", - "sha256:5f36b271dae35c465ef5e9090e1fdaba4a60a56f0bb0ba03e0932a66f28b9189", - "sha256:6955369e4d9f48f41e3f238a9e60f9410645db7e07435e62c6a9ea6135a4907f", - "sha256:7b7c2a3c9eb1a827d42539aa64091640bd275b81e097cd1d8d82ef91ffa2e811", - "sha256:8ce0f819d2f1933953fca255db2471ad58184a60508f03e6285e5114b6254844", - "sha256:94a166927e53972a9698af9542ace4e38b9de50c34352b962f4d9a7d4c927af4", - "sha256:a7f1b5b2c15866f2db413a3649a8fe4fd7b428ae58be2c0f6bca5eefd53ca2be", - "sha256:c8b3a1cebcba9b3669ed1a84cc65bf005728d2f0bc1ed2a6594a992e817f3a50", - "sha256:de3ceed6e661954871d6cd78b410213bdcb136f79aafe22aa7182e028b8c7307", - "sha256:f0eca9ca8628dbb4e916ae2491d72957fdd35f7a5d326b7032a345f111ac07fe" - ], - "index": "pypi", - "version": "==0.2.18" + "sha256:00810cd5275f5c3f44b9eb0e521d1a841ee2f8023622de39ffc7d88bd533d8e0", + "sha256:0b6820fc64f2ff7ef3e7253a093c946a87865c877b3889149a6d21d322ed8dbd", + "sha256:11270b16c1b012677e3e2dd166c1aa273388776bf99a3e3677179db5097ee16a", + "sha256:2b926f179eb4bce72b651bfdf76f8aa05d167b2b72bc2f3657fd319f40232adc", + "sha256:2eb021804e9df1761abeb844bb86648d77aa118a663c82f50ea04110d87ed707", + "sha256:3805161c4e12088bd74752ba69630e915bc30fe666034f47217a2f16b16efc37", + "sha256:5d4f5e2189861b352b73acb803b5f4bb409c2f36275d22717e27d4e0c217ae55", + "sha256:75c7cafb840f24430b009f7368945cb5ca88b2b54bb384ebfba495f16bc9c121", + "sha256:790056b54c068ff8dceb443eaefb696b84beff58cca6c07afd754d17692a4804", + "sha256:7e98621856b0a911c21faa5eef8f8ea3e691526c2433f9afc2be713cb6fbdb48", + "sha256:833b3b5f1783ce95834a13030300cea00cbdfd64ea29260d01af9c4821da0aa9", + "sha256:a7b928862daddb29805a1010a0282f77f4b8b238a37b5f76bc6c0d16d930fd22", + "sha256:ac536a4b5c073fdadd8f5f4889adabe1cbdae55305366fb870723c96ca7f49c3", + "sha256:b8eb7affc590e542fa7981ef508cd1644f62176bcd10d4429890fc629b47f0bc", + "sha256:c2e3f0d18cc101132fe10ab7ef5c4f41411297e639e23b64b5e888ccaad63f41", + "sha256:d0adf00e2b2026fa10a42537b60d161e516f206781c7515e4e97e09f72a8c5d0", + "sha256:d53a4577b6123ca1d7e8483fad3e13cb7eda28913d516bd0a648c1a473aa21a9", + "sha256:d8325d51e47cb5b11f649d55e626d56c76041ba508cd59e0cb1cf687cc7612f1", + "sha256:df8eac98fec80bd6f5fd0ae27a65de14f1e1a65a76d8e2237eb695f9cd1121d9", + "sha256:e3dedd7858a21312f7675841529941035a2ac91057db13402c8fe907aa19205a", + "sha256:ec9c8bf86e397cb88c560361f60fdce478b5edb8b93f04ead419b72fbe937ea6", + "sha256:ed06ed78f6b69d57463b46a04f68f270605301e69d80756a8adf7519002de57d", + "sha256:fc483dd8d20f8f8c010783a25a84db3bebeadced92d24d34b40d687f8043ac69", + "sha256:fdb20740d24ab9f2a1341458a00a11205294e97e905de060eeab1ceca020c09c" + ], + "index": "pypi", + "version": "==0.2.19" }, "opentelemetry-api": { "hashes": [ @@ -1610,107 +1621,91 @@ }, "propcache": { "hashes": [ - "sha256:00181262b17e517df2cd85656fcd6b4e70946fe62cd625b9d74ac9977b64d8d9", - "sha256:0e53cb83fdd61cbd67202735e6a6687a7b491c8742dfc39c9e01e80354956763", - "sha256:1235c01ddaa80da8235741e80815ce381c5267f96cc49b1477fdcf8c047ef325", - "sha256:140fbf08ab3588b3468932974a9331aff43c0ab8a2ec2c608b6d7d1756dbb6cb", - "sha256:191db28dc6dcd29d1a3e063c3be0b40688ed76434622c53a284e5427565bbd9b", - "sha256:1e41d67757ff4fbc8ef2af99b338bfb955010444b92929e9e55a6d4dcc3c4f09", - "sha256:1ec43d76b9677637a89d6ab86e1fef70d739217fefa208c65352ecf0282be957", - "sha256:20a617c776f520c3875cf4511e0d1db847a076d720714ae35ffe0df3e440be68", - "sha256:218db2a3c297a3768c11a34812e63b3ac1c3234c3a086def9c0fee50d35add1f", - "sha256:22aa8f2272d81d9317ff5756bb108021a056805ce63dd3630e27d042c8092798", - "sha256:25a1f88b471b3bc911d18b935ecb7115dff3a192b6fef46f0bfaf71ff4f12418", - "sha256:25c8d773a62ce0451b020c7b29a35cfbc05de8b291163a7a0f3b7904f27253e6", - "sha256:2a60ad3e2553a74168d275a0ef35e8c0a965448ffbc3b300ab3a5bb9956c2162", - "sha256:2a66df3d4992bc1d725b9aa803e8c5a66c010c65c741ad901e260ece77f58d2f", - "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036", - "sha256:2e900bad2a8456d00a113cad8c13343f3b1f327534e3589acc2219729237a2e8", - "sha256:2ee7606193fb267be4b2e3b32714f2d58cad27217638db98a60f9efb5efeccc2", - "sha256:33ac8f098df0585c0b53009f039dfd913b38c1d2edafed0cedcc0c32a05aa110", - "sha256:3444cdba6628accf384e349014084b1cacd866fbb88433cd9d279d90a54e0b23", - "sha256:363ea8cd3c5cb6679f1c2f5f1f9669587361c062e4899fce56758efa928728f8", - "sha256:375a12d7556d462dc64d70475a9ee5982465fbb3d2b364f16b86ba9135793638", - "sha256:388f3217649d6d59292b722d940d4d2e1e6a7003259eb835724092a1cca0203a", - "sha256:3947483a381259c06921612550867b37d22e1df6d6d7e8361264b6d037595f44", - "sha256:39e104da444a34830751715f45ef9fc537475ba21b7f1f5b0f4d71a3b60d7fe2", - "sha256:3c997f8c44ec9b9b0bcbf2d422cc00a1d9b9c681f56efa6ca149a941e5560da2", - "sha256:3dfafb44f7bb35c0c06eda6b2ab4bfd58f02729e7c4045e179f9a861b07c9850", - "sha256:3ebbcf2a07621f29638799828b8d8668c421bfb94c6cb04269130d8de4fb7136", - "sha256:3f88a4095e913f98988f5b338c1d4d5d07dbb0b6bad19892fd447484e483ba6b", - "sha256:439e76255daa0f8151d3cb325f6dd4a3e93043e6403e6491813bcaaaa8733887", - "sha256:4569158070180c3855e9c0791c56be3ceeb192defa2cdf6a3f39e54319e56b89", - "sha256:466c219deee4536fbc83c08d09115249db301550625c7fef1c5563a584c9bc87", - "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348", - "sha256:4c7dde9e533c0a49d802b4f3f218fa9ad0a1ce21f2c2eb80d5216565202acab4", - "sha256:53d1bd3f979ed529f0805dd35ddaca330f80a9a6d90bc0121d2ff398f8ed8861", - "sha256:55346705687dbd7ef0d77883ab4f6fabc48232f587925bdaf95219bae072491e", - "sha256:56295eb1e5f3aecd516d91b00cfd8bf3a13991de5a479df9e27dd569ea23959c", - "sha256:56bb5c98f058a41bb58eead194b4db8c05b088c93d94d5161728515bd52b052b", - "sha256:5a5b3bb545ead161be780ee85a2b54fdf7092815995661947812dde94a40f6fb", - "sha256:5f2564ec89058ee7c7989a7b719115bdfe2a2fb8e7a4543b8d1c0cc4cf6478c1", - "sha256:608cce1da6f2672a56b24a015b42db4ac612ee709f3d29f27a00c943d9e851de", - "sha256:63f13bf09cc3336eb04a837490b8f332e0db41da66995c9fd1ba04552e516354", - "sha256:662dd62358bdeaca0aee5761de8727cfd6861432e3bb828dc2a693aa0471a563", - "sha256:676135dcf3262c9c5081cc8f19ad55c8a64e3f7282a21266d05544450bffc3a5", - "sha256:67aeb72e0f482709991aa91345a831d0b707d16b0257e8ef88a2ad246a7280bf", - "sha256:67b69535c870670c9f9b14a75d28baa32221d06f6b6fa6f77a0a13c5a7b0a5b9", - "sha256:682a7c79a2fbf40f5dbb1eb6bfe2cd865376deeac65acf9beb607505dced9e12", - "sha256:6994984550eaf25dd7fc7bd1b700ff45c894149341725bb4edc67f0ffa94efa4", - "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5", - "sha256:6e2e54267980349b723cff366d1e29b138b9a60fa376664a157a342689553f71", - "sha256:73e4b40ea0eda421b115248d7e79b59214411109a5bc47d0d48e4c73e3b8fcf9", - "sha256:74acd6e291f885678631b7ebc85d2d4aec458dd849b8c841b57ef04047833bed", - "sha256:7665f04d0c7f26ff8bb534e1c65068409bf4687aa2534faf7104d7182debb336", - "sha256:7735e82e3498c27bcb2d17cb65d62c14f1100b71723b68362872bca7d0913d90", - "sha256:77a86c261679ea5f3896ec060be9dc8e365788248cc1e049632a1be682442063", - "sha256:7cf18abf9764746b9c8704774d8b06714bcb0a63641518a3a89c7f85cc02c2ad", - "sha256:83928404adf8fb3d26793665633ea79b7361efa0287dfbd372a7e74311d51ee6", - "sha256:8e40876731f99b6f3c897b66b803c9e1c07a989b366c6b5b475fafd1f7ba3fb8", - "sha256:8f188cfcc64fb1266f4684206c9de0e80f54622c3f22a910cbd200478aeae61e", - "sha256:91997d9cb4a325b60d4e3f20967f8eb08dfcb32b22554d5ef78e6fd1dda743a2", - "sha256:91ee8fc02ca52e24bcb77b234f22afc03288e1dafbb1f88fe24db308910c4ac7", - "sha256:92fe151145a990c22cbccf9ae15cae8ae9eddabfc949a219c9f667877e40853d", - "sha256:945db8ee295d3af9dbdbb698cce9bbc5c59b5c3fe328bbc4387f59a8a35f998d", - "sha256:9517d5e9e0731957468c29dbfd0f976736a0e55afaea843726e887f36fe017df", - "sha256:952e0d9d07609d9c5be361f33b0d6d650cd2bae393aabb11d9b719364521984b", - "sha256:97a58a28bcf63284e8b4d7b460cbee1edaab24634e82059c7b8c09e65284f178", - "sha256:97e48e8875e6c13909c800fa344cd54cc4b2b0db1d5f911f840458a500fde2c2", - "sha256:9e0f07b42d2a50c7dd2d8675d50f7343d998c64008f1da5fef888396b7f84630", - "sha256:a3dc1a4b165283bd865e8f8cb5f0c64c05001e0718ed06250d8cac9bec115b48", - "sha256:a3ebe9a75be7ab0b7da2464a77bb27febcb4fab46a34f9288f39d74833db7f61", - "sha256:a64e32f8bd94c105cc27f42d3b658902b5bcc947ece3c8fe7bc1b05982f60e89", - "sha256:a6ed8db0a556343d566a5c124ee483ae113acc9a557a807d439bcecc44e7dfbb", - "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3", - "sha256:b33d7a286c0dc1a15f5fc864cc48ae92a846df287ceac2dd499926c3801054a6", - "sha256:bc092ba439d91df90aea38168e11f75c655880c12782facf5cf9c00f3d42b562", - "sha256:c436130cc779806bdf5d5fae0d848713105472b8566b75ff70048c47d3961c5b", - "sha256:c5869b8fd70b81835a6f187c5fdbe67917a04d7e52b6e7cc4e5fe39d55c39d58", - "sha256:c5ecca8f9bab618340c8e848d340baf68bcd8ad90a8ecd7a4524a81c1764b3db", - "sha256:cfac69017ef97db2438efb854edf24f5a29fd09a536ff3a992b75990720cdc99", - "sha256:d2f0d0f976985f85dfb5f3d685697ef769faa6b71993b46b295cdbbd6be8cc37", - "sha256:d5bed7f9805cc29c780f3aee05de3262ee7ce1f47083cfe9f77471e9d6777e83", - "sha256:d6a21ef516d36909931a2967621eecb256018aeb11fc48656e3257e73e2e247a", - "sha256:d9b6ddac6408194e934002a69bcaadbc88c10b5f38fb9307779d1c629181815d", - "sha256:db47514ffdbd91ccdc7e6f8407aac4ee94cc871b15b577c1c324236b013ddd04", - "sha256:df81779732feb9d01e5d513fad0122efb3d53bbc75f61b2a4f29a020bc985e70", - "sha256:e4a91d44379f45f5e540971d41e4626dacd7f01004826a18cb048e7da7e96544", - "sha256:e63e3e1e0271f374ed489ff5ee73d4b6e7c60710e1f76af5f0e1a6117cd26394", - "sha256:e70fac33e8b4ac63dfc4c956fd7d85a0b1139adcfc0d964ce288b7c527537fea", - "sha256:ecddc221a077a8132cf7c747d5352a15ed763b674c0448d811f408bf803d9ad7", - "sha256:f45eec587dafd4b2d41ac189c2156461ebd0c1082d2fe7013571598abb8505d1", - "sha256:f52a68c21363c45297aca15561812d542f8fc683c85201df0bebe209e349f793", - "sha256:f571aea50ba5623c308aa146eb650eebf7dbe0fd8c5d946e28343cb3b5aad577", - "sha256:f60f0ac7005b9f5a6091009b09a419ace1610e163fa5deaba5ce3484341840e7", - "sha256:f6475a1b2ecb310c98c28d271a30df74f9dd436ee46d09236a6b750a7599ce57", - "sha256:f6d5749fdd33d90e34c2efb174c7e236829147a2713334d708746e94c4bde40d", - "sha256:f902804113e032e2cdf8c71015651c97af6418363bea8d78dc0911d56c335032", - "sha256:fa1076244f54bb76e65e22cb6910365779d5c3d71d1f18b275f1dfc7b0d71b4d", - "sha256:fc2db02409338bf36590aa985a461b2c96fce91f8e7e0f14c50c5fcc4f229016", - "sha256:ffcad6c564fe6b9b8916c1aefbb37a362deebf9394bd2974e9d84232e3e08504" + "sha256:03ff9d3f665769b2a85e6157ac8b439644f2d7fd17615a82fa55739bc97863f4", + "sha256:049324ee97bb67285b49632132db351b41e77833678432be52bdd0289c0e05e4", + "sha256:081a430aa8d5e8876c6909b67bd2d937bfd531b0382d3fdedb82612c618bc41a", + "sha256:0f022d381747f0dfe27e99d928e31bc51a18b65bb9e481ae0af1380a6725dd1f", + "sha256:12d1083f001ace206fe34b6bdc2cb94be66d57a850866f0b908972f90996b3e9", + "sha256:14d86fe14b7e04fa306e0c43cdbeebe6b2c2156a0c9ce56b815faacc193e320d", + "sha256:160291c60081f23ee43d44b08a7e5fb76681221a8e10b3139618c5a9a291b84e", + "sha256:1672137af7c46662a1c2be1e8dc78cb6d224319aaa40271c9257d886be4363a6", + "sha256:19a0f89a7bb9d8048d9c4370c9c543c396e894c76be5525f5e1ad287f1750ddf", + "sha256:1ac2f5fe02fa75f56e1ad473f1175e11f475606ec9bd0be2e78e4734ad575034", + "sha256:1cd9a1d071158de1cc1c71a26014dcdfa7dd3d5f4f88c298c7f90ad6f27bb46d", + "sha256:1ffc3cca89bb438fb9c95c13fc874012f7b9466b89328c3c8b1aa93cdcfadd16", + "sha256:297878dc9d0a334358f9b608b56d02e72899f3b8499fc6044133f0d319e2ec30", + "sha256:2d3af2e79991102678f53e0dbf4c35de99b6b8b58f29a27ca0325816364caaba", + "sha256:30b43e74f1359353341a7adb783c8f1b1c676367b011709f466f42fda2045e95", + "sha256:3156628250f46a0895f1f36e1d4fbe062a1af8718ec3ebeb746f1d23f0c5dc4d", + "sha256:31f5af773530fd3c658b32b6bdc2d0838543de70eb9a2156c03e410f7b0d3aae", + "sha256:3935bfa5fede35fb202c4b569bb9c042f337ca4ff7bd540a0aa5e37131659348", + "sha256:39d51fbe4285d5db5d92a929e3e21536ea3dd43732c5b177c7ef03f918dff9f2", + "sha256:3f77ce728b19cb537714499928fe800c3dda29e8d9428778fc7c186da4c09a64", + "sha256:4160d9283bd382fa6c0c2b5e017acc95bc183570cd70968b9202ad6d8fc48dce", + "sha256:4a571d97dbe66ef38e472703067021b1467025ec85707d57e78711c085984e54", + "sha256:4e6281aedfca15301c41f74d7005e6e3f4ca143584ba696ac69df4f02f40d629", + "sha256:52277518d6aae65536e9cea52d4e7fd2f7a66f4aa2d30ed3f2fcea620ace3c54", + "sha256:556fc6c10989f19a179e4321e5d678db8eb2924131e64652a51fe83e4c3db0e1", + "sha256:574faa3b79e8ebac7cb1d7930f51184ba1ccf69adfdec53a12f319a06030a68b", + "sha256:58791550b27d5488b1bb52bc96328456095d96206a250d28d874fafe11b3dfaf", + "sha256:5b750a8e5a1262434fb1517ddf64b5de58327f1adc3524a5e44c2ca43305eb0b", + "sha256:5d97151bc92d2b2578ff7ce779cdb9174337390a535953cbb9452fb65164c587", + "sha256:5eee736daafa7af6d0a2dc15cc75e05c64f37fc37bafef2e00d77c14171c2097", + "sha256:6445804cf4ec763dc70de65a3b0d9954e868609e83850a47ca4f0cb64bd79fea", + "sha256:647894f5ae99c4cf6bb82a1bb3a796f6e06af3caa3d32e26d2350d0e3e3faf24", + "sha256:66d4cfda1d8ed687daa4bc0274fcfd5267873db9a5bc0418c2da19273040eeb7", + "sha256:6a9a8c34fb7bb609419a211e59da8887eeca40d300b5ea8e56af98f6fbbb1541", + "sha256:6b3f39a85d671436ee3d12c017f8fdea38509e4f25b28eb25877293c98c243f6", + "sha256:6b6fb63ae352e13748289f04f37868099e69dba4c2b3e271c46061e82c745634", + "sha256:70693319e0b8fd35dd863e3e29513875eb15c51945bf32519ef52927ca883bc3", + "sha256:781e65134efaf88feb447e8c97a51772aa75e48b794352f94cb7ea717dedda0d", + "sha256:819ce3b883b7576ca28da3861c7e1a88afd08cc8c96908e08a3f4dd64a228034", + "sha256:857112b22acd417c40fa4595db2fe28ab900c8c5fe4670c7989b1c0230955465", + "sha256:887d9b0a65404929641a9fabb6452b07fe4572b269d901d622d8a34a4e9043b2", + "sha256:8b3489ff1ed1e8315674d0775dc7d2195fb13ca17b3808721b54dbe9fd020faf", + "sha256:92fc4500fcb33899b05ba73276dfb684a20d31caa567b7cb5252d48f896a91b1", + "sha256:9403db39be1393618dd80c746cb22ccda168efce239c73af13c3763ef56ffc04", + "sha256:98110aa363f1bb4c073e8dcfaefd3a5cea0f0834c2aab23dda657e4dab2f53b5", + "sha256:999779addc413181912e984b942fbcc951be1f5b3663cd80b2687758f434c583", + "sha256:9caac6b54914bdf41bcc91e7eb9147d331d29235a7c967c150ef5df6464fd1bb", + "sha256:a7a078f5d37bee6690959c813977da5291b24286e7b962e62a94cec31aa5188b", + "sha256:a7e65eb5c003a303b94aa2c3852ef130230ec79e349632d030e9571b87c4698c", + "sha256:a96dc1fa45bd8c407a0af03b2d5218392729e1822b0c32e62c5bf7eeb5fb3958", + "sha256:aca405706e0b0a44cc6bfd41fbe89919a6a56999157f6de7e182a990c36e37bc", + "sha256:accb6150ce61c9c4b7738d45550806aa2b71c7668c6942f17b0ac182b6142fd4", + "sha256:ad1af54a62ffe39cf34db1aa6ed1a1873bd548f6401db39d8e7cd060b9211f82", + "sha256:ae1aa1cd222c6d205853b3013c69cd04515f9d6ab6de4b0603e2e1c33221303e", + "sha256:b2d0a12018b04f4cb820781ec0dffb5f7c7c1d2a5cd22bff7fb055a2cb19ebce", + "sha256:b480c6a4e1138e1aa137c0079b9b6305ec6dcc1098a8ca5196283e8a49df95a9", + "sha256:b74c261802d3d2b85c9df2dfb2fa81b6f90deeef63c2db9f0e029a3cac50b518", + "sha256:ba278acf14471d36316159c94a802933d10b6a1e117b8554fe0d0d9b75c9d536", + "sha256:bb6178c241278d5fe853b3de743087be7f5f4c6f7d6d22a3b524d323eecec505", + "sha256:bf72af5e0fb40e9babf594308911436c8efde3cb5e75b6f206c34ad18be5c052", + "sha256:bfd3223c15bebe26518d58ccf9a39b93948d3dcb3e57a20480dfdd315356baff", + "sha256:c214999039d4f2a5b2073ac506bba279945233da8c786e490d411dfc30f855c1", + "sha256:c2f992c07c0fca81655066705beae35fc95a2fa7366467366db627d9f2ee097f", + "sha256:cba4cfa1052819d16699e1d55d18c92b6e094d4517c41dd231a8b9f87b6fa681", + "sha256:cea7daf9fc7ae6687cf1e2c049752f19f146fdc37c2cc376e7d0032cf4f25347", + "sha256:cf6c4150f8c0e32d241436526f3c3f9cbd34429492abddbada2ffcff506c51af", + "sha256:d09c333d36c1409d56a9d29b3a1b800a42c76a57a5a8907eacdbce3f18768246", + "sha256:d27b84d5880f6d8aa9ae3edb253c59d9f6642ffbb2c889b78b60361eed449787", + "sha256:d2ccec9ac47cf4e04897619c0e0c1a48c54a71bdf045117d3a26f80d38ab1fb0", + "sha256:d71264a80f3fcf512eb4f18f59423fe82d6e346ee97b90625f283df56aee103f", + "sha256:d93f3307ad32a27bda2e88ec81134b823c240aa3abb55821a8da553eed8d9439", + "sha256:d9631c5e8b5b3a0fda99cb0d29c18133bca1e18aea9effe55adb3da1adef80d3", + "sha256:ddfab44e4489bd79bda09d84c430677fc7f0a4939a73d2bba3073036f487a0a6", + "sha256:e7048abd75fe40712005bcfc06bb44b9dfcd8e101dda2ecf2f5aa46115ad07ca", + "sha256:e73091191e4280403bde6c9a52a6999d69cdfde498f1fdf629105247599b57ec", + "sha256:e800776a79a5aabdb17dcc2346a7d66d0777e942e4cd251defeb084762ecd17d", + "sha256:edc9fc7051e3350643ad929df55c451899bb9ae6d24998a949d2e4c87fb596d3", + "sha256:f089118d584e859c62b3da0892b88a83d611c2033ac410e929cb6754eec0ed16", + "sha256:f174bbd484294ed9fdf09437f889f95807e5f229d5d93588d34e92106fbf6717", + "sha256:f508b0491767bb1f2b87fdfacaba5f7eddc2f867740ec69ece6d1946d29029a6", + "sha256:f7a31fc1e1bd362874863fdeed71aed92d348f5336fd84f2197ba40c59f061bd", + "sha256:f9479aa06a793c5aeba49ce5c5692ffb51fcd9a7016e017d555d5e2b0045d212" ], - "markers": "python_version >= '3.8'", - "version": "==0.2.0" + "markers": "python_version >= '3.9'", + "version": "==0.2.1" }, "proto-plus": { "hashes": [ @@ -1834,12 +1829,12 @@ "crypto" ], "hashes": [ - "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850", - "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c" + "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", + "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb" ], "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==2.9.0" + "markers": "python_version >= '3.9'", + "version": "==2.10.1" }, "pymongo": { "hashes": [ @@ -1937,16 +1932,17 @@ "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a" ], + "markers": "python_version >= '3.8'", "version": "==1.0.1" }, "python-multipart": { "hashes": [ - "sha256:045e1f98d719c1ce085ed7f7e1ef9d8ccc8c02ba02b5566d5f7521410ced58cb", - "sha256:43dcf96cf65888a9cd3423544dd0d75ac10f7aa0c3c28a175bbcd00c9ce1aebf" + "sha256:905502ef39050557b7a6af411f454bc19526529ca46ae6831508438890ce12cc", + "sha256:f8d5b0b9c618575bf9df01c684ded1d94a338839bdd8223838afacfb4bb2082d" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==0.0.12" + "version": "==0.0.19" }, "pytz": { "hashes": [ @@ -2011,16 +2007,17 @@ "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" ], + "markers": "python_version >= '3.8'", "version": "==6.0.2" }, "redis": { "hashes": [ - "sha256:f6c997521fedbae53387307c5d0bf784d9acc28d9f1d058abeac566ec4dbed72", - "sha256:f8ea06b7482a668c6475ae202ed8d9bcaa409f6e87fb77ed1043d912afd62e24" + "sha256:0b1087665a771b1ff2e003aa5bdd354f15a70c9e25d5a7dbf9c722c16528a7b0", + "sha256:ae174f2bb3b1bf2b09d54bf3e51fbc1469cf6c10aa03e21141f51969801a7897" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==5.1.1" + "version": "==5.2.0" }, "requests": { "hashes": [ @@ -2032,11 +2029,11 @@ }, "rich": { "hashes": [ - "sha256:9836f5096eb2172c9e77df411c1b009bace4193d6a481d534fea75ebba758283", - "sha256:bc1e01b899537598cf02579d2b9f4a415104d3fc439313a7a2c165d76557a08e" + "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", + "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90" ], "markers": "python_full_version >= '3.8.0'", - "version": "==13.9.3" + "version": "==13.9.4" }, "rsa": { "hashes": [ @@ -2056,12 +2053,12 @@ }, "sentry-sdk": { "hashes": [ - "sha256:625955884b862cc58748920f9e21efdfb8e0d4f98cca4ab0d3918576d5b606ad", - "sha256:dd0a05352b78ffeacced73a94e86f38b32e2eae15fff5f30ca5abb568a72eacf" + "sha256:7b0b3b709dee051337244a09a30dbf6e95afe0d34a1f8b430d45e0982a7c125b", + "sha256:ee4a4d2ae8bfe3cac012dcf3e4607975904c137e1738116549fc3dbbb6ff0e36" ], "index": "pypi", "markers": "python_version >= '3.6'", - "version": "==2.17.0" + "version": "==2.19.0" }, "setuptools": { "hashes": [ @@ -2159,11 +2156,11 @@ }, "starlette": { "hashes": [ - "sha256:39cbd8768b107d68bfe1ff1672b38a2c38b49777de46d2a592841d58e3bf7c2a", - "sha256:a0193a3c413ebc9c78bff1c3546a45bb8c8bcb4a84cae8747d650a65bd37210a" + "sha256:9834fd799d1a87fd346deb76158668cfa0b0d56f85caefe8268e2d97c3468b62", + "sha256:fbc189474b4731cf30fcef52f18a8d070e3f3b46c6a04c97579e85e6ffca942d" ], "markers": "python_version >= '3.8'", - "version": "==0.41.0" + "version": "==0.41.2" }, "taskiq": { "extras": [ @@ -2295,6 +2292,7 @@ "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816", "sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2" ], + "markers": "python_full_version >= '3.8.0'", "version": "==0.21.0" }, "watchdog": { @@ -2332,182 +2330,155 @@ }, "watchfiles": { "hashes": [ - "sha256:01550ccf1d0aed6ea375ef259706af76ad009ef5b0203a3a4cce0f6024f9b68a", - "sha256:01def80eb62bd5db99a798d5e1f5f940ca0a05986dcfae21d833af7a46f7ee22", - "sha256:07cdef0c84c03375f4e24642ef8d8178e533596b229d32d2bbd69e5128ede02a", - "sha256:083dc77dbdeef09fa44bb0f4d1df571d2e12d8a8f985dccde71ac3ac9ac067a0", - "sha256:1cf1f6dd7825053f3d98f6d33f6464ebdd9ee95acd74ba2c34e183086900a827", - "sha256:21ab23fdc1208086d99ad3f69c231ba265628014d4aed31d4e8746bd59e88cd1", - "sha256:2dadf8a8014fde6addfd3c379e6ed1a981c8f0a48292d662e27cabfe4239c83c", - "sha256:2e28d91ef48eab0afb939fa446d8ebe77e2f7593f5f463fd2bb2b14132f95b6e", - "sha256:2efec17819b0046dde35d13fb8ac7a3ad877af41ae4640f4109d9154ed30a188", - "sha256:30bbd525c3262fd9f4b1865cb8d88e21161366561cd7c9e1194819e0a33ea86b", - "sha256:316449aefacf40147a9efaf3bd7c9bdd35aaba9ac5d708bd1eb5763c9a02bef5", - "sha256:327763da824817b38ad125dcd97595f942d720d32d879f6c4ddf843e3da3fe90", - "sha256:32aa53a9a63b7f01ed32e316e354e81e9da0e6267435c7243bf8ae0f10b428ef", - "sha256:34e19e56d68b0dad5cff62273107cf5d9fbaf9d75c46277aa5d803b3ef8a9e9b", - "sha256:3770e260b18e7f4e576edca4c0a639f704088602e0bc921c5c2e721e3acb8d15", - "sha256:3d2e3ab79a1771c530233cadfd277fcc762656d50836c77abb2e5e72b88e3a48", - "sha256:41face41f036fee09eba33a5b53a73e9a43d5cb2c53dad8e61fa6c9f91b5a51e", - "sha256:43e3e37c15a8b6fe00c1bce2473cfa8eb3484bbeecf3aefbf259227e487a03df", - "sha256:449f43f49c8ddca87c6b3980c9284cab6bd1f5c9d9a2b00012adaaccd5e7decd", - "sha256:4933a508d2f78099162da473841c652ad0de892719043d3f07cc83b33dfd9d91", - "sha256:49d617df841a63b4445790a254013aea2120357ccacbed00253f9c2b5dc24e2d", - "sha256:49fb58bcaa343fedc6a9e91f90195b20ccb3135447dc9e4e2570c3a39565853e", - "sha256:4a7fa2bc0efef3e209a8199fd111b8969fe9db9c711acc46636686331eda7dd4", - "sha256:4abf4ad269856618f82dee296ac66b0cd1d71450fc3c98532d93798e73399b7a", - "sha256:4b8693502d1967b00f2fb82fc1e744df128ba22f530e15b763c8d82baee15370", - "sha256:4d28cea3c976499475f5b7a2fec6b3a36208656963c1a856d328aeae056fc5c1", - "sha256:5148c2f1ea043db13ce9b0c28456e18ecc8f14f41325aa624314095b6aa2e9ea", - "sha256:54ca90a9ae6597ae6dc00e7ed0a040ef723f84ec517d3e7ce13e63e4bc82fa04", - "sha256:551ec3ee2a3ac9cbcf48a4ec76e42c2ef938a7e905a35b42a1267fa4b1645896", - "sha256:5c51749f3e4e269231510da426ce4a44beb98db2dce9097225c338f815b05d4f", - "sha256:632676574429bee8c26be8af52af20e0c718cc7f5f67f3fb658c71928ccd4f7f", - "sha256:6509ed3f467b79d95fc62a98229f79b1a60d1b93f101e1c61d10c95a46a84f43", - "sha256:6bdcfa3cd6fdbdd1a068a52820f46a815401cbc2cb187dd006cb076675e7b735", - "sha256:7138eff8baa883aeaa074359daabb8b6c1e73ffe69d5accdc907d62e50b1c0da", - "sha256:7211b463695d1e995ca3feb38b69227e46dbd03947172585ecb0588f19b0d87a", - "sha256:73bde715f940bea845a95247ea3e5eb17769ba1010efdc938ffcb967c634fa61", - "sha256:78470906a6be5199524641f538bd2c56bb809cd4bf29a566a75051610bc982c3", - "sha256:7ae3e208b31be8ce7f4c2c0034f33406dd24fbce3467f77223d10cd86778471c", - "sha256:7e4bd963a935aaf40b625c2499f3f4f6bbd0c3776f6d3bc7c853d04824ff1c9f", - "sha256:82ae557a8c037c42a6ef26c494d0631cacca040934b101d001100ed93d43f361", - "sha256:82b2509f08761f29a0fdad35f7e1638b8ab1adfa2666d41b794090361fb8b855", - "sha256:8360f7314a070c30e4c976b183d1d8d1585a4a50c5cb603f431cebcbb4f66327", - "sha256:85d5f0c7771dcc7a26c7a27145059b6bb0ce06e4e751ed76cdf123d7039b60b5", - "sha256:88bcd4d0fe1d8ff43675360a72def210ebad3f3f72cabfeac08d825d2639b4ab", - "sha256:9301c689051a4857d5b10777da23fafb8e8e921bcf3abe6448a058d27fb67633", - "sha256:951088d12d339690a92cef2ec5d3cfd957692834c72ffd570ea76a6790222777", - "sha256:95cf3b95ea665ab03f5a54765fa41abf0529dbaf372c3b83d91ad2cfa695779b", - "sha256:96619302d4374de5e2345b2b622dc481257a99431277662c30f606f3e22f42be", - "sha256:999928c6434372fde16c8f27143d3e97201160b48a614071261701615a2a156f", - "sha256:9a60e2bf9dc6afe7f743e7c9b149d1fdd6dbf35153c78fe3a14ae1a9aee3d98b", - "sha256:9f895d785eb6164678ff4bb5cc60c5996b3ee6df3edb28dcdeba86a13ea0465e", - "sha256:a2a9891723a735d3e2540651184be6fd5b96880c08ffe1a98bae5017e65b544b", - "sha256:a974231b4fdd1bb7f62064a0565a6b107d27d21d9acb50c484d2cdba515b9366", - "sha256:aa0fd7248cf533c259e59dc593a60973a73e881162b1a2f73360547132742823", - "sha256:acbfa31e315a8f14fe33e3542cbcafc55703b8f5dcbb7c1eecd30f141df50db3", - "sha256:afb72325b74fa7a428c009c1b8be4b4d7c2afedafb2982827ef2156646df2fe1", - "sha256:b3ef2c69c655db63deb96b3c3e587084612f9b1fa983df5e0c3379d41307467f", - "sha256:b52a65e4ea43c6d149c5f8ddb0bef8d4a1e779b77591a458a893eb416624a418", - "sha256:b665caeeda58625c3946ad7308fbd88a086ee51ccb706307e5b1fa91556ac886", - "sha256:b74fdffce9dfcf2dc296dec8743e5b0332d15df19ae464f0e249aa871fc1c571", - "sha256:b995bfa6bf01a9e09b884077a6d37070464b529d8682d7691c2d3b540d357a0c", - "sha256:bd82010f8ab451dabe36054a1622870166a67cf3fce894f68895db6f74bbdc94", - "sha256:bdcd5538e27f188dd3c804b4a8d5f52a7fc7f87e7fd6b374b8e36a4ca03db428", - "sha256:c79d7719d027b7a42817c5d96461a99b6a49979c143839fc37aa5748c322f234", - "sha256:cdab9555053399318b953a1fe1f586e945bc8d635ce9d05e617fd9fe3a4687d6", - "sha256:ce72dba6a20e39a0c628258b5c308779b8697f7676c254a845715e2a1039b968", - "sha256:d337193bbf3e45171c8025e291530fb7548a93c45253897cd764a6a71c937ed9", - "sha256:d3dcb774e3568477275cc76554b5a565024b8ba3a0322f77c246bc7111c5bb9c", - "sha256:d64ba08db72e5dfd5c33be1e1e687d5e4fcce09219e8aee893a4862034081d4e", - "sha256:d7a2e3b7f5703ffbd500dabdefcbc9eafeff4b9444bbdd5d83d79eedf8428fab", - "sha256:d831ee0a50946d24a53821819b2327d5751b0c938b12c0653ea5be7dea9c82ec", - "sha256:d9018153cf57fc302a2a34cb7564870b859ed9a732d16b41a9b5cb2ebed2d444", - "sha256:e5171ef898299c657685306d8e1478a45e9303ddcd8ac5fed5bd52ad4ae0b69b", - "sha256:e94e98c7cb94cfa6e071d401ea3342767f28eb5a06a58fafdc0d2a4974f4f35c", - "sha256:ec39698c45b11d9694a1b635a70946a5bad066b593af863460a8e600f0dff1ca", - "sha256:ed9aba6e01ff6f2e8285e5aa4154e2970068fe0fc0998c4380d0e6278222269b", - "sha256:edf71b01dec9f766fb285b73930f95f730bb0943500ba0566ae234b5c1618c18", - "sha256:ee82c98bed9d97cd2f53bdb035e619309a098ea53ce525833e26b93f673bc318", - "sha256:f4c96283fca3ee09fb044f02156d9570d156698bc3734252175a38f0e8975f07", - "sha256:f7d9b87c4c55e3ea8881dfcbf6d61ea6775fffed1fedffaa60bd047d3c08c430", - "sha256:f83df90191d67af5a831da3a33dd7628b02a95450e168785586ed51e6d28943c", - "sha256:fca9433a45f18b7c779d2bae7beeec4f740d28b788b117a48368d95a3233ed83", - "sha256:fd92bbaa2ecdb7864b7600dcdb6f2f1db6e0346ed425fbd01085be04c63f0b05" + "sha256:06d828fe2adc4ac8a64b875ca908b892a3603d596d43e18f7948f3fef5fc671c", + "sha256:074c7618cd6c807dc4eaa0982b4a9d3f8051cd0b72793511848fd64630174b17", + "sha256:09551237645d6bff3972592f2aa5424df9290e7a2e15d63c5f47c48cde585935", + "sha256:0fc3bf0effa2d8075b70badfdd7fb839d7aa9cea650d17886982840d71fdeabf", + "sha256:12ab123135b2f42517f04e720526d41448667ae8249e651385afb5cda31fedc0", + "sha256:13a4f9ee0cd25682679eea5c14fc629e2eaa79aab74d963bc4e21f43b8ea1877", + "sha256:1d19df28f99d6a81730658fbeb3ade8565ff687f95acb59665f11502b441be5f", + "sha256:1e176b6b4119b3f369b2b4e003d53a226295ee862c0962e3afd5a1c15680b4e3", + "sha256:1ee5edc939f53466b329bbf2e58333a5461e6c7b50c980fa6117439e2c18b42d", + "sha256:1f73c2147a453315d672c1ad907abe6d40324e34a185b51e15624bc793f93cc6", + "sha256:1ff236d7a3f4b0a42f699a22fc374ba526bc55048a70cbb299661158e1bb5e1f", + "sha256:245fab124b9faf58430da547512d91734858df13f2ddd48ecfa5e493455ffccb", + "sha256:28babb38cf2da8e170b706c4b84aa7e4528a6fa4f3ee55d7a0866456a1662041", + "sha256:28fb64b5843d94e2c2483f7b024a1280662a44409bedee8f2f51439767e2d107", + "sha256:29cf884ad4285d23453c702ed03d689f9c0e865e3c85d20846d800d4787de00f", + "sha256:2a825ba4b32c214e3855b536eb1a1f7b006511d8e64b8215aac06eb680642d84", + "sha256:2ac778a460ea22d63c7e6fb0bc0f5b16780ff0b128f7f06e57aaec63bd339285", + "sha256:2c2696611182c85eb0e755b62b456f48debff484b7306b56f05478b843ca8ece", + "sha256:2d9c0518fabf4a3f373b0a94bb9e4ea7a1df18dec45e26a4d182aa8918dee855", + "sha256:2de52b499e1ab037f1a87cb8ebcb04a819bf087b1015a4cf6dcf8af3c2a2613e", + "sha256:37566c844c9ce3b5deb964fe1a23378e575e74b114618d211fbda8f59d7b5dab", + "sha256:3d94fd83ed54266d789f287472269c0def9120a2022674990bd24ad989ebd7a0", + "sha256:48051d1c504448b2fcda71c5e6e3610ae45de6a0b8f5a43b961f250be4bdf5a8", + "sha256:487d15927f1b0bd24e7df921913399bb1ab94424c386bea8b267754d698f8f0e", + "sha256:4a3b33c3aefe9067ebd87846806cd5fc0b017ab70d628aaff077ab9abf4d06b3", + "sha256:4ff9c7e84e8b644a8f985c42bcc81457240316f900fc72769aaedec9d088055a", + "sha256:533a7cbfe700e09780bb31c06189e39c65f06c7f447326fee707fd02f9a6e945", + "sha256:53ae447f06f8f29f5ab40140f19abdab822387a7c426a369eb42184b021e97eb", + "sha256:550109001920a993a4383b57229c717fa73627d2a4e8fcb7ed33c7f1cddb0c85", + "sha256:5bbd0311588c2de7f9ea5cf3922ccacfd0ec0c1922870a2be503cc7df1ca8be7", + "sha256:5dccfc70480087567720e4e36ec381bba1ed68d7e5f368fe40c93b3b1eba0105", + "sha256:5f75cd42e7e2254117cf37ff0e68c5b3f36c14543756b2da621408349bd9ca7c", + "sha256:648e2b6db53eca6ef31245805cd528a16f56fa4cc15aeec97795eaf713c11435", + "sha256:774ef36b16b7198669ce655d4f75b4c3d370e7f1cbdfb997fb10ee98717e2058", + "sha256:8a2127cd68950787ee36753e6d401c8ea368f73beaeb8e54df5516a06d1ecd82", + "sha256:90004553be36427c3d06ec75b804233f8f816374165d5225b93abd94ba6e7234", + "sha256:905f69aad276639eff3893759a07d44ea99560e67a1cf46ff389cd62f88872a2", + "sha256:9122b8fdadc5b341315d255ab51d04893f417df4e6c1743b0aac8bf34e96e025", + "sha256:9272fdbc0e9870dac3b505bce1466d386b4d8d6d2bacf405e603108d50446940", + "sha256:936f362e7ff28311b16f0b97ec51e8f2cc451763a3264640c6ed40fb252d1ee4", + "sha256:947ccba18a38b85c366dafeac8df2f6176342d5992ca240a9d62588b214d731f", + "sha256:95dc785bc284552d044e561b8f4fe26d01ab5ca40d35852a6572d542adfeb4bc", + "sha256:95de85c254f7fe8cbdf104731f7f87f7f73ae229493bebca3722583160e6b152", + "sha256:9b4fb98100267e6a5ebaff6aaa5d20aea20240584647470be39fe4823012ac96", + "sha256:9c01446626574561756067f00b37e6b09c8622b0fc1e9fdbc7cbcea328d4e514", + "sha256:9c9a8d8fd97defe935ef8dd53d562e68942ad65067cd1c54d6ed8a088b1d931d", + "sha256:9e1d9284cc84de7855fcf83472e51d32daf6f6cecd094160192628bc3fee1b78", + "sha256:a0abf173975eb9dd17bb14c191ee79999e650997cc644562f91df06060610e62", + "sha256:a2218e78e2c6c07b1634a550095ac2a429026b2d5cbcd49a594f893f2bb8c936", + "sha256:a5a7a06cfc65e34fd0a765a7623c5ba14707a0870703888e51d3d67107589817", + "sha256:b2bca898c1dc073912d3db7fa6926cc08be9575add9e84872de2c99c688bac4e", + "sha256:b46e15c34d4e401e976d6949ad3a74d244600d5c4b88c827a3fdf18691a46359", + "sha256:b551c465a59596f3d08170bd7e1c532c7260dd90ed8135778038e13c5d48aa81", + "sha256:b555a93c15bd2c71081922be746291d776d47521a00703163e5fbe6d2a402399", + "sha256:bc338ce9f8846543d428260fa0f9a716626963148edc937d71055d01d81e1525", + "sha256:bedf84835069f51c7b026b3ca04e2e747ea8ed0a77c72006172c72d28c9f69fc", + "sha256:c3d258d78341d5d54c0c804a5b7faa66cd30ba50b2756a7161db07ce15363b8d", + "sha256:c83a6d33a9eda0af6a7470240d1af487807adc269704fe76a4972dd982d16236", + "sha256:c9a13ac46b545a7d0d50f7641eefe47d1597e7d1783a5d89e09d080e6dff44b0", + "sha256:cf517701a4a872417f4e02a136e929537743461f9ec6cdb8184d9a04f4843545", + "sha256:d2b39aa8edd9e5f56f99a2a2740a251dc58515398e9ed5a4b3e5ff2827060755", + "sha256:d3572d4c34c4e9c33d25b3da47d9570d5122f8433b9ac6519dca49c2740d23cd", + "sha256:d562a6114ddafb09c33246c6ace7effa71ca4b6a2324a47f4b09b6445ea78941", + "sha256:e1ed613ee107269f66c2df631ec0fc8efddacface85314d392a4131abe299f00", + "sha256:e3750434c83b61abb3163b49c64b04180b85b4dabb29a294513faec57f2ffdb7", + "sha256:eba98901a2eab909dbd79681190b9049acc650f6111fde1845484a4450761e98", + "sha256:f159ac795785cde4899e0afa539f4c723fb5dd336ce5605bc909d34edd00b79b", + "sha256:f8c4f3a1210ed099a99e6a710df4ff2f8069411059ffe30fa5f9467ebed1256b", + "sha256:fa13d604fcb9417ae5f2e3de676e66aa97427d888e83662ad205bed35a313176", + "sha256:fbd0ab7a9943bbddb87cbc2bf2f09317e74c77dc55b1f5657f81d04666c25269", + "sha256:ffd98a299b0a74d1b704ef0ed959efb753e656a4e0425c14e46ae4c3cbdd2919" ], - "version": "==0.24.0" + "markers": "python_version >= '3.9'", + "version": "==1.0.0" }, "websockets": { "hashes": [ - "sha256:004280a140f220c812e65f36944a9ca92d766b6cc4560be652a0a3883a79ed8a", - "sha256:035233b7531fb92a76beefcbf479504db8c72eb3bff41da55aecce3a0f729e54", - "sha256:149e622dc48c10ccc3d2760e5f36753db9cacf3ad7bc7bbbfd7d9c819e286f23", - "sha256:163e7277e1a0bd9fb3c8842a71661ad19c6aa7bb3d6678dc7f89b17fbcc4aeb7", - "sha256:18503d2c5f3943e93819238bf20df71982d193f73dcecd26c94514f417f6b135", - "sha256:1971e62d2caa443e57588e1d82d15f663b29ff9dfe7446d9964a4b6f12c1e700", - "sha256:204e5107f43095012b00f1451374693267adbb832d29966a01ecc4ce1db26faf", - "sha256:2510c09d8e8df777177ee3d40cd35450dc169a81e747455cc4197e63f7e7bfe5", - "sha256:25c35bf84bf7c7369d247f0b8cfa157f989862c49104c5cf85cb5436a641d93e", - "sha256:2f85cf4f2a1ba8f602298a853cec8526c2ca42a9a4b947ec236eaedb8f2dc80c", - "sha256:308e20f22c2c77f3f39caca508e765f8725020b84aa963474e18c59accbf4c02", - "sha256:325b1ccdbf5e5725fdcb1b0e9ad4d2545056479d0eee392c291c1bf76206435a", - "sha256:327b74e915cf13c5931334c61e1a41040e365d380f812513a255aa804b183418", - "sha256:346bee67a65f189e0e33f520f253d5147ab76ae42493804319b5716e46dddf0f", - "sha256:38377f8b0cdeee97c552d20cf1865695fcd56aba155ad1b4ca8779a5b6ef4ac3", - "sha256:3c78383585f47ccb0fcf186dcb8a43f5438bd7d8f47d69e0b56f71bf431a0a68", - "sha256:4059f790b6ae8768471cddb65d3c4fe4792b0ab48e154c9f0a04cefaabcd5978", - "sha256:459bf774c754c35dbb487360b12c5727adab887f1622b8aed5755880a21c4a20", - "sha256:463e1c6ec853202dd3657f156123d6b4dad0c546ea2e2e38be2b3f7c5b8e7295", - "sha256:4676df3fe46956fbb0437d8800cd5f2b6d41143b6e7e842e60554398432cf29b", - "sha256:485307243237328c022bc908b90e4457d0daa8b5cf4b3723fd3c4a8012fce4c6", - "sha256:48a2ef1381632a2f0cb4efeff34efa97901c9fbc118e01951ad7cfc10601a9bb", - "sha256:4b889dbd1342820cc210ba44307cf75ae5f2f96226c0038094455a96e64fb07a", - "sha256:586a356928692c1fed0eca68b4d1c2cbbd1ca2acf2ac7e7ebd3b9052582deefa", - "sha256:58cf7e75dbf7e566088b07e36ea2e3e2bd5676e22216e4cad108d4df4a7402a0", - "sha256:5993260f483d05a9737073be197371940c01b257cc45ae3f1d5d7adb371b266a", - "sha256:5dd6da9bec02735931fccec99d97c29f47cc61f644264eb995ad6c0c27667238", - "sha256:5f2e75431f8dc4a47f31565a6e1355fb4f2ecaa99d6b89737527ea917066e26c", - "sha256:5f9fee94ebafbc3117c30be1844ed01a3b177bb6e39088bc6b2fa1dc15572084", - "sha256:61fc0dfcda609cda0fc9fe7977694c0c59cf9d749fbb17f4e9483929e3c48a19", - "sha256:624459daabeb310d3815b276c1adef475b3e6804abaf2d9d2c061c319f7f187d", - "sha256:62d516c325e6540e8a57b94abefc3459d7dab8ce52ac75c96cad5549e187e3a7", - "sha256:6548f29b0e401eea2b967b2fdc1c7c7b5ebb3eeb470ed23a54cd45ef078a0db9", - "sha256:6d2aad13a200e5934f5a6767492fb07151e1de1d6079c003ab31e1823733ae79", - "sha256:6d6855bbe70119872c05107e38fbc7f96b1d8cb047d95c2c50869a46c65a8e96", - "sha256:70c5be9f416aa72aab7a2a76c90ae0a4fe2755c1816c153c1a2bcc3333ce4ce6", - "sha256:730f42125ccb14602f455155084f978bd9e8e57e89b569b4d7f0f0c17a448ffe", - "sha256:7a43cfdcddd07f4ca2b1afb459824dd3c6d53a51410636a2c7fc97b9a8cf4842", - "sha256:7bd6abf1e070a6b72bfeb71049d6ad286852e285f146682bf30d0296f5fbadfa", - "sha256:7c1e90228c2f5cdde263253fa5db63e6653f1c00e7ec64108065a0b9713fa1b3", - "sha256:7c65ffa900e7cc958cd088b9a9157a8141c991f8c53d11087e6fb7277a03f81d", - "sha256:80c421e07973a89fbdd93e6f2003c17d20b69010458d3a8e37fb47874bd67d51", - "sha256:82d0ba76371769d6a4e56f7e83bb8e81846d17a6190971e38b5de108bde9b0d7", - "sha256:83f91d8a9bb404b8c2c41a707ac7f7f75b9442a0a876df295de27251a856ad09", - "sha256:87c6e35319b46b99e168eb98472d6c7d8634ee37750d7693656dc766395df096", - "sha256:8d23b88b9388ed85c6faf0e74d8dec4f4d3baf3ecf20a65a47b836d56260d4b9", - "sha256:9156c45750b37337f7b0b00e6248991a047be4aa44554c9886fe6bdd605aab3b", - "sha256:91a0fa841646320ec0d3accdff5b757b06e2e5c86ba32af2e0815c96c7a603c5", - "sha256:95858ca14a9f6fa8413d29e0a585b31b278388aa775b8a81fa24830123874678", - "sha256:95df24ca1e1bd93bbca51d94dd049a984609687cb2fb08a7f2c56ac84e9816ea", - "sha256:9b37c184f8b976f0c0a231a5f3d6efe10807d41ccbe4488df8c74174805eea7d", - "sha256:9b6f347deb3dcfbfde1c20baa21c2ac0751afaa73e64e5b693bb2b848efeaa49", - "sha256:9d75baf00138f80b48f1eac72ad1535aac0b6461265a0bcad391fc5aba875cfc", - "sha256:9ef8aa8bdbac47f4968a5d66462a2a0935d044bf35c0e5a8af152d58516dbeb5", - "sha256:a11e38ad8922c7961447f35c7b17bffa15de4d17c70abd07bfbe12d6faa3e027", - "sha256:a1b54689e38d1279a51d11e3467dd2f3a50f5f2e879012ce8f2d6943f00e83f0", - "sha256:a3b3366087c1bc0a2795111edcadddb8b3b59509d5db5d7ea3fdd69f954a8878", - "sha256:a569eb1b05d72f9bce2ebd28a1ce2054311b66677fcd46cf36204ad23acead8c", - "sha256:a7affedeb43a70351bb811dadf49493c9cfd1ed94c9c70095fd177e9cc1541fa", - "sha256:a9a396a6ad26130cdae92ae10c36af09d9bfe6cafe69670fd3b6da9b07b4044f", - "sha256:a9ab1e71d3d2e54a0aa646ab6d4eebfaa5f416fe78dfe4da2839525dc5d765c6", - "sha256:a9cd1af7e18e5221d2878378fbc287a14cd527fdd5939ed56a18df8a31136bb2", - "sha256:a9dcaf8b0cc72a392760bb8755922c03e17a5a54e08cca58e8b74f6902b433cf", - "sha256:b9d7439d7fab4dce00570bb906875734df13d9faa4b48e261c440a5fec6d9708", - "sha256:bcc03c8b72267e97b49149e4863d57c2d77f13fae12066622dc78fe322490fe6", - "sha256:c11d4d16e133f6df8916cc5b7e3e96ee4c44c936717d684a94f48f82edb7c92f", - "sha256:c1dca61c6db1166c48b95198c0b7d9c990b30c756fc2923cc66f68d17dc558fd", - "sha256:c518e84bb59c2baae725accd355c8dc517b4a3ed8db88b4bc93c78dae2974bf2", - "sha256:c7934fd0e920e70468e676fe7f1b7261c1efa0d6c037c6722278ca0228ad9d0d", - "sha256:c7e72ce6bda6fb9409cc1e8164dd41d7c91466fb599eb047cfda72fe758a34a7", - "sha256:c90d6dec6be2c7d03378a574de87af9b1efea77d0c52a8301dd831ece938452f", - "sha256:ceec59f59d092c5007e815def4ebb80c2de330e9588e101cf8bd94c143ec78a5", - "sha256:cf1781ef73c073e6b0f90af841aaf98501f975d306bbf6221683dd594ccc52b6", - "sha256:d04f13a1d75cb2b8382bdc16ae6fa58c97337253826dfe136195b7f89f661557", - "sha256:d6d300f8ec35c24025ceb9b9019ae9040c1ab2f01cddc2bcc0b518af31c75c14", - "sha256:d8dbb1bf0c0a4ae8b40bdc9be7f644e2f3fb4e8a9aca7145bfa510d4a374eeb7", - "sha256:de58647e3f9c42f13f90ac7e5f58900c80a39019848c5547bc691693098ae1bd", - "sha256:deeb929efe52bed518f6eb2ddc00cc496366a14c726005726ad62c2dd9017a3c", - "sha256:df01aea34b6e9e33572c35cd16bae5a47785e7d5c8cb2b54b2acdb9678315a17", - "sha256:e2620453c075abeb0daa949a292e19f56de518988e079c36478bacf9546ced23", - "sha256:e4450fc83a3df53dec45922b576e91e94f5578d06436871dce3a6be38e40f5db", - "sha256:e54affdeb21026329fb0744ad187cf812f7d3c2aa702a5edb562b325191fcab6", - "sha256:e9875a0143f07d74dc5e1ded1c4581f0d9f7ab86c78994e2ed9e95050073c94d", - "sha256:f1c3cf67185543730888b20682fb186fc8d0fa6f07ccc3ef4390831ab4b388d9", - "sha256:f48c749857f8fb598fb890a75f540e3221d0976ed0bf879cf3c7eef34151acee", - "sha256:f779498eeec470295a2b1a5d97aa1bc9814ecd25e1eb637bd9d1c73a327387f6" - ], - "version": "==13.1" + "sha256:00fe5da3f037041da1ee0cf8e308374e236883f9842c7c465aa65098b1c9af59", + "sha256:01bb2d4f0a6d04538d3c5dfd27c0643269656c28045a53439cbf1c004f90897a", + "sha256:034feb9f4286476f273b9a245fb15f02c34d9586a5bc936aff108c3ba1b21beb", + "sha256:04a97aca96ca2acedf0d1f332c861c5a4486fdcba7bcef35873820f940c4231e", + "sha256:0d4290d559d68288da9f444089fd82490c8d2744309113fc26e2da6e48b65da6", + "sha256:1288369a6a84e81b90da5dbed48610cd7e5d60af62df9851ed1d1d23a9069f10", + "sha256:14839f54786987ccd9d03ed7f334baec0f02272e7ec4f6e9d427ff584aeea8b4", + "sha256:1d045cbe1358d76b24d5e20e7b1878efe578d9897a25c24e6006eef788c0fdf0", + "sha256:1f874ba705deea77bcf64a9da42c1f5fc2466d8f14daf410bc7d4ceae0a9fcb0", + "sha256:205f672a6c2c671a86d33f6d47c9b35781a998728d2c7c2a3e1cf3333fcb62b7", + "sha256:2177ee3901075167f01c5e335a6685e71b162a54a89a56001f1c3e9e3d2ad250", + "sha256:219c8187b3ceeadbf2afcf0f25a4918d02da7b944d703b97d12fb01510869078", + "sha256:25225cc79cfebc95ba1d24cd3ab86aaa35bcd315d12fa4358939bd55e9bd74a5", + "sha256:3630b670d5057cd9e08b9c4dab6493670e8e762a24c2c94ef312783870736ab9", + "sha256:368a05465f49c5949e27afd6fbe0a77ce53082185bbb2ac096a3a8afaf4de52e", + "sha256:36ebd71db3b89e1f7b1a5deaa341a654852c3518ea7a8ddfdf69cc66acc2db1b", + "sha256:39450e6215f7d9f6f7bc2a6da21d79374729f5d052333da4d5825af8a97e6735", + "sha256:398b10c77d471c0aab20a845e7a60076b6390bfdaac7a6d2edb0d2c59d75e8d8", + "sha256:3c3deac3748ec73ef24fc7be0b68220d14d47d6647d2f85b2771cb35ea847aa1", + "sha256:3f14a96a0034a27f9d47fd9788913924c89612225878f8078bb9d55f859272b0", + "sha256:3fc753451d471cff90b8f467a1fc0ae64031cf2d81b7b34e1811b7e2691bc4bc", + "sha256:414ffe86f4d6f434a8c3b7913655a1a5383b617f9bf38720e7c0799fac3ab1c6", + "sha256:449d77d636f8d9c17952628cc7e3b8faf6e92a17ec581ec0c0256300717e1512", + "sha256:4b6caec8576e760f2c7dd878ba817653144d5f369200b6ddf9771d64385b84d4", + "sha256:4d4fc827a20abe6d544a119896f6b78ee13fe81cbfef416f3f2ddf09a03f0e2e", + "sha256:5a42d3ecbb2db5080fc578314439b1d79eef71d323dc661aa616fb492436af5d", + "sha256:5b918d288958dc3fa1c5a0b9aa3256cb2b2b84c54407f4813c45d52267600cd3", + "sha256:5ef440054124728cc49b01c33469de06755e5a7a4e83ef61934ad95fc327fbb0", + "sha256:660c308dabd2b380807ab64b62985eaccf923a78ebc572bd485375b9ca2b7dc7", + "sha256:6a6c9bcf7cdc0fd41cc7b7944447982e8acfd9f0d560ea6d6845428ed0562058", + "sha256:6d24fc337fc055c9e83414c94e1ee0dee902a486d19d2a7f0929e49d7d604b09", + "sha256:7048eb4415d46368ef29d32133134c513f507fff7d953c18c91104738a68c3b3", + "sha256:77569d19a13015e840b81550922056acabc25e3f52782625bc6843cfa034e1da", + "sha256:8149a0f5a72ca36720981418eeffeb5c2729ea55fa179091c81a0910a114a5d2", + "sha256:836bef7ae338a072e9d1863502026f01b14027250a4545672673057997d5c05a", + "sha256:8621a07991add373c3c5c2cf89e1d277e49dc82ed72c75e3afc74bd0acc446f0", + "sha256:87e31011b5c14a33b29f17eb48932e63e1dcd3fa31d72209848652310d3d1f0d", + "sha256:88cf9163ef674b5be5736a584c999e98daf3aabac6e536e43286eb74c126b9c7", + "sha256:8fda642151d5affdee8a430bd85496f2e2517be3a2b9d2484d633d5712b15c56", + "sha256:90b5d9dfbb6d07a84ed3e696012610b6da074d97453bd01e0e30744b472c8179", + "sha256:90f4c7a069c733d95c308380aae314f2cb45bd8a904fb03eb36d1a4983a4993f", + "sha256:9481a6de29105d73cf4515f2bef8eb71e17ac184c19d0b9918a3701c6c9c4f23", + "sha256:9607b9a442392e690a57909c362811184ea429585a71061cd5d3c2b98065c199", + "sha256:9777564c0a72a1d457f0848977a1cbe15cfa75fa2f67ce267441e465717dcf1a", + "sha256:a032855dc7db987dff813583d04f4950d14326665d7e714d584560b140ae6b8b", + "sha256:a0adf84bc2e7c86e8a202537b4fd50e6f7f0e4a6b6bf64d7ccb96c4cd3330b29", + "sha256:a35f704be14768cea9790d921c2c1cc4fc52700410b1c10948511039be824aac", + "sha256:a3dfff83ca578cada2d19e665e9c8368e1598d4e787422a460ec70e531dbdd58", + "sha256:a4c805c6034206143fbabd2d259ec5e757f8b29d0a2f0bf3d2fe5d1f60147a4a", + "sha256:a655bde548ca98f55b43711b0ceefd2a88a71af6350b0c168aa77562104f3f45", + "sha256:ad2ab2547761d79926effe63de21479dfaf29834c50f98c4bf5b5480b5838434", + "sha256:b1f3628a0510bd58968c0f60447e7a692933589b791a6b572fcef374053ca280", + "sha256:b7e7ea2f782408c32d86b87a0d2c1fd8871b0399dd762364c731d86c86069a78", + "sha256:bc6ccf7d54c02ae47a48ddf9414c54d48af9c01076a2e1023e3b486b6e72c707", + "sha256:bea45f19b7ca000380fbd4e02552be86343080120d074b87f25593ce1700ad58", + "sha256:cc1fc87428c1d18b643479caa7b15db7d544652e5bf610513d4a3478dbe823d0", + "sha256:cd7c11968bc3860d5c78577f0dbc535257ccec41750675d58d8dc66aa47fe52c", + "sha256:ceada5be22fa5a5a4cdeec74e761c2ee7db287208f54c718f2df4b7e200b8d4a", + "sha256:cf5201a04550136ef870aa60ad3d29d2a59e452a7f96b94193bee6d73b8ad9a9", + "sha256:d9fd19ecc3a4d5ae82ddbfb30962cf6d874ff943e56e0c81f5169be2fda62979", + "sha256:ddaa4a390af911da6f680be8be4ff5aaf31c4c834c1a9147bc21cbcbca2d4370", + "sha256:df174ece723b228d3e8734a6f2a6febbd413ddec39b3dc592f5a4aa0aff28098", + "sha256:e0744623852f1497d825a49a99bfbec9bea4f3f946df6eb9d8a2f0c37a2fec2e", + "sha256:e5dc25a9dbd1a7f61eca4b7cb04e74ae4b963d658f9e4f9aad9cd00b688692c8", + "sha256:e7591d6f440af7f73c4bd9404f3772bfee064e639d2b6cc8c94076e71b2471c1", + "sha256:eb6d38971c800ff02e4a6afd791bbe3b923a9a57ca9aeab7314c21c84bf9ff05", + "sha256:ed907449fe5e021933e46a3e65d651f641975a768d0649fee59f10c2985529ed", + "sha256:f6cf0ad281c979306a6a34242b371e90e891bce504509fb6bb5246bbbf31e7b6", + "sha256:f95ba34d71e2fa0c5d225bde3b3bdb152e957150100e75c86bc7f3964c450d89" + ], + "markers": "python_version >= '3.9'", + "version": "==14.1" }, "wrapt": { "hashes": [ @@ -2587,91 +2558,91 @@ }, "yarl": { "hashes": [ - "sha256:019f5d58093402aa8f6661e60fd82a28746ad6d156f6c5336a70a39bd7b162b9", - "sha256:0fd9c227990f609c165f56b46107d0bc34553fe0387818c42c02f77974402c36", - "sha256:1208ca14eed2fda324042adf8d6c0adf4a31522fa95e0929027cd487875f0240", - "sha256:122d8e7986043d0549e9eb23c7fd23be078be4b70c9eb42a20052b3d3149c6f2", - "sha256:147b0fcd0ee33b4b5f6edfea80452d80e419e51b9a3f7a96ce98eaee145c1581", - "sha256:178ccb856e265174a79f59721031060f885aca428983e75c06f78aa24b91d929", - "sha256:1a5cf32539373ff39d97723e39a9283a7277cbf1224f7aef0c56c9598b6486c3", - "sha256:1a5e9d8ce1185723419c487758d81ac2bde693711947032cce600ca7c9cda7d6", - "sha256:1bc22e00edeb068f71967ab99081e9406cd56dbed864fc3a8259442999d71552", - "sha256:1cf936ba67bc6c734f3aa1c01391da74ab7fc046a9f8bbfa230b8393b90cf472", - "sha256:234f3a3032b505b90e65b5bc6652c2329ea7ea8855d8de61e1642b74b4ee65d2", - "sha256:26768342f256e6e3c37533bf9433f5f15f3e59e3c14b2409098291b3efaceacb", - "sha256:27e11db3f1e6a51081a981509f75617b09810529de508a181319193d320bc5c7", - "sha256:2bd6a51010c7284d191b79d3b56e51a87d8e1c03b0902362945f15c3d50ed46b", - "sha256:2f1fe2b2e3ee418862f5ebc0c0083c97f6f6625781382f828f6d4e9b614eba9b", - "sha256:32468f41242d72b87ab793a86d92f885355bcf35b3355aa650bfa846a5c60058", - "sha256:35b4f7842154176523e0a63c9b871168c69b98065d05a4f637fce342a6a2693a", - "sha256:38fec8a2a94c58bd47c9a50a45d321ab2285ad133adefbbadf3012c054b7e656", - "sha256:3a91654adb7643cb21b46f04244c5a315a440dcad63213033826549fa2435f71", - "sha256:3ab3ed42c78275477ea8e917491365e9a9b69bb615cb46169020bd0aa5e2d6d3", - "sha256:3d375a19ba2bfe320b6d873f3fb165313b002cef8b7cc0a368ad8b8a57453837", - "sha256:4199db024b58a8abb2cfcedac7b1292c3ad421684571aeb622a02f242280e8d6", - "sha256:4f32c4cb7386b41936894685f6e093c8dfaf0960124d91fe0ec29fe439e201d0", - "sha256:4ffb7c129707dd76ced0a4a4128ff452cecf0b0e929f2668ea05a371d9e5c104", - "sha256:504e1fe1cc4f170195320eb033d2b0ccf5c6114ce5bf2f617535c01699479bca", - "sha256:542fa8e09a581bcdcbb30607c7224beff3fdfb598c798ccd28a8184ffc18b7eb", - "sha256:5570e6d47bcb03215baf4c9ad7bf7c013e56285d9d35013541f9ac2b372593e7", - "sha256:571f781ae8ac463ce30bacebfaef2c6581543776d5970b2372fbe31d7bf31a07", - "sha256:595ca5e943baed31d56b33b34736461a371c6ea0038d3baec399949dd628560b", - "sha256:5b8e265a0545637492a7e12fd7038370d66c9375a61d88c5567d0e044ded9202", - "sha256:5b9101f528ae0f8f65ac9d64dda2bb0627de8a50344b2f582779f32fda747c1d", - "sha256:5ff96da263740779b0893d02b718293cc03400c3a208fc8d8cd79d9b0993e532", - "sha256:621280719c4c5dad4c1391160a9b88925bb8b0ff6a7d5af3224643024871675f", - "sha256:62c7da0ad93a07da048b500514ca47b759459ec41924143e2ddb5d7e20fd3db5", - "sha256:649bddcedee692ee8a9b7b6e38582cb4062dc4253de9711568e5620d8707c2a3", - "sha256:66ea8311422a7ba1fc79b4c42c2baa10566469fe5a78500d4e7754d6e6db8724", - "sha256:676d96bafc8c2d0039cea0cd3fd44cee7aa88b8185551a2bb93354668e8315c2", - "sha256:707ae579ccb3262dfaef093e202b4c3fb23c3810e8df544b1111bd2401fd7b09", - "sha256:7118bdb5e3ed81acaa2095cba7ec02a0fe74b52a16ab9f9ac8e28e53ee299732", - "sha256:789a3423f28a5fff46fbd04e339863c169ece97c827b44de16e1a7a42bc915d2", - "sha256:7ace71c4b7a0c41f317ae24be62bb61e9d80838d38acb20e70697c625e71f120", - "sha256:7c7c30fb38c300fe8140df30a046a01769105e4cf4282567a29b5cdb635b66c4", - "sha256:7d7aaa8ff95d0840e289423e7dc35696c2b058d635f945bf05b5cd633146b027", - "sha256:7f8713717a09acbfee7c47bfc5777e685539fefdd34fa72faf504c8be2f3df4e", - "sha256:858728086914f3a407aa7979cab743bbda1fe2bdf39ffcd991469a370dd7414d", - "sha256:8791d66d81ee45866a7bb15a517b01a2bcf583a18ebf5d72a84e6064c417e64b", - "sha256:87dd10bc0618991c66cee0cc65fa74a45f4ecb13bceec3c62d78ad2e42b27a16", - "sha256:8994c42f4ca25df5380ddf59f315c518c81df6a68fed5bb0c159c6cb6b92f120", - "sha256:8a0296040e5cddf074c7f5af4a60f3fc42c0237440df7bcf5183be5f6c802ed5", - "sha256:8b37d5ec034e668b22cf0ce1074d6c21fd2a08b90d11b1b73139b750a8b0dd97", - "sha256:8c42998fd1cbeb53cd985bff0e4bc25fbe55fd6eb3a545a724c1012d69d5ec84", - "sha256:8f639e3f5795a6568aa4f7d2ac6057c757dcd187593679f035adbf12b892bb00", - "sha256:921b81b8d78f0e60242fb3db615ea3f368827a76af095d5a69f1c3366db3f596", - "sha256:995d0759004c08abd5d1b81300a91d18c8577c6389300bed1c7c11675105a44d", - "sha256:99a9dcd4b71dd5f5f949737ab3f356cfc058c709b4f49833aeffedc2652dac56", - "sha256:9a91217208306d82357c67daeef5162a41a28c8352dab7e16daa82e3718852a7", - "sha256:a5ace0177520bd4caa99295a9b6fb831d0e9a57d8e0501a22ffaa61b4c024283", - "sha256:a5b6c09b9b4253d6a208b0f4a2f9206e511ec68dce9198e0fbec4f160137aa67", - "sha256:a9394c65ae0ed95679717d391c862dece9afacd8fa311683fc8b4362ce8a410c", - "sha256:aa7943f04f36d6cafc0cf53ea89824ac2c37acbdb4b316a654176ab8ffd0f968", - "sha256:ab2b2ac232110a1fdb0d3ffcd087783edd3d4a6ced432a1bf75caf7b7be70916", - "sha256:ad7a852d1cd0b8d8b37fc9d7f8581152add917a98cfe2ea6e241878795f917ae", - "sha256:b140e532fe0266003c936d017c1ac301e72ee4a3fd51784574c05f53718a55d8", - "sha256:b439cae82034ade094526a8f692b9a2b5ee936452de5e4c5f0f6c48df23f8604", - "sha256:b6f687ced5510a9a2474bbae96a4352e5ace5fa34dc44a217b0537fec1db00b4", - "sha256:b9ca7b9147eb1365c8bab03c003baa1300599575effad765e0b07dd3501ea9af", - "sha256:bdcf667a5dec12a48f669e485d70c54189f0639c2157b538a4cffd24a853624f", - "sha256:cdcffe1dbcb4477d2b4202f63cd972d5baa155ff5a3d9e35801c46a415b7f71a", - "sha256:d1aab176dd55b59f77a63b27cffaca67d29987d91a5b615cbead41331e6b7428", - "sha256:d1b0796168b953bca6600c5f97f5ed407479889a36ad7d17183366260f29a6b9", - "sha256:d3f1cc3d3d4dc574bebc9b387f6875e228ace5748a7c24f49d8f01ac1bc6c31b", - "sha256:d743e3118b2640cef7768ea955378c3536482d95550222f908f392167fe62059", - "sha256:d8643975a0080f361639787415a038bfc32d29208a4bf6b783ab3075a20b1ef3", - "sha256:d9525f03269e64310416dbe6c68d3b23e5d34aaa8f47193a1c45ac568cecbc49", - "sha256:de6c14dd7c7c0badba48157474ea1f03ebee991530ba742d381b28d4f314d6f3", - "sha256:e49e0fd86c295e743fd5be69b8b0712f70a686bc79a16e5268386c2defacaade", - "sha256:e6980a558d8461230c457218bd6c92dfc1d10205548215c2c21d79dc8d0a96f3", - "sha256:e8be3aff14f0120ad049121322b107f8a759be76a6a62138322d4c8a337a9e2c", - "sha256:e9951afe6557c75a71045148890052cb942689ee4c9ec29f5436240e1fcc73b7", - "sha256:ed097b26f18a1f5ff05f661dc36528c5f6735ba4ce8c9645e83b064665131349", - "sha256:f1d1f45e3e8d37c804dca99ab3cf4ab3ed2e7a62cd82542924b14c0a4f46d243", - "sha256:fe8bba2545427418efc1929c5c42852bdb4143eb8d0a46b09de88d1fe99258e7" + "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba", + "sha256:02ddb6756f8f4517a2d5e99d8b2f272488e18dd0bfbc802f31c16c6c20f22193", + "sha256:045b8482ce9483ada4f3f23b3774f4e1bf4f23a2d5c912ed5170f68efb053318", + "sha256:09c7907c8548bcd6ab860e5f513e727c53b4a714f459b084f6580b49fa1b9cee", + "sha256:0b0cad37311123211dc91eadcb322ef4d4a66008d3e1bdc404808992260e1a0e", + "sha256:0b3c92fa08759dbf12b3a59579a4096ba9af8dd344d9a813fc7f5070d86bbab1", + "sha256:0fb2171a4486bb075316ee754c6d8382ea6eb8b399d4ec62fde2b591f879778a", + "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186", + "sha256:1d407181cfa6e70077df3377938c08012d18893f9f20e92f7d2f314a437c30b1", + "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50", + "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640", + "sha256:2d06d3005e668744e11ed80812e61efd77d70bb7f03e33c1598c301eea20efbb", + "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8", + "sha256:3236da9272872443f81fedc389bace88408f64f89f75d1bdb2256069a8730ccc", + "sha256:35098b24e0327fc4ebdc8ffe336cee0a87a700c24ffed13161af80124b7dc8e5", + "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58", + "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2", + "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393", + "sha256:4ac515b860c36becb81bb84b667466885096b5fc85596948548b667da3bf9f24", + "sha256:5094d9206c64181d0f6e76ebd8fb2f8fe274950a63890ee9e0ebfd58bf9d787b", + "sha256:54d6921f07555713b9300bee9c50fb46e57e2e639027089b1d795ecd9f7fa910", + "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c", + "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272", + "sha256:602d98f2c2d929f8e697ed274fbadc09902c4025c5a9963bf4e9edfc3ab6f7ed", + "sha256:61b1a825a13bef4a5f10b1885245377d3cd0bf87cba068e1d9a88c2ae36880e1", + "sha256:61e5e68cb65ac8f547f6b5ef933f510134a6bf31bb178be428994b0cb46c2a04", + "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d", + "sha256:6333c5a377c8e2f5fae35e7b8f145c617b02c939d04110c76f29ee3676b5f9a5", + "sha256:6748dbf9bfa5ba1afcc7556b71cda0d7ce5f24768043a02a58846e4a443d808d", + "sha256:67a283dd2882ac98cc6318384f565bffc751ab564605959df4752d42483ad889", + "sha256:75674776d96d7b851b6498f17824ba17849d790a44d282929c42dbb77d4f17ae", + "sha256:757e81cae69244257d125ff31663249b3013b5dc0a8520d73694aed497fb195b", + "sha256:77a6e85b90a7641d2e07184df5557132a337f136250caafc9ccaa4a2a998ca2c", + "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576", + "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34", + "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477", + "sha256:80316a8bd5109320d38eef8833ccf5f89608c9107d02d2a7f985f98ed6876990", + "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2", + "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512", + "sha256:8503ad47387b8ebd39cbbbdf0bf113e17330ffd339ba1144074da24c545f0069", + "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a", + "sha256:8874027a53e3aea659a6d62751800cf6e63314c160fd607489ba5c2edd753cf6", + "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0", + "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8", + "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb", + "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa", + "sha256:93b2e109287f93db79210f86deb6b9bbb81ac32fc97236b16f7433db7fc437d8", + "sha256:9d41beda9dc97ca9ab0b9888cb71f7539124bc05df02c0cff6e5acc5a19dcc6e", + "sha256:a440a2a624683108a1b454705ecd7afc1c3438a08e890a1513d468671d90a04e", + "sha256:a4bb030cf46a434ec0225bddbebd4b89e6471814ca851abb8696170adb163985", + "sha256:a9ca04806f3be0ac6d558fffc2fdf8fcef767e0489d2684a21912cc4ed0cd1b8", + "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1", + "sha256:ac36703a585e0929b032fbaab0707b75dc12703766d0b53486eabd5139ebadd5", + "sha256:b1771de9944d875f1b98a745bc547e684b863abf8f8287da8466cf470ef52690", + "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10", + "sha256:b4f6450109834af88cb4cc5ecddfc5380ebb9c228695afc11915a0bf82116789", + "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b", + "sha256:b643562c12680b01e17239be267bc306bbc6aac1f34f6444d1bded0c5ce438ca", + "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e", + "sha256:b9d60031cf568c627d028239693fd718025719c02c9f55df0a53e587aab951b5", + "sha256:ba23302c0c61a9999784e73809427c9dbedd79f66a13d84ad1b1943802eaaf59", + "sha256:ba87babd629f8af77f557b61e49e7c7cac36f22f871156b91e10a6e9d4f829e9", + "sha256:c017a3b6df3a1bd45b9fa49a0f54005e53fbcad16633870104b66fa1a30a29d8", + "sha256:c1e1cc06da1491e6734f0ea1e6294ce00792193c463350626571c287c9a704db", + "sha256:c654d5207c78e0bd6d749f6dae1dcbbfde3403ad3a4b11f3c5544d9906969dde", + "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7", + "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb", + "sha256:ccaa3a4b521b780a7e771cc336a2dba389a0861592bbce09a476190bb0c8b4b3", + "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6", + "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285", + "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb", + "sha256:d980e0325b6eddc81331d3f4551e2a333999fb176fd153e075c6d1c2530aa8a8", + "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482", + "sha256:e2c08cc9b16f4f4bc522771d96734c7901e7ebef70c6c5c35dd0f10845270bcd", + "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75", + "sha256:e3b9fd71836999aad54084906f8663dffcd2a7fb5cdafd6c37713b2e72be1760", + "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782", + "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53", + "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2", + "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1", + "sha256:fe57328fbc1bfd0bd0514470ac692630f3901c0ee39052ae47acd1d90a436719", + "sha256:fea09ca13323376a2fdfb353a5fa2e59f90cd18d7ca4eaa1fd31f0a8b4f91e62" ], "markers": "python_version >= '3.9'", - "version": "==1.16.0" + "version": "==1.18.3" }, "zipp": { "hashes": [ diff --git a/src/apps/activities/api/activities.py b/src/apps/activities/api/activities.py index 193de76c11e..41e6e85d47e 100644 --- a/src/apps/activities/api/activities.py +++ b/src/apps/activities/api/activities.py @@ -5,14 +5,17 @@ from apps.activities.crud import ActivitiesCRUD from apps.activities.domain.activity import ( + ActivitiesMetadata, ActivityLanguageWithItemsMobileDetailPublic, ActivityOrFlowWithAssignmentsPublic, ActivitySingleLanguageWithItemsDetailPublic, + ActivitySubjectMetadata, ActivityWithAssignmentDetailsPublic, ) from apps.activities.filters import AppletActivityFilter from apps.activities.services.activity import ActivityItemService, ActivityService from apps.activity_assignments.service import ActivityAssignmentService +from apps.activity_flows.crud import FlowsCRUD from apps.activity_flows.domain.flow import FlowWithAssignmentDetailsPublic from apps.activity_flows.service.flow import FlowService from apps.answers.deps.preprocess_arbitrary import get_answer_session @@ -169,7 +172,8 @@ async def applet_activities_for_target_subject( applet_service = AppletService(session, user.id) await applet_service.exist_by_id(applet_id) - await SubjectsService(session, user.id).exist_by_id(subject_id) + subject = await SubjectsService(session, user.id).exist_by_id(subject_id) + is_limited_respondent = subject.user_id is None # Restrict the endpoint access to owners, managers, coordinators, and assigned reviewers await CheckAccessService(session, user.id).check_subject_subject_access(applet_id, subject_id) @@ -191,7 +195,7 @@ async def applet_activities_for_target_subject( activities_and_flows = await ActivityService(session, user.id).get_activity_and_flow_basic_info_by_ids_or_auto( applet_id=applet_id, ids=activity_and_flow_ids_from_submissions + activity_and_flow_ids_from_assignments, - include_auto=True, + include_auto=not is_limited_respondent, language=language, ) @@ -358,3 +362,110 @@ async def __filter_activities( activities.remove(activity) return activities + + +async def applet_activities_metadata_for_subject( + applet_id: uuid.UUID, + subject_id: uuid.UUID, + user: User = Depends(get_current_user), + language: str = Depends(get_language), + session=Depends(get_session), + answer_session=Depends(get_answer_session), +) -> Response[ActivitiesMetadata]: + applet_service = AppletService(session, user.id) + await applet_service.exist_by_id(applet_id) + await CheckAccessService(session, user.id).check_applet_detail_access(applet_id) + + subject = await SubjectsService(session, user.id).exist_by_id(subject_id) + is_limited_respondent = subject.user_id is None + + # Fetch assigned activity or flow IDs for the subject + assigned_activities = await ActivityAssignmentService(session).get_assigned_activity_or_flow_ids_for_subject( + subject_id + ) + + # Fetch activities submissions by the subject + submitted_activities = await AnswerService(session, user.id, answer_session).get_submissions_by_subject(subject_id) + + # Fetch auto-assigned activity and flow IDs by applet ID + auto_activity_ids = await ActivityService(session, user.id).get_activity_and_flow_ids_by_applet_id_auto(applet_id) + + # Combine all assigned IDs and submitted activity IDs + all_activity_ids = ( + set(assigned_activities.activities.keys()) + | set(submitted_activities.activities.keys()) + | set(auto_activity_ids) + ) + + activities = await ActivitiesCRUD(session).get_by_applet_id_and_activities_ids(applet_id, list(all_activity_ids)) + flows = await FlowsCRUD(session).get_by_applet_id_and_flows_ids(applet_id, list(all_activity_ids)) + + activities_state = {activity.id: activity.soft_exists() for activity in activities} + flows_state = {flow.id: flow.soft_exists() for flow in flows} + + # Initialize ActivitiesCounters with zero counts + activities_metadata = ActivitiesMetadata(subject_id=subject_id) + + # Iterate over all activity or flow IDs + for activity_or_flow_id in all_activity_ids: + is_auto = activity_or_flow_id in auto_activity_ids + + # Get submission and assignment data if available + submission_data = submitted_activities.activities.get(activity_or_flow_id) + assignments_data = assigned_activities.activities.get(activity_or_flow_id) + + # Initialize sets for respondents and subjects + respondents = set() + subjects = set() + + # Initialize submission counts + respondent_submissions_count = 0 + subject_submissions_count = 0 + + # Update from submission data + if submission_data: + respondents.update(submission_data.respondents) + subjects.update(submission_data.subjects) + respondent_submissions_count = submission_data.respondent_submissions_count + subject_submissions_count = submission_data.subject_submissions_count + + # Update from assignment data + if assignments_data: + respondents.update(assignments_data.respondents) + subjects.update(assignments_data.subjects) + + # Include the subject for auto-assigned activities, excluding limited accounts + if is_auto and not is_limited_respondent: + respondents.add(subject_id) + subjects.add(subject_id) + + # Calculate counts + respondents_count = len(respondents) + subjects_count = len(subjects) + + activity_or_flow_exists = activities_state.get(activity_or_flow_id) or flows_state.get(activity_or_flow_id) + + # Update activities counters counts + if subjects_count > 0: + if activity_or_flow_exists: + activities_metadata.respondent_activities_count_existing += 1 + else: + activities_metadata.respondent_activities_count_deleted += 1 + if respondents_count > 0: + if activity_or_flow_exists: + activities_metadata.target_activities_count_existing += 1 + else: + activities_metadata.target_activities_count_deleted += 1 + + # Append the activity subject counters + activities_metadata.activities_or_flows.append( + ActivitySubjectMetadata( + activity_or_flow_id=activity_or_flow_id, + respondents_count=respondents_count, + subjects_count=subjects_count, + respondent_submissions_count=respondent_submissions_count, + subject_submissions_count=subject_submissions_count, + ) + ) + + return Response(result=activities_metadata) diff --git a/src/apps/activities/crud/activity.py b/src/apps/activities/crud/activity.py index 6061c5681c8..10345553e9e 100644 --- a/src/apps/activities/crud/activity.py +++ b/src/apps/activities/crud/activity.py @@ -107,6 +107,12 @@ async def get_ids_by_applet_id(self, applet_id: uuid.UUID) -> list[uuid.UUID]: result = await self._execute(query) return result.scalars().all() + async def get_ids_by_applet_id_auto(self, applet_id: uuid.UUID) -> list[uuid.UUID]: + query: Query = select(ActivitySchema.id) + query = query.where(ActivitySchema.applet_id == applet_id, ActivitySchema.auto_assign.is_(True)) + result = await self._execute(query) + return result.scalars().all() + async def get_activity_and_flow_basic_info_by_ids_or_auto( self, applet_id: uuid.UUID, ids: list[uuid.UUID], include_auto: bool, language: str ) -> list[ActivityOrFlowBasicInfoInternal]: diff --git a/src/apps/activities/domain/activity.py b/src/apps/activities/domain/activity.py index 8305d5e5e1f..8f0c9cfe9f4 100644 --- a/src/apps/activities/domain/activity.py +++ b/src/apps/activities/domain/activity.py @@ -156,3 +156,20 @@ class ActivityBaseInfo(ActivityMinimumInfo, InternalModel): contains_response_types: list[ResponseType] item_count: int auto_assign: bool + + +class ActivitySubjectMetadata(PublicModel): + activity_or_flow_id: uuid.UUID + respondents_count: int + respondent_submissions_count: int + subjects_count: int + subject_submissions_count: int + + +class ActivitiesMetadata(PublicModel): + subject_id: uuid.UUID + respondent_activities_count_existing: int = 0 + respondent_activities_count_deleted: int = 0 + target_activities_count_existing: int = 0 + target_activities_count_deleted: int = 0 + activities_or_flows: list[ActivitySubjectMetadata] = Field(default_factory=list) diff --git a/src/apps/activities/router.py b/src/apps/activities/router.py index c54145866dc..46184c7fef7 100644 --- a/src/apps/activities/router.py +++ b/src/apps/activities/router.py @@ -8,10 +8,12 @@ applet_activities_for_respondent_subject, applet_activities_for_subject, applet_activities_for_target_subject, + applet_activities_metadata_for_subject, public_activity_retrieve, ) from apps.activities.api.reusable_item_choices import item_choice_create, item_choice_delete, item_choice_retrieve from apps.activities.domain.activity import ( + ActivitiesMetadata, ActivityOrFlowWithAssignmentsPublic, ActivitySingleLanguageWithItemsDetailPublic, ) @@ -133,3 +135,16 @@ **DEFAULT_OPENAPI_RESPONSE, }, )(applet_activities_for_respondent_subject) + +router.get( + "/applet/{applet_id}/subject/{subject_id}/metadata", + description="""Get metadata, like number of submissions and participants for activities and activity + flows associated with the given participant, either as respondent or target subject. + """, + status_code=status.HTTP_200_OK, + responses={ + status.HTTP_200_OK: {"model": Response[ActivitiesMetadata]}, + **AUTHENTICATION_ERROR_RESPONSES, + **DEFAULT_OPENAPI_RESPONSE, + }, +)(applet_activities_metadata_for_subject) diff --git a/src/apps/activities/services/activity.py b/src/apps/activities/services/activity.py index b10d46527fa..31af33ed9a6 100644 --- a/src/apps/activities/services/activity.py +++ b/src/apps/activities/services/activity.py @@ -1,3 +1,4 @@ +import asyncio import uuid from apps.activities.crud import ActivitiesCRUD, ActivityHistoriesCRUD @@ -20,6 +21,7 @@ from apps.activities.errors import ActivityAccessDeniedError, ActivityDoeNotExist from apps.activities.services.activity_item import ActivityItemService from apps.activity_assignments.service import ActivityAssignmentService +from apps.activity_flows.crud import FlowsCRUD from apps.applets.crud import AppletsCRUD, UserAppletAccessCRUD from apps.schedule.crud.events import ActivityEventsCRUD, EventCRUD from apps.schedule.service.schedule import ScheduleService @@ -462,3 +464,11 @@ async def get_activity_and_flow_basic_info_by_ids_or_auto( return await ActivitiesCRUD(self.session).get_activity_and_flow_basic_info_by_ids_or_auto( applet_id, ids, include_auto, language ) + + async def get_activity_and_flow_ids_by_applet_id_auto(self, applet_id: uuid.UUID) -> list[uuid.UUID]: + activity_ids_coro = ActivitiesCRUD(self.session).get_ids_by_applet_id_auto(applet_id) + flow_ids_coro = FlowsCRUD(self.session).get_ids_by_applet_id_auto(applet_id) + + activity_ids, flow_ids = await asyncio.gather(activity_ids_coro, flow_ids_coro) + + return activity_ids + flow_ids diff --git a/src/apps/activities/tests/test_activities.py b/src/apps/activities/tests/test_activities.py index 43faa1f8352..65494fc711b 100644 --- a/src/apps/activities/tests/test_activities.py +++ b/src/apps/activities/tests/test_activities.py @@ -32,6 +32,7 @@ from apps.shared.test.client import TestClient from apps.subjects.db.schemas import SubjectSchema from apps.subjects.domain import Subject +from apps.subjects.services import SubjectsService from apps.themes.domain import Theme from apps.users.domain import User from apps.workspaces.domain.constants import Role @@ -283,6 +284,7 @@ class TestActivities: subject_assigned_activities_url = "/activities/applet/{applet_id}/subject/{subject_id}" target_assigned_activities_url = "/activities/applet/{applet_id}/target/{subject_id}" respondent_assigned_activities_url = "/activities/applet/{applet_id}/respondent/{subject_id}" + activity_metadata_by_subject_url = "/activities/applet/{applet_id}/subject/{subject_id}/metadata" async def test_activity_detail(self, client: TestClient, applet_one: AppletFull, tom: User): activity = applet_one.activities[0] @@ -1266,6 +1268,26 @@ async def test_assigned_activities_limited_respondent( assert result_activity["performanceTaskType"] is None assert len(result_activity["assignments"]) == 0 + response = await client.get( + self.activity_metadata_by_subject_url.format( + applet_id=applet_one.id, subject_id=applet_one_shell_account.id + ) + ) + + assert response.status_code == http.HTTPStatus.OK + result = response.json()["result"] + + assert result["respondentActivitiesCountExisting"] == 1 + assert result["respondentActivitiesCountDeleted"] == 0 + assert result["targetActivitiesCountExisting"] == 0 + assert result["targetActivitiesCountDeleted"] == 0 + assert len(result["activitiesOrFlows"]) == 1 + assert result["activitiesOrFlows"][0]["activityOrFlowId"] == str(activity.id) + assert result["activitiesOrFlows"][0]["respondentsCount"] == 0 + assert result["activitiesOrFlows"][0]["respondentSubmissionsCount"] == 1 + assert result["activitiesOrFlows"][0]["subjectsCount"] == 1 + assert result["activitiesOrFlows"][0]["subjectSubmissionsCount"] == 0 + @pytest.mark.parametrize("subject_type", ["target", "respondent"]) async def test_assigned_activities_auto_assigned( self, @@ -1317,6 +1339,33 @@ async def test_assigned_activities_auto_assigned( assert activity_result["isPerformanceTask"] is False assert activity_result["performanceTaskType"] is None + response = await client.get( + self.activity_metadata_by_subject_url.format( + applet_id=applet_activity_flow_lucy_manager.id, subject_id=lucy_applet_activity_flow_subject.id + ) + ) + + assert response.status_code == http.HTTPStatus.OK + result = response.json()["result"] + + assert result["respondentActivitiesCountExisting"] == 2 + assert result["respondentActivitiesCountDeleted"] == 0 + assert result["targetActivitiesCountExisting"] == 2 + assert result["targetActivitiesCountDeleted"] == 0 + assert len(result["activitiesOrFlows"]) == 2 + flow_counters = next(item for item in result["activitiesOrFlows"] if item["activityOrFlowId"] == str(flow.id)) + activity_counters = next( + item for item in result["activitiesOrFlows"] if item["activityOrFlowId"] == str(activity.id) + ) + assert flow_counters["respondentsCount"] == 1 + assert flow_counters["respondentSubmissionsCount"] == 0 + assert flow_counters["subjectsCount"] == 1 + assert flow_counters["subjectSubmissionsCount"] == 0 + assert activity_counters["respondentsCount"] == 1 + assert activity_counters["respondentSubmissionsCount"] == 0 + assert activity_counters["subjectsCount"] == 1 + assert activity_counters["subjectSubmissionsCount"] == 0 + @pytest.mark.parametrize( "subject_type,result_order", [ @@ -1567,6 +1616,60 @@ async def test_assigned_activities_manually_assigned( subject_attr = "targetSubject" if subject_type == "target" else "respondentSubject" assert flow_assignment[subject_attr]["id"] == str(user_empty_applet_subject.id) + as_respondent = ( + {activity_by_number[1].id, activity_by_number[2].id} + if subject_type == "target" + else {activity_by_number[4].id, activity_by_number[3].id} + ) + as_target = ( + {activity_by_number[1].id, activity_by_number[3].id} + if subject_type == "target" + else {activity_by_number[4].id, activity_by_number[2].id} + ) + + as_respondent.update( + {flow_by_number[1].id, flow_by_number[2].id} + if subject_type == "target" + else { + flow_by_number[4].id, + flow_by_number[3].id, + } + ) + as_target.update( + {flow_by_number[1].id, flow_by_number[3].id} + if subject_type == "target" + else { + flow_by_number[4].id, + flow_by_number[2].id, + } + ) + + client.login(lucy) + + response = await client.get( + self.activity_metadata_by_subject_url.format( + applet_id=empty_applet_lucy_manager.id, + subject_id=user_empty_applet_subject.id if subject_type == "target" else lucy_empty_applet_subject.id, + ) + ) + + assert response.status_code == http.HTTPStatus.OK + result = response.json()["result"] + + assert len(result["activitiesOrFlows"]) == 6 + assert result["respondentActivitiesCountExisting"] == 4 + assert result["respondentActivitiesCountDeleted"] == 0 + assert result["targetActivitiesCountExisting"] == 4 + assert result["targetActivitiesCountDeleted"] == 0 + for activityOrFlow in result["activitiesOrFlows"]: + is_respondent = uuid.UUID(activityOrFlow["activityOrFlowId"]) in as_respondent + is_target = uuid.UUID(activityOrFlow["activityOrFlowId"]) in as_target + + assert activityOrFlow["respondentsCount"] == (1 if is_target else 0) + assert activityOrFlow["respondentSubmissionsCount"] == 0 + assert activityOrFlow["subjectsCount"] == (1 if is_respondent else 0) + assert activityOrFlow["subjectSubmissionsCount"] == 0 + @pytest.mark.parametrize("subject_type", ["target", "respondent"]) async def test_assigned_activities_from_submission( self, @@ -1634,6 +1737,26 @@ async def test_assigned_activities_from_submission( assert result_activity["performanceTaskType"] is None assert len(result_activity["assignments"]) == 0 + response = await client.get( + self.activity_metadata_by_subject_url.format( + applet_id=applet_one_lucy_respondent.id, subject_id=tom_applet_one_subject.id + ) + ) + + assert response.status_code == http.HTTPStatus.OK + result = response.json()["result"] + + assert result["respondentActivitiesCountExisting"] == (0 if subject_type == "target" else 1) + assert result["respondentActivitiesCountDeleted"] == 0 + assert result["targetActivitiesCountExisting"] == (1 if subject_type == "target" else 0) + assert result["targetActivitiesCountDeleted"] == 0 + assert len(result["activitiesOrFlows"]) == 1 + activityOrFlow = result["activitiesOrFlows"][0] + assert activityOrFlow["respondentsCount"] == (1 if subject_type == "target" else 0) + assert activityOrFlow["respondentSubmissionsCount"] == (0 if subject_type == "target" else 1) + assert activityOrFlow["subjectsCount"] == (0 if subject_type == "target" else 1) + assert activityOrFlow["subjectSubmissionsCount"] == (1 if subject_type == "target" else 0) + @pytest.mark.parametrize("subject_type", ["target", "respondent"]) async def test_assigned_hidden_activities( self, @@ -1784,6 +1907,31 @@ async def test_assigned_hidden_activities( assert result_activity_auto["performanceTaskType"] is None assert len(result_activity_auto["assignments"]) == 0 + response = await client.get( + self.activity_metadata_by_subject_url.format( + applet_id=empty_applet_lucy_manager.id, + subject_id=user_empty_applet_subject.id if subject_type == "target" else lucy_empty_applet_subject.id, + ) + ) + + assert response.status_code == http.HTTPStatus.OK + result = response.json()["result"] + + assert len(result["activitiesOrFlows"]) == 4 + assert result["respondentActivitiesCountExisting"] == (2 if subject_type == "target" else 4) + assert result["respondentActivitiesCountDeleted"] == 0 + assert result["targetActivitiesCountExisting"] == (4 if subject_type == "target" else 2) + assert result["targetActivitiesCountDeleted"] == 0 + for activityOrFlow in result["activitiesOrFlows"]: + is_auto = activityOrFlow["activityOrFlowId"] == str(auto_flow.id) or activityOrFlow[ + "activityOrFlowId" + ] == str(auto_activity.id) + + assert activityOrFlow["respondentsCount"] == (1 if is_auto or subject_type == "target" else 0) + assert activityOrFlow["respondentSubmissionsCount"] == 0 + assert activityOrFlow["subjectsCount"] == (1 if is_auto or subject_type != "target" else 0) + assert activityOrFlow["subjectSubmissionsCount"] == 0 + @pytest.mark.parametrize("subject_type", ["target", "respondent"]) async def test_assigned_performance_tasks( self, @@ -1816,3 +1964,91 @@ async def test_assigned_performance_tasks( PerformanceTaskType.ABTRAILS.value, PerformanceTaskType.UNITY.value, ] + + async def test_activities_metadata_deleted_subject( + self, + session: AsyncSession, + client: TestClient, + lucy: User, + empty_applet_lucy_manager: AppletFull, + lucy_empty_applet_subject: Subject, + user_empty_applet_subject: Subject, + activity_create_session: ActivityCreate, + ): + activity_service = ActivityService(session, lucy.id) + activities = await activity_service.update_create( + empty_applet_lucy_manager.id, + [ + ActivityUpdate( + **activity_create_session.dict(exclude={"name", "auto_assign"}), + name="Manual Activity 1", + auto_assign=False, + ), + ActivityUpdate( + **activity_create_session.dict(exclude={"name", "auto_assign"}), + name="Manual Activity 2", + auto_assign=False, + ), + ], + ) + + await ActivityAssignmentService(session).create_many( + empty_applet_lucy_manager.id, + [ + ActivityAssignmentCreate( + activity_id=activities[0].id, + activity_flow_id=None, + respondent_subject_id=lucy_empty_applet_subject.id, + target_subject_id=user_empty_applet_subject.id, + ), + ActivityAssignmentCreate( + activity_id=activities[1].id, + activity_flow_id=None, + respondent_subject_id=user_empty_applet_subject.id, + target_subject_id=user_empty_applet_subject.id, + ), + ], + ) + + manual_activity_2 = next((activity for activity in activities if activity.name == "Manual Activity 2")) + + client.login(lucy) + + response = await client.get( + self.activity_metadata_by_subject_url.format( + applet_id=empty_applet_lucy_manager.id, subject_id=user_empty_applet_subject.id + ) + ) + + assert response.status_code == http.HTTPStatus.OK + result = response.json()["result"] + + assert result["respondentActivitiesCountExisting"] == 1 + assert result["respondentActivitiesCountDeleted"] == 0 + assert result["targetActivitiesCountExisting"] == 2 + assert result["targetActivitiesCountDeleted"] == 0 + assert len(result["activitiesOrFlows"]) == 2 + for activityOrFlow in result["activitiesOrFlows"]: + assert activityOrFlow["respondentsCount"] == 1 + assert activityOrFlow["respondentSubmissionsCount"] == 0 + assert activityOrFlow["subjectsCount"] == ( + 1 if activityOrFlow["activityOrFlowId"] == str(manual_activity_2.id) else 0 + ) + assert activityOrFlow["subjectSubmissionsCount"] == 0 + + await SubjectsService(session, lucy.id).delete(user_empty_applet_subject.id) + + response = await client.get( + self.activity_metadata_by_subject_url.format( + applet_id=empty_applet_lucy_manager.id, subject_id=user_empty_applet_subject.id + ) + ) + + assert response.status_code == http.HTTPStatus.OK + result = response.json()["result"] + + assert result["respondentActivitiesCountExisting"] == 0 + assert result["respondentActivitiesCountDeleted"] == 0 + assert result["targetActivitiesCountExisting"] == 0 + assert result["targetActivitiesCountDeleted"] == 0 + assert len(result["activitiesOrFlows"]) == 0 diff --git a/src/apps/activity_assignments/crud/assignments.py b/src/apps/activity_assignments/crud/assignments.py index 1ab2f9ac69c..1ee90e151c1 100644 --- a/src/apps/activity_assignments/crud/assignments.py +++ b/src/apps/activity_assignments/crud/assignments.py @@ -1,9 +1,9 @@ import datetime import uuid -from sqlalchemy import and_, or_, select, tuple_, update +from sqlalchemy import and_, case, func, or_, select, tuple_, update from sqlalchemy.dialects.postgresql import insert -from sqlalchemy.orm import Query, aliased +from sqlalchemy.orm import InstrumentedAttribute, Query, aliased from apps.activities.db.schemas import ActivitySchema from apps.activity_assignments.db.schemas import ActivityAssigmentSchema @@ -315,3 +315,55 @@ async def check_if_auto_assigned(self, activity_or_flow_id: uuid.UUID) -> bool | db_result = await self._execute(union_query) return db_result.scalar_one_or_none() + + @staticmethod + def _activity_and_flow_ids_by_subject_query(subject_column: InstrumentedAttribute, subject_id: uuid.UUID) -> Query: + respondent_schema = aliased(SubjectSchema) + target_schema = aliased(SubjectSchema) + + query: Query = ( + select( + case( + ( + ActivityAssigmentSchema.activity_id.isnot(None), + ActivityAssigmentSchema.activity_id, + ), + else_=ActivityAssigmentSchema.activity_flow_id, + ).label("activity_id"), + func.array_agg( + ActivityAssigmentSchema.respondent_subject_id + if subject_column == ActivityAssigmentSchema.target_subject_id + else ActivityAssigmentSchema.target_subject_id + ).label("subject_ids"), + func.count(ActivityAssigmentSchema.id).label("assignments_count"), + ) + .join(respondent_schema, respondent_schema.id == ActivityAssigmentSchema.respondent_subject_id) + .join(target_schema, target_schema.id == ActivityAssigmentSchema.target_subject_id) + .where( + subject_column == subject_id, + ActivityAssigmentSchema.soft_exists(), + respondent_schema.soft_exists(), + target_schema.soft_exists(), + ) + .group_by("activity_id", ActivityAssigmentSchema.activity_id, ActivityAssigmentSchema.activity_flow_id) + ) + + return query + + async def get_assignments_by_target_subject(self, target_subject_id: uuid.UUID) -> list[dict]: + query: Query = self._activity_and_flow_ids_by_subject_query( + ActivityAssigmentSchema.target_subject_id, target_subject_id + ) + + res = await self._execute(query) + + return res.mappings().all() + + async def get_assignments_by_respondent_subject(self, respondent_subject_id: uuid.UUID) -> list[dict]: + query: Query = self._activity_and_flow_ids_by_subject_query( + ActivityAssigmentSchema.respondent_subject_id, respondent_subject_id + ) + + res = await self._execute(query) + + return res.mappings().all() diff --git a/src/apps/activity_assignments/domain/assignments.py b/src/apps/activity_assignments/domain/assignments.py index 91a313a46a3..ca9ea6f1b2b 100644 --- a/src/apps/activity_assignments/domain/assignments.py +++ b/src/apps/activity_assignments/domain/assignments.py @@ -1,6 +1,7 @@ +import uuid from uuid import UUID -from pydantic import BaseModel, root_validator +from pydantic import BaseModel, Field, root_validator from apps.activity_assignments.errors import ( ActivityAssignmentActivityOrFlowError, @@ -79,3 +80,15 @@ def validate_assignments(cls, values): class ActivitiesAssignmentsDelete(InternalModel): assignments: list[ActivityAssignmentDelete] + + +class AssignmentsSubjectCounters(PublicModel): + respondents: set[uuid.UUID] = Field(default_factory=set) + subjects: set[uuid.UUID] = Field(default_factory=set) + subject_assignments_count: int = 0 + respondent_assignments_count: int = 0 + + +class AssignmentsActivityCountBySubject(PublicModel): + subject_id: uuid.UUID + activities: dict[uuid.UUID, AssignmentsSubjectCounters] = Field(default_factory=dict) diff --git a/src/apps/activity_assignments/service.py b/src/apps/activity_assignments/service.py index 9ac2a5bfce4..cde77bc5687 100644 --- a/src/apps/activity_assignments/service.py +++ b/src/apps/activity_assignments/service.py @@ -11,6 +11,8 @@ ActivityAssignmentCreate, ActivityAssignmentDelete, ActivityAssignmentWithSubject, + AssignmentsActivityCountBySubject, + AssignmentsSubjectCounters, ) from apps.activity_flows.crud import FlowsCRUD from apps.activity_flows.db.schemas import ActivityFlowSchema @@ -447,6 +449,36 @@ async def check_if_auto_assigned(self, activity_or_flow_id: uuid.UUID) -> bool | """ return await ActivityAssigmentCRUD(self.session).check_if_auto_assigned(activity_or_flow_id) + async def get_assigned_activity_or_flow_ids_for_subject( + self, subject_id: uuid.UUID + ) -> AssignmentsActivityCountBySubject: + assignments_target_coro = ActivityAssigmentCRUD(self.session).get_assignments_by_target_subject(subject_id) + assignments_respondent_coro = ActivityAssigmentCRUD(self.session).get_assignments_by_respondent_subject( + subject_id + ) + + assignments_target, assignments_respondent = await asyncio.gather( + assignments_target_coro, assignments_respondent_coro + ) + + assignments_activity_count = AssignmentsActivityCountBySubject(subject_id=subject_id) + + for activityOrFlow in assignments_target: + activity_counters = assignments_activity_count.activities.setdefault( + activityOrFlow["activity_id"], AssignmentsSubjectCounters() + ) + activity_counters.subject_assignments_count = activityOrFlow["assignments_count"] + activity_counters.respondents.update(activityOrFlow["subject_ids"]) + + for activityOrFlow in assignments_respondent: + activity_counters = assignments_activity_count.activities.setdefault( + activityOrFlow["activity_id"], AssignmentsSubjectCounters() + ) + activity_counters.respondent_assignments_count = activityOrFlow["assignments_count"] + activity_counters.subjects.update(activityOrFlow["subject_ids"]) + + return assignments_activity_count + @staticmethod def _get_email_template_name() -> str: return "new_activity_assignments" diff --git a/src/apps/activity_flows/crud/flow.py b/src/apps/activity_flows/crud/flow.py index 6b8171fcf5c..0b1ae41dc2e 100644 --- a/src/apps/activity_flows/crud/flow.py +++ b/src/apps/activity_flows/crud/flow.py @@ -67,3 +67,10 @@ async def get_ids_by_applet_id(self, applet_id: uuid.UUID) -> list[uuid.UUID]: result = await self._execute(query) return result.scalars().all() + + async def get_ids_by_applet_id_auto(self, applet_id: uuid.UUID) -> list[uuid.UUID]: + query: Query = select(ActivityFlowSchema.id) + query = query.where(ActivityFlowSchema.applet_id == applet_id, ActivityFlowSchema.auto_assign.is_(True)) + + result = await self._execute(query) + return result.scalars().all() diff --git a/src/apps/answers/crud/answers.py b/src/apps/answers/crud/answers.py index fb5ef8c3a9c..01ce9013e3a 100644 --- a/src/apps/answers/crud/answers.py +++ b/src/apps/answers/crud/answers.py @@ -942,7 +942,7 @@ async def delete_by_ids(self, ids: list[uuid.UUID]): async def get_target_subject_ids_by_respondent( self, respondent_subject_id: uuid.UUID, activity_or_flow_id: uuid.UUID - ): + ) -> list[tuple[uuid.UUID, int]]: query: Query = ( select( AnswerSchema.target_subject_id, @@ -950,10 +950,15 @@ async def get_target_subject_ids_by_respondent( ) .where( AnswerSchema.source_subject_id == respondent_subject_id, - or_( - AnswerSchema.id_from_history_id(AnswerSchema.activity_history_id) == str(activity_or_flow_id), - AnswerSchema.id_from_history_id(AnswerSchema.flow_history_id) == str(activity_or_flow_id), + case( + ( + AnswerSchema.flow_history_id.isnot(None), + AnswerSchema.id_from_history_id(AnswerSchema.flow_history_id) == str(activity_or_flow_id), + ), + else_=AnswerSchema.id_from_history_id(AnswerSchema.activity_history_id) == str(activity_or_flow_id), ), + # Exclude incomplete activity flow assessments + AnswerSchema.is_flow_completed.isnot(False), ) .group_by(AnswerSchema.target_subject_id) ) @@ -971,27 +976,77 @@ def __activity_and_flow_ids_by_subject_query(subject_column: InstrumentedAttribu AnswerSchema.id_from_history_id(AnswerSchema.flow_history_id), ), else_=AnswerSchema.id_from_history_id(AnswerSchema.activity_history_id), - ).label("id") + ).label("activity_id"), + ( + AnswerSchema.source_subject_id + if subject_column == AnswerSchema.target_subject_id + else AnswerSchema.target_subject_id + ).label("subject_id"), ) - .where(subject_column == subject_id) - .distinct() + .where( + subject_column == subject_id, + # Exclude incomplete activity flow assessments + AnswerSchema.is_flow_completed.isnot(False), + ) + .group_by("activity_id", "subject_id") ) return query - async def get_activity_and_flow_ids_by_target_subject(self, target_subject_id: uuid.UUID) -> list[uuid.UUID]: + async def get_activity_and_flow_ids_by_target_subject(self, target_subject_id: uuid.UUID) -> list[dict]: """ Get a list of activity and flow IDs based on answers submitted for a target subject """ res = await self._execute( self.__activity_and_flow_ids_by_subject_query(AnswerSchema.target_subject_id, target_subject_id) ) - return res.scalars().all() + return res.mappings().all() - async def get_activity_and_flow_ids_by_source_subject(self, source_subject_id: uuid.UUID) -> list[uuid.UUID]: + async def get_activity_and_flow_ids_by_source_subject(self, source_subject_id: uuid.UUID) -> list[dict]: """ Get a list of activity and flow IDs based on answers submitted for a source subject """ res = await self._execute( self.__activity_and_flow_ids_by_subject_query(AnswerSchema.source_subject_id, source_subject_id) ) - return res.scalars().all() + return res.mappings().all() + + @staticmethod + def _query_submissions_by_subject(subject_column: InstrumentedAttribute, subject_id: uuid.UUID) -> Query: + query: Query = ( + select( + func.count(func.distinct(AnswerSchema.submit_id)).label("submission_count"), + case( + ( + AnswerSchema.flow_history_id.isnot(None), + AnswerSchema.id_from_history_id(AnswerSchema.flow_history_id), + ), + else_=AnswerSchema.id_from_history_id(AnswerSchema.activity_history_id), + ).label("activity_id"), + ( + AnswerSchema.source_subject_id + if subject_column == AnswerSchema.target_subject_id + else AnswerSchema.target_subject_id + ).label("subject_id"), + ) + .where( + subject_column == subject_id, + # Exclude incomplete activity flow assessments + AnswerSchema.is_flow_completed.isnot(False), + ) + .group_by("activity_id", "subject_id") + ) + return query + + async def get_submissions_by_target_subject(self, target_subject_id: uuid.UUID) -> list[dict]: + query: Query = self._query_submissions_by_subject(AnswerSchema.target_subject_id, target_subject_id) + + res = await self._execute(query) + + return res.mappings().all() + + async def get_submissions_by_respondent_subject(self, respondent_subject_id: uuid.UUID) -> list[dict]: + query: Query = self._query_submissions_by_subject(AnswerSchema.source_subject_id, respondent_subject_id) + + res = await self._execute(query) + + return res.mappings().all() diff --git a/src/apps/answers/domain/answers.py b/src/apps/answers/domain/answers.py index c3a18bfb169..8c64dd30a55 100644 --- a/src/apps/answers/domain/answers.py +++ b/src/apps/answers/domain/answers.py @@ -713,3 +713,15 @@ class FilesCopyCheckResult(InternalModel): total_files: int not_copied_files: set[str] files_to_remove: set[str] + + +class SubmissionsSubjectCounters(InternalModel): + respondents: set[uuid.UUID] = Field(default_factory=set) + subjects: set[uuid.UUID] = Field(default_factory=set) + subject_submissions_count: int = 0 + respondent_submissions_count: int = 0 + + +class SubmissionsActivityCountBySubject(InternalModel): + subject_id: uuid.UUID + activities: dict[uuid.UUID, SubmissionsSubjectCounters] = Field(default_factory=dict) diff --git a/src/apps/answers/service.py b/src/apps/answers/service.py index 06002d9a7fe..aab7ce30774 100644 --- a/src/apps/answers/service.py +++ b/src/apps/answers/service.py @@ -67,6 +67,8 @@ AppletSubmission, FilesCopyCheckResult, RespondentAnswerData, + SubmissionsActivityCountBySubject, + SubmissionsSubjectCounters, ) from apps.answers.errors import ( ActivityIsNotAssessment, @@ -102,6 +104,7 @@ from apps.subjects.crud import SubjectsCrud from apps.subjects.db.schemas import SubjectSchema from apps.subjects.domain import SubjectReadResponse +from apps.subjects.services import SubjectsService from apps.users import User, UserSchema, UsersCRUD from apps.workspaces.crud.applet_access import AppletAccessCRUD from apps.workspaces.crud.user_applet_access import UserAppletAccessCRUD @@ -1938,21 +1941,75 @@ async def get_target_subject_ids_by_respondent_and_activity_or_flow( async def get_activity_and_flow_ids_by_target_subject(self, target_subject_id: uuid.UUID) -> list[uuid.UUID]: """ - Get a list of activity and flow IDs based on answers submitted for a target subject + Get a list of activity and flow IDs based on answers submitted for a target subject. + Excludes answers whose source subject was soft-deleted. The data returned is just a combined list of activity and flow IDs, without any - distinction between the two + distinction between the two. """ - return await AnswersCRUD(self.answer_session).get_activity_and_flow_ids_by_target_subject(target_subject_id) + results = await AnswersCRUD(self.answer_session).get_activity_and_flow_ids_by_target_subject(target_subject_id) + existing_subject_ids = await self._filter_out_soft_deleted_subjects(results) + activity_ids = [result["activity_id"] for result in results if result["subject_id"] in existing_subject_ids] + + return activity_ids async def get_activity_and_flow_ids_by_source_subject(self, source_subject_id: uuid.UUID) -> list[uuid.UUID]: """ - Get a list of activity and flow IDs based on answers submitted for a source subject + Get a list of activity and flow IDs based on answers submitted for a source subject. + Excludes answers whose target subject was soft-deleted. The data returned is just a combined list of activity and flow IDs, without any - distinction between the two + distinction between the two. + """ + results = await AnswersCRUD(self.answer_session).get_activity_and_flow_ids_by_source_subject(source_subject_id) + existing_subject_ids = await self._filter_out_soft_deleted_subjects(results) + activity_ids = [result["activity_id"] for result in results if result["subject_id"] in existing_subject_ids] + + return activity_ids + + async def _filter_out_soft_deleted_subjects(self, submissions: list[dict]) -> set[uuid.UUID]: + """ + Filter out submissions whose subject_id column corresponds to soft-deleted subjects """ - return await AnswersCRUD(self.answer_session).get_activity_and_flow_ids_by_source_subject(source_subject_id) + subject_ids = set([activityOrFlow["subject_id"] for activityOrFlow in submissions]) + + assert self.user_id + existing_subjects = await SubjectsService(self.session, self.user_id).get_by_ids(list(subject_ids)) + existing_subject_ids = {subject.id for subject in existing_subjects} + + return existing_subject_ids + + async def get_submissions_by_subject(self, subject_id: uuid.UUID) -> SubmissionsActivityCountBySubject: + submissions_target_coro = AnswersCRUD(self.answer_session).get_submissions_by_target_subject(subject_id) + submissions_respondent_coro = AnswersCRUD(self.answer_session).get_submissions_by_respondent_subject(subject_id) + + submissions_target, submissions_respondent = await asyncio.gather( + submissions_target_coro, submissions_respondent_coro + ) + + existing_subject_ids = await self._filter_out_soft_deleted_subjects(submissions_target + submissions_respondent) + + submissions_activity_count = SubmissionsActivityCountBySubject(subject_id=subject_id) + + for activity_submissions in submissions_target: + activity_counters = submissions_activity_count.activities.setdefault( + uuid.UUID(activity_submissions["activity_id"]), SubmissionsSubjectCounters() + ) + respondent_subject_id = activity_submissions["subject_id"] + if respondent_subject_id in existing_subject_ids: + activity_counters.respondents.add(respondent_subject_id) + activity_counters.subject_submissions_count += activity_submissions["submission_count"] + + for activity_submissions in submissions_respondent: + activity_counters = submissions_activity_count.activities.setdefault( + uuid.UUID(activity_submissions["activity_id"]), SubmissionsSubjectCounters() + ) + target_subject_id = activity_submissions["subject_id"] + if target_subject_id in existing_subject_ids: + activity_counters.subjects.add(target_subject_id) + activity_counters.respondent_submissions_count += activity_submissions["submission_count"] + + return submissions_activity_count class ReportServerService: From 122328e6253739be62d53de46bfff557de73121f Mon Sep 17 00:00:00 2001 From: Rodrigo Colao Merlo Date: Mon, 9 Dec 2024 21:57:43 -0300 Subject: [PATCH 02/10] feature: Add Last Submission Timestamp to metadata endpoint (M2-7859) (#1676) * feature: Add Last Submission Timestamp to counters endpoint (M2-7859) * Update due metadata endpoint refactoring * Returning lastSubmissionDate separated between subject and respondent * Update deps Update deps --- Pipfile | 50 +- Pipfile.lock | 854 +++++++++---------- src/apps/activities/api/activities.py | 14 +- src/apps/activities/domain/activity.py | 2 + src/apps/activities/tests/test_activities.py | 34 +- src/apps/answers/crud/answers.py | 14 +- src/apps/answers/domain/answers.py | 4 +- src/apps/answers/service.py | 42 +- src/apps/authentication/api/auth.py | 7 +- src/apps/authentication/tests/test_auth.py | 4 +- 10 files changed, 536 insertions(+), 489 deletions(-) diff --git a/Pipfile b/Pipfile index 804cd0b2329..bd80fd374cd 100644 --- a/Pipfile +++ b/Pipfile @@ -7,16 +7,17 @@ name = "pypi" aio-pika = "==9.5.3" aiofiles = "==24.1.0" aiohttp = "==3.11.9" -alembic = "==1.13.3" +alembic = "==1.14.0" asyncpg = "==0.30.0" -azure-storage-blob = "==12.23.1" -bcrypt = "==4.2.0" -boto3 = "==1.35.54" -fastapi = "==0.115.4" +azure-storage-blob = "==12.24.0" +bcrypt = "==4.2.1" +boto3 = "==1.35.77" +fastapi = "==0.115.6" fastapi-mail = "==1.2.9" firebase-admin = "==6.5.0" httpx = "==0.28.0" jinja2 = "==3.1.4" +more-itertools = "==10.5.0" nh3 = "==0.2.19" opentelemetry-api = "==1.27.0" opentelemetry-distro = "==0.48b0" @@ -37,9 +38,10 @@ opentelemetry-sdk-extension-aws = "==2.0.2" opentelemetry-semantic-conventions = "==0.48b0" opentelemetry-test-utils = "==0.48b0" opentelemetry-util-http = "==0.48b0" -pyOpenSSL = "==24.2.1" pydantic = { extras = ["email"], version = "==1.10.18" } -pymongo = "*" +pyjwt = "==2.10.1" +pymongo = "==4.10.1" +pyOpenSSL = "==24.2.1" python-multipart = "==0.0.19" redis = "==5.2.0" sentry-sdk = "~=2.13" @@ -49,37 +51,35 @@ taskiq = { extras = ["reload"], version = "==0.11.7" } taskiq-aio-pika = "==0.4.1" taskiq-fastapi = "==0.3.2" taskiq-redis = "==1.0.2" -typer = "==0.12.5" -uvicorn = { extras = ["standard"], version = "==0.32.0" } -pyjwt = "==2.10.1" -more-itertools = "==10.5.0" +typer = "==0.15.1" +uvicorn = { extras = ["standard"], version = "==0.32.1" } [dev-packages] +allure-pytest = "==2.13.5" +cachetools = "==5.3.0" +gevent = "==24.2.1" +greenlet = "==3.1.0" ipdb = "==0.13.13" -pudb = "==2024.1.3" +mypy = "==1.13.0" +nest-asyncio = "==1.6.0" pre-commit = "==4.0.1" -ruff = "==0.7.2" -allure-pytest = "==2.13.5" +pudb = "==2024.1.3" pydantic-factories = "==1.17.3" +pyld = "==2.0.4" pytest = "==8.3.4" pytest-asyncio = "~=0.19" pytest-cov = "==6.0.0" pytest-env = "==1.1.5" pytest-lazy-fixtures = "==1.1.1" pytest-mock = "==3.14.0" -nest-asyncio = "==1.6.0" -gevent = "==24.11.1" -mypy = "==1.13.0" -types-python-dateutil = "==2.9.0.20241003" -typing-extensions = "==4.12.2" -types-requests = "==2.32.0.20241016" -types-pytz = "==2024.2.0.20241003" +reproschema = "==0.6.2" +ruff = "==0.8.2" types-aiofiles = "==24.1.0.20240626" types-cachetools = "==5.5.0.20240820" -greenlet = "==3.1.0" -reproschema = "0.9.0" -cachetools = "==5.3.0" -pyld = "==2.0.4" +types-python-dateutil = "==2.9.0.20241206 " +types-pytz = "==2024.2.0.20241003" +types-requests = "==2.32.0.20241016" +typing-extensions = "==4.12.2" [requires] python_version = "3.11" diff --git a/Pipfile.lock b/Pipfile.lock index 0cea16b642c..2d6005f6f8c 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "578bf8ce82875f3bc65c46c8dada7a184f74af54b6b702f5ed24f949e13f0177" + "sha256": "8372ca972d5ba9b60fc31e38f4767a9ac379a32b80a59bbfbeb4f9f4fbd26444" }, "pipfile-spec": 6, "requires": { @@ -151,20 +151,20 @@ }, "alembic": { "hashes": [ - "sha256:203503117415561e203aa14541740643a611f641517f0209fcae63e9fa09f1a2", - "sha256:908e905976d15235fae59c9ac42c4c5b75cfcefe3d27c0fbf7ae15a37715d80e" + "sha256:99bd884ca390466db5e27ffccff1d179ec5c05c965cfefc0607e69f9e411cb25", + "sha256:b00892b53b3642d0b8dbedba234dbf1924b69be83a9a769d5a624b01094e304b" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==1.13.3" + "version": "==1.14.0" }, "anyio": { "hashes": [ - "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c", - "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d" + "sha256:2f834749c602966b7d456a7567cafcb309f96482b5081d14ac93ccd457f9dd48", + "sha256:ea60c3723ab42ba6fff7e8ccb0488c898ec538ff4df1f1d5e642c3601d07e352" ], "markers": "python_version >= '3.9'", - "version": "==4.6.2.post1" + "version": "==4.7.0" }, "asgiref": { "hashes": [ @@ -248,79 +248,77 @@ }, "azure-storage-blob": { "hashes": [ - "sha256:1c2238aa841d1545f42714a5017c010366137a44a0605da2d45f770174bfc6b4", - "sha256:a587e54d4e39d2a27bd75109db164ffa2058fe194061e5446c5a89bca918272f" + "sha256:4f0bb4592ea79a2d986063696514c781c9e62be240f09f6397986e01755bc071", + "sha256:eaaaa1507c8c363d6e1d1342bd549938fdf1adec9b1ada8658c8f5bf3aea844e" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==12.23.1" + "version": "==12.24.0" }, "bcrypt": { "hashes": [ - "sha256:096a15d26ed6ce37a14c1ac1e48119660f21b24cba457f160a4b830f3fe6b5cb", - "sha256:0da52759f7f30e83f1e30a888d9163a81353ef224d82dc58eb5bb52efcabc399", - "sha256:1bb429fedbe0249465cdd85a58e8376f31bb315e484f16e68ca4c786dcc04291", - "sha256:1d84cf6d877918620b687b8fd1bf7781d11e8a0998f576c7aa939776b512b98d", - "sha256:1ee38e858bf5d0287c39b7a1fc59eec64bbf880c7d504d3a06a96c16e14058e7", - "sha256:1ff39b78a52cf03fdf902635e4c81e544714861ba3f0efc56558979dd4f09170", - "sha256:27fe0f57bb5573104b5a6de5e4153c60814c711b29364c10a75a54bb6d7ff48d", - "sha256:3413bd60460f76097ee2e0a493ccebe4a7601918219c02f503984f0a7ee0aebe", - "sha256:3698393a1b1f1fd5714524193849d0c6d524d33523acca37cd28f02899285060", - "sha256:373db9abe198e8e2c70d12b479464e0d5092cc122b20ec504097b5f2297ed184", - "sha256:39e1d30c7233cfc54f5c3f2c825156fe044efdd3e0b9d309512cc514a263ec2a", - "sha256:3bbbfb2734f0e4f37c5136130405332640a1e46e6b23e000eeff2ba8d005da68", - "sha256:3d3a6d28cb2305b43feac298774b997e372e56c7c7afd90a12b3dc49b189151c", - "sha256:5a1e8aa9b28ae28020a3ac4b053117fb51c57a010b9f969603ed885f23841458", - "sha256:61ed14326ee023917ecd093ee6ef422a72f3aec6f07e21ea5f10622b735538a9", - "sha256:655ea221910bcac76ea08aaa76df427ef8625f92e55a8ee44fbf7753dbabb328", - "sha256:762a2c5fb35f89606a9fde5e51392dad0cd1ab7ae64149a8b935fe8d79dd5ed7", - "sha256:77800b7147c9dc905db1cba26abe31e504d8247ac73580b4aa179f98e6608f34", - "sha256:8ac68872c82f1add6a20bd489870c71b00ebacd2e9134a8aa3f98a0052ab4b0e", - "sha256:8d7bb9c42801035e61c109c345a28ed7e84426ae4865511eb82e913df18f58c2", - "sha256:8f6ede91359e5df88d1f5c1ef47428a4420136f3ce97763e31b86dd8280fbdf5", - "sha256:9c1c4ad86351339c5f320ca372dfba6cb6beb25e8efc659bedd918d921956bae", - "sha256:c02d944ca89d9b1922ceb8a46460dd17df1ba37ab66feac4870f6862a1533c00", - "sha256:c52aac18ea1f4a4f65963ea4f9530c306b56ccd0c6f8c8da0c06976e34a6e841", - "sha256:cb2a8ec2bc07d3553ccebf0746bbf3d19426d1c6d1adbd4fa48925f66af7b9e8", - "sha256:cf69eaf5185fd58f268f805b505ce31f9b9fc2d64b376642164e9244540c1221", - "sha256:f4f4acf526fcd1c34e7ce851147deedd4e26e6402369304220250598b26448db" + "sha256:041fa0155c9004eb98a232d54da05c0b41d4b8e66b6fc3cb71b4b3f6144ba837", + "sha256:04e56e3fe8308a88b77e0afd20bec516f74aecf391cdd6e374f15cbed32783d6", + "sha256:1340411a0894b7d3ef562fb233e4b6ed58add185228650942bdc885362f32c17", + "sha256:533e7f3bcf2f07caee7ad98124fab7499cb3333ba2274f7a36cf1daee7409d99", + "sha256:6765386e3ab87f569b276988742039baab087b2cdb01e809d74e74503c2faafe", + "sha256:687cf30e6681eeda39548a93ce9bfbb300e48b4d445a43db4298d2474d2a1e54", + "sha256:76132c176a6d9953cdc83c296aeaed65e1a708485fd55abf163e0d9f8f16ce0e", + "sha256:76d3e352b32f4eeb34703370e370997065d28a561e4a18afe4fef07249cb4396", + "sha256:807261df60a8b1ccd13e6599c779014a362ae4e795f5c59747f60208daddd96d", + "sha256:89df2aea2c43be1e1fa066df5f86c8ce822ab70a30e4c210968669565c0f4685", + "sha256:8ad2f4528cbf0febe80e5a3a57d7a74e6635e41af1ea5675282a33d769fba413", + "sha256:8c458cd103e6c5d1d85cf600e546a639f234964d0228909d8f8dbeebff82d526", + "sha256:8dbd0747208912b1e4ce730c6725cb56c07ac734b3629b60d4398f082ea718ad", + "sha256:909faa1027900f2252a9ca5dfebd25fc0ef1417943824783d1c8418dd7d6df4a", + "sha256:aaa2e285be097050dba798d537b6efd9b698aa88eef52ec98d23dcd6d7cf6fea", + "sha256:adadd36274510a01f33e6dc08f5824b97c9580583bd4487c564fc4617b328005", + "sha256:b1ee315739bc8387aa36ff127afc99120ee452924e0df517a8f3e4c0187a0f5f", + "sha256:b588af02b89d9fad33e5f98f7838bf590d6d692df7153647724a7f20c186f6bf", + "sha256:b7703ede632dc945ed1172d6f24e9f30f27b1b1a067f32f68bf169c5f08d0425", + "sha256:c6f5fa3775966cca251848d4d5393ab016b3afed251163c1436fefdec3b02c84", + "sha256:cde78d385d5e93ece5479a0a87f73cd6fa26b171c786a884f955e165032b262c", + "sha256:cfdf3d7530c790432046c40cda41dfee8c83e29482e6a604f8930b9930e94139", + "sha256:e158009a54c4c8bc91d5e0da80920d048f918c61a581f0a63e4e93bb556d362f", + "sha256:e84e0e6f8e40a242b11bce56c313edc2be121cec3e0ec2d76fce01f6af33c07c", + "sha256:f85b1ffa09240c89aa2e1ae9f3b1c687104f7b2b9d2098da4e923f1b7082d331" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==4.2.0" + "version": "==4.2.1" }, "blinker": { "hashes": [ - "sha256:1779309f71bf239144b9399d06ae925637cf6634cf6bd131104184531bf67c01", - "sha256:8f77b09d3bf7c795e969e9486f39c2c5e9c39d4ee07424be2bc594ece9642d83" + "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", + "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc" ], - "markers": "python_version >= '3.8'", - "version": "==1.8.2" + "markers": "python_version >= '3.9'", + "version": "==1.9.0" }, "boto3": { "hashes": [ - "sha256:2d5e160b614db55fbee7981001c54476cb827c441cef65b2fcb2c52a62019909", - "sha256:7d9c359bbbc858a60b51c86328db813353c8bd1940212cdbd0a7da835291c2e1" + "sha256:a09871805f8e462349a1c33c23eb413668df0bf68424e61d53518e1a7d883b2f", + "sha256:cc819cdbccbc2d0dc185f1dcfe74cf3809489c4cae63c2e5d6a557aa0c5ab928" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==1.35.54" + "version": "==1.35.77" }, "botocore": { "hashes": [ - "sha256:131bb59ce59c8a939b31e8e647242d70cf11d32d4529fa4dca01feea1e891a76", - "sha256:9cca1811094b6cdc144c2c063a3ec2db6d7c88194b04d4277cd34fc8e3473aff" + "sha256:17b778016644e9342ca3ff2f430c1d1db0c6126e9b41a57cff52ac58e7a455e0", + "sha256:3faa27d65841499762228902d7e215fa99a4c2fdc76c9113e1c3f339bdf685b8" ], "markers": "python_version >= '3.8'", - "version": "==1.35.54" + "version": "==1.35.77" }, "cachecontrol": { "hashes": [ - "sha256:7db1195b41c81f8274a7bbd97c956f44e8348265a1bc7641c37dfebc39f0c938", - "sha256:f5bf3f0620c38db2e5122c0726bdebb0d16869de966ea6a2befe92470b740ea0" + "sha256:06ef916a1e4eb7dba9948cdfc9c76e749db2e02104a9a1277e8b642591a0f717", + "sha256:65e3abd62b06382ce3894df60dde9e0deb92aeb734724f68fa4f3b91e97206b9" ], - "markers": "python_version >= '3.7'", - "version": "==0.14.0" + "markers": "python_version >= '3.8'", + "version": "==0.14.1" }, "cachetools": { "hashes": [ @@ -565,11 +563,11 @@ }, "deprecated": { "hashes": [ - "sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c", - "sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3" + "sha256:353bc4a8ac4bfc96800ddab349d89c25dec1079f65fd53acdcc1e0b975b21320", + "sha256:683e561a90de76239796e6b6feac66b99030d2dd3fcf61ef996330f14bbb9b0d" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.2.14" + "version": "==1.2.15" }, "dnspython": { "hashes": [ @@ -597,12 +595,12 @@ }, "fastapi": { "hashes": [ - "sha256:0b504a063ffb3cf96a5e27dc1bc32c80ca743a2528574f9cdc77daa2d31b4742", - "sha256:db653475586b091cb8b2fec2ac54a680ac6a158e07406e1abae31679e8826349" + "sha256:9ec46f7addc14ea472958a96aae5b5de65f39721a46aaf5705c480d9a8b76654", + "sha256:e9240b29e36fa8f4bb7290316988e90c381e5092e0cbe84e7818cc3713bcf305" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==0.115.4" + "version": "==0.115.6" }, "fastapi-mail": { "hashes": [ @@ -731,27 +729,27 @@ "grpc" ], "hashes": [ - "sha256:4a152fd11a9f774ea606388d423b68aa7e6d6a0ffe4c8266f74979613ec09f81", - "sha256:6869eacb2a37720380ba5898312af79a4d30b8bca1548fb4093e0697dc4bdf5d" + "sha256:10d82ac0fca69c82a25b3efdeefccf6f28e02ebb97925a8cce8edbfe379929d9", + "sha256:e255640547a597a4da010876d333208ddac417d60add22b6851a0c66a831fcaf" ], - "markers": "platform_python_implementation != 'PyPy'", - "version": "==2.21.0" + "markers": "python_version >= '3.7'", + "version": "==2.24.0" }, "google-api-python-client": { "hashes": [ - "sha256:1a5232e9cfed8c201799d9327e4d44dc7ea7daa3c6e1627fca41aa201539c0da", - "sha256:b9d68c6b14ec72580d66001bd33c5816b78e2134b93ccc5cf8f624516b561750" + "sha256:1b420062e03bfcaa1c79e2e00a612d29a6a934151ceb3d272fe150a656dc8f17", + "sha256:a521bbbb2ec0ba9d6f307cdd64ed6e21eeac372d1bd7493a4ab5022941f784ad" ], "markers": "python_version >= '3.7'", - "version": "==2.149.0" + "version": "==2.154.0" }, "google-auth": { "hashes": [ - "sha256:25df55f327ef021de8be50bad0dfd4a916ad0de96da86cd05661c9297723ad3f", - "sha256:f4c64ed4e01e8e8b646ef34c018f8bf3338df0c8e37d8b3bba40e7f574a3278a" + "sha256:51a15d47028b66fd36e5c64a82d2d57480075bccc7da37cde257fc94177a61fb", + "sha256:545e9618f2df0bcbb7dcbc45a546485b1212624716975a1ea5ae8149ce769ab1" ], "markers": "python_version >= '3.7'", - "version": "==2.35.0" + "version": "==2.36.0" }, "google-auth-httplib2": { "hashes": [ @@ -773,16 +771,16 @@ "sha256:1b2ce6e0b791aee89a1e4f072beba1012247e89baca361eed721fb467fe054b0", "sha256:b49f0019d7bd0d4ab5972a4cff13994b0aabe72d24242200d904db2fb49df7f7" ], - "markers": "platform_python_implementation != 'PyPy'", + "markers": "python_version >= '3.7'", "version": "==2.19.0" }, "google-cloud-storage": { "hashes": [ - "sha256:97a4d45c368b7d401ed48c4fdfe86e1e1cb96401c9e199e419d289e2c0370166", - "sha256:aaf7acd70cdad9f274d29332673fcab98708d0e1f4dceb5a5356aaef06af4d99" + "sha256:aeb971b5c29cf8ab98445082cbfe7b161a1f48ed275822f59ed3f1524ea54fba", + "sha256:cd05e9e7191ba6cb68934d8eb76054d9be4562aa89dbc4236feee4d7d51342b2" ], "markers": "python_version >= '3.7'", - "version": "==2.18.2" + "version": "==2.19.0" }, "google-crc32c": { "hashes": [ @@ -827,11 +825,11 @@ }, "googleapis-common-protos": { "hashes": [ - "sha256:2972e6c496f435b92590fd54045060867f3fe9be2c82ab148fc8885035479a63", - "sha256:334a29d07cddc3aa01dee4988f9afd9b2916ee2ff49d6b757155dc0d197852c0" + "sha256:c3e7b33d15fdca5374cc0a7346dd92ffa847425cc4ea941d970f13680052ec8c", + "sha256:d7abcd75fabb2e0ec9f74466401f6c119a0b498e27370e9be4c94cb7e382b8ed" ], "markers": "python_version >= '3.7'", - "version": "==1.65.0" + "version": "==1.66.0" }, "greenlet": { "hashes": [ @@ -909,74 +907,76 @@ "sha256:f406b22b7c9a9b4f8aa9d2ab13d6ae0ac3e85c9a809bd590ad53fed2bf70dc79", "sha256:f6ff3b14f2df4c41660a7dec01045a045653998784bf8cfcb5a525bdffffbc8f" ], + "markers": "python_version >= '3.7'", "version": "==3.1.1" }, "grpcio": { "hashes": [ - "sha256:014dfc020e28a0d9be7e93a91f85ff9f4a87158b7df9952fe23cc42d29d31e1e", - "sha256:0892dd200ece4822d72dd0952f7112c542a487fc48fe77568deaaa399c1e717d", - "sha256:0bb94e66cd8f0baf29bd3184b6aa09aeb1a660f9ec3d85da615c5003154bc2bf", - "sha256:0c69bf11894cad9da00047f46584d5758d6ebc9b5950c0dc96fec7e0bce5cde9", - "sha256:15c05a26a0f7047f720da41dc49406b395c1470eef44ff7e2c506a47ac2c0591", - "sha256:16724ffc956ea42967f5758c2f043faef43cb7e48a51948ab593570570d1e68b", - "sha256:227316b5631260e0bef8a3ce04fa7db4cc81756fea1258b007950b6efc90c05d", - "sha256:2b7183c80b602b0ad816315d66f2fb7887614ead950416d60913a9a71c12560d", - "sha256:2f55c1e0e2ae9bdd23b3c63459ee4c06d223b68aeb1961d83c48fb63dc29bc03", - "sha256:30d47dbacfd20cbd0c8be9bfa52fdb833b395d4ec32fe5cff7220afc05d08571", - "sha256:323741b6699cd2b04a71cb38f502db98f90532e8a40cb675393d248126a268af", - "sha256:3840994689cc8cbb73d60485c594424ad8adb56c71a30d8948d6453083624b52", - "sha256:391df8b0faac84d42f5b8dfc65f5152c48ed914e13c522fd05f2aca211f8bfad", - "sha256:42199e704095b62688998c2d84c89e59a26a7d5d32eed86d43dc90e7a3bd04aa", - "sha256:54d16383044e681f8beb50f905249e4e7261dd169d4aaf6e52eab67b01cbbbe2", - "sha256:5a1e03c3102b6451028d5dc9f8591131d6ab3c8a0e023d94c28cb930ed4b5f81", - "sha256:62492bd534979e6d7127b8a6b29093161a742dee3875873e01964049d5250a74", - "sha256:662c8e105c5e5cee0317d500eb186ed7a93229586e431c1bf0c9236c2407352c", - "sha256:682968427a63d898759474e3b3178d42546e878fdce034fd7474ef75143b64e3", - "sha256:74b900566bdf68241118f2918d312d3bf554b2ce0b12b90178091ea7d0a17b3d", - "sha256:77196216d5dd6f99af1c51e235af2dd339159f657280e65ce7e12c1a8feffd1d", - "sha256:7f200aca719c1c5dc72ab68be3479b9dafccdf03df530d137632c534bb6f1ee3", - "sha256:7fc1d2b9fd549264ae585026b266ac2db53735510a207381be509c315b4af4e8", - "sha256:82e5bd4b67b17c8c597273663794a6a46a45e44165b960517fe6d8a2f7f16d23", - "sha256:8c9a35b8bc50db35ab8e3e02a4f2a35cfba46c8705c3911c34ce343bd777813a", - "sha256:985b2686f786f3e20326c4367eebdaed3e7aa65848260ff0c6644f817042cb15", - "sha256:9d75641a2fca9ae1ae86454fd25d4c298ea8cc195dbc962852234d54a07060ad", - "sha256:a4e95e43447a02aa603abcc6b5e727d093d161a869c83b073f50b9390ecf0fa8", - "sha256:a6b9a5c18863fd4b6624a42e2712103fb0f57799a3b29651c0e5b8119a519d65", - "sha256:aa8d025fae1595a207b4e47c2e087cb88d47008494db258ac561c00877d4c8f8", - "sha256:ac11ecb34a86b831239cc38245403a8de25037b448464f95c3315819e7519772", - "sha256:ae6de510f670137e755eb2a74b04d1041e7210af2444103c8c95f193340d17ee", - "sha256:b2a44e572fb762c668e4812156b81835f7aba8a721b027e2d4bb29fb50ff4d33", - "sha256:b6eb68493a05d38b426604e1dc93bfc0137c4157f7ab4fac5771fd9a104bbaa6", - "sha256:b9bca3ca0c5e74dea44bf57d27e15a3a3996ce7e5780d61b7c72386356d231db", - "sha256:bd79929b3bb96b54df1296cd3bf4d2b770bd1df6c2bdf549b49bab286b925cdc", - "sha256:c4c425f440fb81f8d0237c07b9322fc0fb6ee2b29fbef5f62a322ff8fcce240d", - "sha256:cb204a742997277da678611a809a8409657b1398aaeebf73b3d9563b7d154c13", - "sha256:cf51d28063338608cd8d3cd64677e922134837902b70ce00dad7f116e3998210", - "sha256:cfd9306511fdfc623a1ba1dc3bc07fbd24e6cfbe3c28b4d1e05177baa2f99617", - "sha256:cff8e54d6a463883cda2fab94d2062aad2f5edd7f06ae3ed030f2a74756db365", - "sha256:d01793653248f49cf47e5695e0a79805b1d9d4eacef85b310118ba1dfcd1b955", - "sha256:d4ea4509d42c6797539e9ec7496c15473177ce9abc89bc5c71e7abe50fc25737", - "sha256:d90cfdafcf4b45a7a076e3e2a58e7bc3d59c698c4f6470b0bb13a4d869cf2273", - "sha256:e090b2553e0da1c875449c8e75073dd4415dd71c9bde6a406240fdf4c0ee467c", - "sha256:e91d154689639932305b6ea6f45c6e46bb51ecc8ea77c10ef25aa77f75443ad4", - "sha256:eef1dce9d1a46119fd09f9a992cf6ab9d9178b696382439446ca5f399d7b96fe", - "sha256:efe32b45dd6d118f5ea2e5deaed417d8a14976325c93812dd831908522b402c9", - "sha256:f4d613fbf868b2e2444f490d18af472ccb47660ea3df52f068c9c8801e1f3e85", - "sha256:f55f077685f61f0fbd06ea355142b71e47e4a26d2d678b3ba27248abfe67163a", - "sha256:f623c57a5321461c84498a99dddf9d13dac0e40ee056d884d6ec4ebcab647a78", - "sha256:f6bd2ab135c64a4d1e9e44679a616c9bc944547357c830fafea5c3caa3de5153", - "sha256:f95e15db43e75a534420e04822df91f645664bf4ad21dfaad7d51773c80e6bb4", - "sha256:fd6bc27861e460fe28e94226e3673d46e294ca4673d46b224428d197c5935e69", - "sha256:fe89295219b9c9e47780a0f1c75ca44211e706d1c598242249fe717af3385ec8" - ], - "markers": "python_version >= '3.8'", - "version": "==1.67.0" + "sha256:025f790c056815b3bf53da850dd70ebb849fd755a4b1ac822cb65cd631e37d43", + "sha256:04cfd68bf4f38f5bb959ee2361a7546916bd9a50f78617a346b3aeb2b42e2161", + "sha256:0feb02205a27caca128627bd1df4ee7212db051019a9afa76f4bb6a1a80ca95e", + "sha256:1098f03dedc3b9810810568060dea4ac0822b4062f537b0f53aa015269be0a76", + "sha256:12941d533f3cd45d46f202e3667be8ebf6bcb3573629c7ec12c3e211d99cfccf", + "sha256:255b1635b0ed81e9f91da4fcc8d43b7ea5520090b9a9ad9340d147066d1d3613", + "sha256:298ee7f80e26f9483f0b6f94cc0a046caf54400a11b644713bb5b3d8eb387600", + "sha256:2c4cec6177bf325eb6faa6bd834d2ff6aa8bb3b29012cceb4937b86f8b74323c", + "sha256:2cc1fd04af8399971bcd4f43bd98c22d01029ea2e56e69c34daf2bf8470e47f5", + "sha256:334ab917792904245a028f10e803fcd5b6f36a7b2173a820c0b5b076555825e1", + "sha256:3522c77d7e6606d6665ec8d50e867f13f946a4e00c7df46768f1c85089eae515", + "sha256:37ea3be171f3cf3e7b7e412a98b77685eba9d4fd67421f4a34686a63a65d99f9", + "sha256:390eee4225a661c5cd133c09f5da1ee3c84498dc265fd292a6912b65c421c78c", + "sha256:3aed6544e4d523cd6b3119b0916cef3d15ef2da51e088211e4d1eb91a6c7f4f1", + "sha256:3ceb56c4285754e33bb3c2fa777d055e96e6932351a3082ce3559be47f8024f0", + "sha256:44a8502dd5de653ae6a73e2de50a401d84184f0331d0ac3daeb044e66d5c5054", + "sha256:4b177f5547f1b995826ef529d2eef89cca2f830dd8b2c99ffd5fde4da734ba73", + "sha256:4efac5481c696d5cb124ff1c119a78bddbfdd13fc499e3bc0ca81e95fc573684", + "sha256:52fbf85aa71263380d330f4fce9f013c0798242e31ede05fcee7fbe40ccfc20d", + "sha256:55857c71641064f01ff0541a1776bfe04a59db5558e82897d35a7793e525774c", + "sha256:66a24f3d45c33550703f0abb8b656515b0ab777970fa275693a2f6dc8e35f1c1", + "sha256:6ab2d912ca39c51f46baf2a0d92aa265aa96b2443266fc50d234fa88bf877d8e", + "sha256:77d65165fc35cff6e954e7fd4229e05ec76102d4406d4576528d3a3635fc6172", + "sha256:7dfc914cc31c906297b30463dde0b9be48e36939575eaf2a0a22a8096e69afe5", + "sha256:7f20ebec257af55694d8f993e162ddf0d36bd82d4e57f74b31c67b3c6d63d8b2", + "sha256:80af6f1e69c5e68a2be529990684abdd31ed6622e988bf18850075c81bb1ad6e", + "sha256:83bbf5807dc3ee94ce1de2dfe8a356e1d74101e4b9d7aa8c720cc4818a34aded", + "sha256:8720c25cd9ac25dd04ee02b69256d0ce35bf8a0f29e20577427355272230965a", + "sha256:8829924fffb25386995a31998ccbbeaa7367223e647e0122043dfc485a87c666", + "sha256:8a3869a6661ec8f81d93f4597da50336718bde9eb13267a699ac7e0a1d6d0bea", + "sha256:8cb620037a2fd9eeee97b4531880e439ebfcd6d7d78f2e7dcc3726428ab5ef63", + "sha256:919d7f18f63bcad3a0f81146188e90274fde800a94e35d42ffe9eadf6a9a6330", + "sha256:95c87ce2a97434dffe7327a4071839ab8e8bffd0054cc74cbe971fba98aedd60", + "sha256:963cc8d7d79b12c56008aabd8b457f400952dbea8997dd185f155e2f228db079", + "sha256:96f473cdacfdd506008a5d7579c9f6a7ff245a9ade92c3c0265eb76cc591914f", + "sha256:9d1fae6bbf0816415b81db1e82fb3bf56f7857273c84dcbe68cbe046e58e1ccd", + "sha256:a0c8ddabef9c8f41617f213e527254c41e8b96ea9d387c632af878d05db9229c", + "sha256:a1b988b40f2fd9de5c820f3a701a43339d8dcf2cb2f1ca137e2c02671cc83ac1", + "sha256:a47faedc9ea2e7a3b6569795c040aae5895a19dde0c728a48d3c5d7995fda385", + "sha256:a8040f85dcb9830d8bbb033ae66d272614cec6faceee88d37a88a9bd1a7a704e", + "sha256:b33bd114fa5a83f03ec6b7b262ef9f5cac549d4126f1dc702078767b10c46ed9", + "sha256:c08079b4934b0bf0a8847f42c197b1d12cba6495a3d43febd7e99ecd1cdc8d54", + "sha256:c28848761a6520c5c6071d2904a18d339a796ebe6b800adc8b3f474c5ce3c3ad", + "sha256:cb400138e73969eb5e0535d1d06cae6a6f7a15f2cc74add320e2130b8179211a", + "sha256:cbb5780e2e740b6b4f2d208e90453591036ff80c02cc605fea1af8e6fc6b1bbe", + "sha256:ccf2ebd2de2d6661e2520dae293298a3803a98ebfc099275f113ce1f6c2a80f1", + "sha256:d35740e3f45f60f3c37b1e6f2f4702c23867b9ce21c6410254c9c682237da68d", + "sha256:d99abcd61760ebb34bdff37e5a3ba333c5cc09feda8c1ad42547bea0416ada78", + "sha256:ddda1aa22495d8acd9dfbafff2866438d12faec4d024ebc2e656784d96328ad0", + "sha256:dffd29a2961f3263a16d73945b57cd44a8fd0b235740cb14056f0612329b345e", + "sha256:e4842e4872ae4ae0f5497bf60a0498fa778c192cc7a9e87877abd2814aca9475", + "sha256:e8dbe3e00771bfe3d04feed8210fc6617006d06d9a2679b74605b9fed3e8362c", + "sha256:ee2e743e51cb964b4975de572aa8fb95b633f496f9fcb5e257893df3be854746", + "sha256:eeb38ff04ab6e5756a2aef6ad8d94e89bb4a51ef96e20f45c44ba190fa0bcaad", + "sha256:f8261fa2a5f679abeb2a0a93ad056d765cdca1c47745eda3f2d87f874ff4b8c9" + ], + "markers": "python_version >= '3.8'", + "version": "==1.68.1" }, "grpcio-status": { "hashes": [ "sha256:289bdd7b2459794a12cf95dc0cb727bd4a1742c37bd823f760236c937e53a485", "sha256:f9049b762ba8de6b1086789d8315846e094edac2c50beaf462338b301a8fd4b8" ], + "markers": "python_version >= '3.6'", "version": "==1.62.3" }, "h11": { @@ -1104,11 +1104,11 @@ }, "mako": { "hashes": [ - "sha256:9ec3a1583713479fae654f83ed9fa8c9a4c16b7bb0daba0e6bbebff50c0d983d", - "sha256:a91198468092a2f1a0de86ca92690fb0cfc43ca90ee17e15d93662b4c04b241a" + "sha256:42f48953c7eb91332040ff567eb7eea69b22e7a4affbc5ba8e845e8f730f6627", + "sha256:577b97e414580d3e088d47c2dbbe9594aa7a5146ed2875d4dfa9075af2dd3cc8" ], "markers": "python_version >= '3.8'", - "version": "==1.3.6" + "version": "==1.3.8" }, "markdown-it-py": { "hashes": [ @@ -1605,11 +1605,11 @@ }, "packaging": { "hashes": [ - "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", - "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124" + "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", + "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f" ], "markers": "python_version >= '3.8'", - "version": "==24.1" + "version": "==24.2" }, "pamqp": { "hashes": [ @@ -1916,7 +1916,7 @@ "sha256:93d9577b88da0bbea8cc8334ee8b918ed014968fd2ec383e868fb8afb1ccef84", "sha256:cbf74e27246d595d9a74b186b810f6fbb86726dbf3b9532efb343f6d7294fe9c" ], - "markers": "python_version > '3.0'", + "markers": "python_version >= '3.9'", "version": "==3.2.0" }, "python-dateutil": { @@ -2045,28 +2045,28 @@ }, "s3transfer": { "hashes": [ - "sha256:263ed587a5803c6c708d3ce44dc4dfedaab4c1a32e8329bab818933d79ddcf5d", - "sha256:4f50ed74ab84d474ce614475e0b8d5047ff080810aac5d01ea25231cfc944b0c" + "sha256:244a76a24355363a68164241438de1b72f8781664920260c48465896b712a41e", + "sha256:29edc09801743c21eb5ecbc617a152df41d3c287f67b615f73e5f750583666a7" ], "markers": "python_version >= '3.8'", - "version": "==0.10.3" + "version": "==0.10.4" }, "sentry-sdk": { "hashes": [ - "sha256:7b0b3b709dee051337244a09a30dbf6e95afe0d34a1f8b430d45e0982a7c125b", - "sha256:ee4a4d2ae8bfe3cac012dcf3e4607975904c137e1738116549fc3dbbb6ff0e36" + "sha256:467df6e126ba242d39952375dd816fbee0f217d119bf454a8ce74cf1e7909e8d", + "sha256:ebdc08228b4d131128e568d696c210d846e5b9d70aa0327dec6b1272d9d40b84" ], "index": "pypi", "markers": "python_version >= '3.6'", - "version": "==2.19.0" + "version": "==2.19.2" }, "setuptools": { "hashes": [ - "sha256:753bb6ebf1f465a1912e19ed1d41f403a79173a9acf66a42e7e6aec45c3c16ec", - "sha256:a7fcb66f68b4d9e8e66b42f9876150a3371558f98fa32222ffaa5bced76406f8" + "sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6", + "sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d" ], - "markers": "python_version >= '3.8'", - "version": "==75.2.0" + "markers": "python_version >= '3.9'", + "version": "==75.6.0" }, "shellingham": { "hashes": [ @@ -2078,11 +2078,11 @@ }, "six": { "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", + "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", - "version": "==1.16.0" + "version": "==1.17.0" }, "sniffio": { "hashes": [ @@ -2156,11 +2156,11 @@ }, "starlette": { "hashes": [ - "sha256:9834fd799d1a87fd346deb76158668cfa0b0d56f85caefe8268e2d97c3468b62", - "sha256:fbc189474b4731cf30fcef52f18a8d070e3f3b46c6a04c97579e85e6ffca942d" + "sha256:0e4ab3d16522a255be6b28260b938eae2482f98ce5cc934cb08dce8dc3ba5835", + "sha256:44cedb2b7c77a9de33a8b74b2b90e9f50d11fcf25d8270ea525ad71a25374ff7" ], "markers": "python_version >= '3.8'", - "version": "==0.41.2" + "version": "==0.41.3" }, "taskiq": { "extras": [ @@ -2184,11 +2184,11 @@ }, "taskiq-dependencies": { "hashes": [ - "sha256:04546a5786e0f8cb2e008af19cdf415dd27d63d6d29ccf15eda8fa6b8b6b8006", - "sha256:8b10d2635a8ada8774f1b555e0a6d72c4fb5e6089601858d38dd95ff6d214a4c" + "sha256:5756690fd9f1f9efac34aac5959f173724e898a852de790238f97090467c4e3c", + "sha256:fba4dbaac47dfc8817fd2efeb13cefe41f45790b4871ba65fcdfd3c74f7121dc" ], - "markers": "python_full_version >= '3.8.1' and python_full_version < '4.0.0'", - "version": "==1.5.4" + "markers": "python_version >= '3.9' and python_version < '4.0'", + "version": "==1.5.6" }, "taskiq-fastapi": { "hashes": [ @@ -2210,12 +2210,12 @@ }, "typer": { "hashes": [ - "sha256:62fe4e471711b147e3365034133904df3e235698399bc4de2b36c8579298d52b", - "sha256:f592f089bedcc8ec1b974125d64851029c3b1af145f04aca64d69410f0c9b722" + "sha256:7994fb7b8155b64d3402518560648446072864beefd44aa2dc36972a5972e847", + "sha256:a0588c0a7fa68a1978a069818657778f86abe6ff5ea6abf472f940a08bfe4f0a" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==0.12.5" + "version": "==0.15.1" }, "typing-extensions": { "hashes": [ @@ -2246,11 +2246,11 @@ "standard" ], "hashes": [ - "sha256:60b8f3a5ac027dcd31448f411ced12b5ef452c646f76f02f8cc3f25d8d26fd82", - "sha256:f78b36b143c16f54ccdb8190d0a26b5f1901fe5a3c777e1ab29f26391af8551e" + "sha256:82ad92fd58da0d12af7482ecdb5f2470a04c9c9a53ced65b9bbb4a205377602e", + "sha256:ee9519c246a72b1c084cea8d3b44ed6026e78a4a309cbedae9c37e4cb9fbb175" ], "markers": "python_version >= '3.8'", - "version": "==0.32.0" + "version": "==0.32.1" }, "uvloop": { "hashes": [ @@ -2326,6 +2326,7 @@ "sha256:ea5d86d1bcf4a9d24610aa2f6f25492f441960cf04aed2bd9a97db439b643a7b", "sha256:efe3252137392a471a2174d721e1037a0e6a5da7beb72a021e662b7000a9903f" ], + "markers": "python_version >= '3.6'", "version": "==2.3.1" }, "watchfiles": { @@ -2482,79 +2483,74 @@ }, "wrapt": { "hashes": [ - "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc", - "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81", - "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09", - "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e", - "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca", - "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0", - "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb", - "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487", - "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40", - "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c", - "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060", - "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202", - "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41", - "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9", - "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b", - "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664", - "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d", - "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362", - "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00", - "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc", - "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1", - "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267", - "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956", - "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966", - "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1", - "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228", - "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72", - "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d", - "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292", - "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0", - "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0", - "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36", - "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c", - "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5", - "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f", - "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73", - "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b", - "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2", - "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593", - "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39", - "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389", - "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf", - "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf", - "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89", - "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c", - "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c", - "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f", - "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440", - "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465", - "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136", - "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b", - "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8", - "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3", - "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8", - "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6", - "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e", - "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f", - "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c", - "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e", - "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8", - "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2", - "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020", - "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35", - "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d", - "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3", - "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537", - "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809", - "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d", - "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a", - "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4" - ], - "markers": "python_version >= '3.6'", - "version": "==1.16.0" + "sha256:0229b247b0fc7dee0d36176cbb79dbaf2a9eb7ecc50ec3121f40ef443155fb1d", + "sha256:0698d3a86f68abc894d537887b9bbf84d29bcfbc759e23f4644be27acf6da301", + "sha256:0a0a1a1ec28b641f2a3a2c35cbe86c00051c04fffcfcc577ffcdd707df3f8635", + "sha256:0b48554952f0f387984da81ccfa73b62e52817a4386d070c75e4db7d43a28c4a", + "sha256:0f2a28eb35cf99d5f5bd12f5dd44a0f41d206db226535b37b0c60e9da162c3ed", + "sha256:140ea00c87fafc42739bd74a94a5a9003f8e72c27c47cd4f61d8e05e6dec8721", + "sha256:16187aa2317c731170a88ef35e8937ae0f533c402872c1ee5e6d079fcf320801", + "sha256:17fcf043d0b4724858f25b8826c36e08f9fb2e475410bece0ec44a22d533da9b", + "sha256:18b956061b8db634120b58f668592a772e87e2e78bc1f6a906cfcaa0cc7991c1", + "sha256:2399408ac33ffd5b200480ee858baa58d77dd30e0dd0cab6a8a9547135f30a88", + "sha256:2a0c23b8319848426f305f9cb0c98a6e32ee68a36264f45948ccf8e7d2b941f8", + "sha256:2dfb7cff84e72e7bf975b06b4989477873dcf160b2fd89959c629535df53d4e0", + "sha256:2f495b6754358979379f84534f8dd7a43ff8cff2558dcdea4a148a6e713a758f", + "sha256:33539c6f5b96cf0b1105a0ff4cf5db9332e773bb521cc804a90e58dc49b10578", + "sha256:3c34f6896a01b84bab196f7119770fd8466c8ae3dfa73c59c0bb281e7b588ce7", + "sha256:498fec8da10e3e62edd1e7368f4b24aa362ac0ad931e678332d1b209aec93045", + "sha256:4d63f4d446e10ad19ed01188d6c1e1bb134cde8c18b0aa2acfd973d41fcc5ada", + "sha256:4e4b4385363de9052dac1a67bfb535c376f3d19c238b5f36bddc95efae15e12d", + "sha256:4e547b447073fc0dbfcbff15154c1be8823d10dab4ad401bdb1575e3fdedff1b", + "sha256:4f643df3d4419ea3f856c5c3f40fec1d65ea2e89ec812c83f7767c8730f9827a", + "sha256:4f763a29ee6a20c529496a20a7bcb16a73de27f5da6a843249c7047daf135977", + "sha256:5ae271862b2142f4bc687bdbfcc942e2473a89999a54231aa1c2c676e28f29ea", + "sha256:5d8fd17635b262448ab8f99230fe4dac991af1dabdbb92f7a70a6afac8a7e346", + "sha256:69c40d4655e078ede067a7095544bcec5a963566e17503e75a3a3e0fe2803b13", + "sha256:69d093792dc34a9c4c8a70e4973a3361c7a7578e9cd86961b2bbf38ca71e4e22", + "sha256:6a9653131bda68a1f029c52157fd81e11f07d485df55410401f745007bd6d339", + "sha256:6ff02a91c4fc9b6a94e1c9c20f62ea06a7e375f42fe57587f004d1078ac86ca9", + "sha256:714c12485aa52efbc0fc0ade1e9ab3a70343db82627f90f2ecbc898fdf0bb181", + "sha256:7264cbb4a18dc4acfd73b63e4bcfec9c9802614572025bdd44d0721983fc1d9c", + "sha256:73a96fd11d2b2e77d623a7f26e004cc31f131a365add1ce1ce9a19e55a1eef90", + "sha256:74bf625b1b4caaa7bad51d9003f8b07a468a704e0644a700e936c357c17dd45a", + "sha256:81b1289e99cf4bad07c23393ab447e5e96db0ab50974a280f7954b071d41b489", + "sha256:8425cfce27b8b20c9b89d77fb50e368d8306a90bf2b6eef2cdf5cd5083adf83f", + "sha256:875d240fdbdbe9e11f9831901fb8719da0bd4e6131f83aa9f69b96d18fae7504", + "sha256:879591c2b5ab0a7184258274c42a126b74a2c3d5a329df16d69f9cee07bba6ea", + "sha256:89fc28495896097622c3fc238915c79365dd0ede02f9a82ce436b13bd0ab7569", + "sha256:8a5e7cc39a45fc430af1aefc4d77ee6bad72c5bcdb1322cfde852c15192b8bd4", + "sha256:8f8909cdb9f1b237786c09a810e24ee5e15ef17019f7cecb207ce205b9b5fcce", + "sha256:914f66f3b6fc7b915d46c1cc424bc2441841083de01b90f9e81109c9759e43ab", + "sha256:92a3d214d5e53cb1db8b015f30d544bc9d3f7179a05feb8f16df713cecc2620a", + "sha256:948a9bd0fb2c5120457b07e59c8d7210cbc8703243225dbd78f4dfc13c8d2d1f", + "sha256:9c900108df470060174108012de06d45f514aa4ec21a191e7ab42988ff42a86c", + "sha256:9f2939cd4a2a52ca32bc0b359015718472d7f6de870760342e7ba295be9ebaf9", + "sha256:a4192b45dff127c7d69b3bdfb4d3e47b64179a0b9900b6351859f3001397dabf", + "sha256:a8fc931382e56627ec4acb01e09ce66e5c03c384ca52606111cee50d931a342d", + "sha256:ad47b095f0bdc5585bced35bd088cbfe4177236c7df9984b3cc46b391cc60627", + "sha256:b1ca5f060e205f72bec57faae5bd817a1560fcfc4af03f414b08fa29106b7e2d", + "sha256:ba1739fb38441a27a676f4de4123d3e858e494fac05868b7a281c0a383c098f4", + "sha256:baa7ef4e0886a6f482e00d1d5bcd37c201b383f1d314643dfb0367169f94f04c", + "sha256:bb90765dd91aed05b53cd7a87bd7f5c188fcd95960914bae0d32c5e7f899719d", + "sha256:bc7f729a72b16ee21795a943f85c6244971724819819a41ddbaeb691b2dd85ad", + "sha256:bdf62d25234290db1837875d4dceb2151e4ea7f9fff2ed41c0fde23ed542eb5b", + "sha256:c30970bdee1cad6a8da2044febd824ef6dc4cc0b19e39af3085c763fdec7de33", + "sha256:d2c63b93548eda58abf5188e505ffed0229bf675f7c3090f8e36ad55b8cbc371", + "sha256:d751300b94e35b6016d4b1e7d0e7bbc3b5e1751e2405ef908316c2a9024008a1", + "sha256:da427d311782324a376cacb47c1a4adc43f99fd9d996ffc1b3e8529c4074d393", + "sha256:daba396199399ccabafbfc509037ac635a6bc18510ad1add8fd16d4739cdd106", + "sha256:e185ec6060e301a7e5f8461c86fb3640a7beb1a0f0208ffde7a65ec4074931df", + "sha256:e4a557d97f12813dc5e18dad9fa765ae44ddd56a672bb5de4825527c847d6379", + "sha256:e5ed16d95fd142e9c72b6c10b06514ad30e846a0d0917ab406186541fe68b451", + "sha256:e711fc1acc7468463bc084d1b68561e40d1eaa135d8c509a65dd534403d83d7b", + "sha256:f28b29dc158ca5d6ac396c8e0a2ef45c4e97bb7e65522bfc04c989e6fe814575", + "sha256:f335579a1b485c834849e9075191c9898e0731af45705c2ebf70e0cd5d58beed", + "sha256:fce6fee67c318fdfb7f285c29a82d84782ae2579c0e1b385b7f36c6e8074fffb", + "sha256:fd136bb85f4568fffca995bd3c8d52080b1e5b225dbf1c2b17b66b4c5fa02838" + ], + "markers": "python_version >= '3.8'", + "version": "==1.17.0" }, "yarl": { "hashes": [ @@ -2646,11 +2642,11 @@ }, "zipp": { "hashes": [ - "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350", - "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29" + "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4", + "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931" ], - "markers": "python_version >= '3.8'", - "version": "==3.20.2" + "markers": "python_version >= '3.9'", + "version": "==3.21.0" } }, "develop": { @@ -2672,10 +2668,11 @@ }, "asttokens": { "hashes": [ - "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24", - "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0" + "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7", + "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2" ], - "version": "==2.4.1" + "markers": "python_version >= '3.8'", + "version": "==3.0.0" }, "attrs": { "hashes": [ @@ -2849,78 +2846,78 @@ "toml" ], "hashes": [ - "sha256:00a1d69c112ff5149cabe60d2e2ee948752c975d95f1e1096742e6077affd376", - "sha256:023bf8ee3ec6d35af9c1c6ccc1d18fa69afa1cb29eaac57cb064dbb262a517f9", - "sha256:0294ca37f1ba500667b1aef631e48d875ced93ad5e06fa665a3295bdd1d95111", - "sha256:06babbb8f4e74b063dbaeb74ad68dfce9186c595a15f11f5d5683f748fa1d172", - "sha256:0809082ee480bb8f7416507538243c8863ac74fd8a5d2485c46f0f7499f2b491", - "sha256:0b3fb02fe73bed561fa12d279a417b432e5b50fe03e8d663d61b3d5990f29546", - "sha256:0b58c672d14f16ed92a48db984612f5ce3836ae7d72cdd161001cc54512571f2", - "sha256:0bcd1069e710600e8e4cf27f65c90c7843fa8edfb4520fb0ccb88894cad08b11", - "sha256:1032e178b76a4e2b5b32e19d0fd0abbce4b58e77a1ca695820d10e491fa32b08", - "sha256:11a223a14e91a4693d2d0755c7a043db43d96a7450b4f356d506c2562c48642c", - "sha256:12394842a3a8affa3ba62b0d4ab7e9e210c5e366fbac3e8b2a68636fb19892c2", - "sha256:182e6cd5c040cec0a1c8d415a87b67ed01193ed9ad458ee427741c7d8513d963", - "sha256:1d5b8007f81b88696d06f7df0cb9af0d3b835fe0c8dbf489bad70b45f0e45613", - "sha256:1f76846299ba5c54d12c91d776d9605ae33f8ae2b9d1d3c3703cf2db1a67f2c0", - "sha256:27fb4a050aaf18772db513091c9c13f6cb94ed40eacdef8dad8411d92d9992db", - "sha256:29155cd511ee058e260db648b6182c419422a0d2e9a4fa44501898cf918866cf", - "sha256:29fc0f17b1d3fea332f8001d4558f8214af7f1d87a345f3a133c901d60347c73", - "sha256:2b6b4c83d8e8ea79f27ab80778c19bc037759aea298da4b56621f4474ffeb117", - "sha256:2fdef0d83a2d08d69b1f2210a93c416d54e14d9eb398f6ab2f0a209433db19e1", - "sha256:3c65d37f3a9ebb703e710befdc489a38683a5b152242664b973a7b7b22348a4e", - "sha256:4f704f0998911abf728a7783799444fcbbe8261c4a6c166f667937ae6a8aa522", - "sha256:51b44306032045b383a7a8a2c13878de375117946d68dcb54308111f39775a25", - "sha256:53d202fd109416ce011578f321460795abfe10bb901b883cafd9b3ef851bacfc", - "sha256:58809e238a8a12a625c70450b48e8767cff9eb67c62e6154a642b21ddf79baea", - "sha256:5915fcdec0e54ee229926868e9b08586376cae1f5faa9bbaf8faf3561b393d52", - "sha256:5beb1ee382ad32afe424097de57134175fea3faf847b9af002cc7895be4e2a5a", - "sha256:5f8ae553cba74085db385d489c7a792ad66f7f9ba2ee85bfa508aeb84cf0ba07", - "sha256:5fbd612f8a091954a0c8dd4c0b571b973487277d26476f8480bfa4b2a65b5d06", - "sha256:6bd818b7ea14bc6e1f06e241e8234508b21edf1b242d49831831a9450e2f35fa", - "sha256:6f01ba56b1c0e9d149f9ac85a2f999724895229eb36bd997b61e62999e9b0901", - "sha256:73d2b73584446e66ee633eaad1a56aad577c077f46c35ca3283cd687b7715b0b", - "sha256:7bb92c539a624cf86296dd0c68cd5cc286c9eef2d0c3b8b192b604ce9de20a17", - "sha256:8165b796df0bd42e10527a3f493c592ba494f16ef3c8b531288e3d0d72c1f6f0", - "sha256:862264b12ebb65ad8d863d51f17758b1684560b66ab02770d4f0baf2ff75da21", - "sha256:8902dd6a30173d4ef09954bfcb24b5d7b5190cf14a43170e386979651e09ba19", - "sha256:8cf717ee42012be8c0cb205dbbf18ffa9003c4cbf4ad078db47b95e10748eec5", - "sha256:8ed9281d1b52628e81393f5eaee24a45cbd64965f41857559c2b7ff19385df51", - "sha256:99b41d18e6b2a48ba949418db48159d7a2e81c5cc290fc934b7d2380515bd0e3", - "sha256:9cb7fa111d21a6b55cbf633039f7bc2749e74932e3aa7cb7333f675a58a58bf3", - "sha256:a181e99301a0ae128493a24cfe5cfb5b488c4e0bf2f8702091473d033494d04f", - "sha256:a413a096c4cbac202433c850ee43fa326d2e871b24554da8327b01632673a076", - "sha256:a6b1e54712ba3474f34b7ef7a41e65bd9037ad47916ccb1cc78769bae324c01a", - "sha256:ade3ca1e5f0ff46b678b66201f7ff477e8fa11fb537f3b55c3f0568fbfe6e718", - "sha256:b0ac3d42cb51c4b12df9c5f0dd2f13a4f24f01943627120ec4d293c9181219ba", - "sha256:b369ead6527d025a0fe7bd3864e46dbee3aa8f652d48df6174f8d0bac9e26e0e", - "sha256:b57b768feb866f44eeed9f46975f3d6406380275c5ddfe22f531a2bf187eda27", - "sha256:b8d3a03d9bfcaf5b0141d07a88456bb6a4c3ce55c080712fec8418ef3610230e", - "sha256:bc66f0bf1d7730a17430a50163bb264ba9ded56739112368ba985ddaa9c3bd09", - "sha256:bf20494da9653f6410213424f5f8ad0ed885e01f7e8e59811f572bdb20b8972e", - "sha256:c48167910a8f644671de9f2083a23630fbf7a1cb70ce939440cd3328e0919f70", - "sha256:c481b47f6b5845064c65a7bc78bc0860e635a9b055af0df46fdf1c58cebf8e8f", - "sha256:c7c8b95bf47db6d19096a5e052ffca0a05f335bc63cef281a6e8fe864d450a72", - "sha256:c9b8e184898ed014884ca84c70562b4a82cbc63b044d366fedc68bc2b2f3394a", - "sha256:cc8ff50b50ce532de2fa7a7daae9dd12f0a699bfcd47f20945364e5c31799fef", - "sha256:d541423cdd416b78626b55f123412fcf979d22a2c39fce251b350de38c15c15b", - "sha256:dab4d16dfef34b185032580e2f2f89253d302facba093d5fa9dbe04f569c4f4b", - "sha256:dacbc52de979f2823a819571f2e3a350a7e36b8cb7484cdb1e289bceaf35305f", - "sha256:df57bdbeffe694e7842092c5e2e0bc80fff7f43379d465f932ef36f027179806", - "sha256:ed8fe9189d2beb6edc14d3ad19800626e1d9f2d975e436f84e19efb7fa19469b", - "sha256:f3ddf056d3ebcf6ce47bdaf56142af51bb7fad09e4af310241e9db7a3a8022e1", - "sha256:f8fe4984b431f8621ca53d9380901f62bfb54ff759a1348cd140490ada7b693c", - "sha256:fe439416eb6380de434886b00c859304338f8b19f6f54811984f3420a2e03858" + "sha256:0824a28ec542a0be22f60c6ac36d679e0e262e5353203bea81d44ee81fe9c6d4", + "sha256:085161be5f3b30fd9b3e7b9a8c301f935c8313dcf928a07b116324abea2c1c2c", + "sha256:0ae1387db4aecb1f485fb70a6c0148c6cdaebb6038f1d40089b1fc84a5db556f", + "sha256:0d59fd927b1f04de57a2ba0137166d31c1a6dd9e764ad4af552912d70428c92b", + "sha256:0f957943bc718b87144ecaee70762bc2bc3f1a7a53c7b861103546d3a403f0a6", + "sha256:13a9e2d3ee855db3dd6ea1ba5203316a1b1fd8eaeffc37c5b54987e61e4194ae", + "sha256:1a330812d9cc7ac2182586f6d41b4d0fadf9be9049f350e0efb275c8ee8eb692", + "sha256:22be16571504c9ccea919fcedb459d5ab20d41172056206eb2994e2ff06118a4", + "sha256:2d10e07aa2b91835d6abec555ec8b2733347956991901eea6ffac295f83a30e4", + "sha256:35371f8438028fdccfaf3570b31d98e8d9eda8bb1d6ab9473f5a390969e98717", + "sha256:3c026eb44f744acaa2bda7493dad903aa5bf5fc4f2554293a798d5606710055d", + "sha256:41ff7b0da5af71a51b53f501a3bac65fb0ec311ebed1632e58fc6107f03b9198", + "sha256:4401ae5fc52ad8d26d2a5d8a7428b0f0c72431683f8e63e42e70606374c311a1", + "sha256:44349150f6811b44b25574839b39ae35291f6496eb795b7366fef3bd3cf112d3", + "sha256:447af20e25fdbe16f26e84eb714ba21d98868705cb138252d28bc400381f6ffb", + "sha256:4a8d8977b0c6ef5aeadcb644da9e69ae0dcfe66ec7f368c89c72e058bd71164d", + "sha256:4e12ae8cc979cf83d258acb5e1f1cf2f3f83524d1564a49d20b8bec14b637f08", + "sha256:592ac539812e9b46046620341498caf09ca21023c41c893e1eb9dbda00a70cbf", + "sha256:5e6b86b5847a016d0fbd31ffe1001b63355ed309651851295315031ea7eb5a9b", + "sha256:608a7fd78c67bee8936378299a6cb9f5149bb80238c7a566fc3e6717a4e68710", + "sha256:61f70dc68bd36810972e55bbbe83674ea073dd1dcc121040a08cdf3416c5349c", + "sha256:65dad5a248823a4996724a88eb51d4b31587aa7aa428562dbe459c684e5787ae", + "sha256:777abfab476cf83b5177b84d7486497e034eb9eaea0d746ce0c1268c71652077", + "sha256:7e216d8044a356fc0337c7a2a0536d6de07888d7bcda76febcb8adc50bdbbd00", + "sha256:85d9636f72e8991a1706b2b55b06c27545448baf9f6dbf51c4004609aacd7dcb", + "sha256:899b8cd4781c400454f2f64f7776a5d87bbd7b3e7f7bda0cb18f857bb1334664", + "sha256:8a289d23d4c46f1a82d5db4abeb40b9b5be91731ee19a379d15790e53031c014", + "sha256:8d2dfa71665a29b153a9681edb1c8d9c1ea50dfc2375fb4dac99ea7e21a0bcd9", + "sha256:8e3c3e38930cfb729cb8137d7f055e5a473ddaf1217966aa6238c88bd9fd50e6", + "sha256:8f8770dfc6e2c6a2d4569f411015c8d751c980d17a14b0530da2d7f27ffdd88e", + "sha256:932fc826442132dde42ee52cf66d941f581c685a6313feebed358411238f60f9", + "sha256:96d636c77af18b5cb664ddf12dab9b15a0cfe9c0bde715da38698c8cea748bfa", + "sha256:97ddc94d46088304772d21b060041c97fc16bdda13c6c7f9d8fcd8d5ae0d8611", + "sha256:98caba4476a6c8d59ec1eb00c7dd862ba9beca34085642d46ed503cc2d440d4b", + "sha256:9901d36492009a0a9b94b20e52ebfc8453bf49bb2b27bca2c9706f8b4f5a554a", + "sha256:99e266ae0b5d15f1ca8d278a668df6f51cc4b854513daab5cae695ed7b721cf8", + "sha256:9c38bf15a40ccf5619fa2fe8f26106c7e8e080d7760aeccb3722664c8656b030", + "sha256:a27801adef24cc30871da98a105f77995e13a25a505a0161911f6aafbd66e678", + "sha256:abd3e72dd5b97e3af4246cdada7738ef0e608168de952b837b8dd7e90341f015", + "sha256:adb697c0bd35100dc690de83154627fbab1f4f3c0386df266dded865fc50a902", + "sha256:b12c6b18269ca471eedd41c1b6a1065b2f7827508edb9a7ed5555e9a56dcfc97", + "sha256:b9389a429e0e5142e69d5bf4a435dd688c14478a19bb901735cdf75e57b13845", + "sha256:ba9e7484d286cd5a43744e5f47b0b3fb457865baf07bafc6bee91896364e1419", + "sha256:bb5555cff66c4d3d6213a296b360f9e1a8e323e74e0426b6c10ed7f4d021e464", + "sha256:be57b6d56e49c2739cdf776839a92330e933dd5e5d929966fbbd380c77f060be", + "sha256:c69e42c892c018cd3c8d90da61d845f50a8243062b19d228189b0224150018a9", + "sha256:ccc660a77e1c2bf24ddbce969af9447a9474790160cfb23de6be4fa88e3951c7", + "sha256:d5275455b3e4627c8e7154feaf7ee0743c2e7af82f6e3b561967b1cca755a0be", + "sha256:d75cded8a3cff93da9edc31446872d2997e327921d8eed86641efafd350e1df1", + "sha256:d872ec5aeb086cbea771c573600d47944eea2dcba8be5f3ee649bfe3cb8dc9ba", + "sha256:d891c136b5b310d0e702e186d70cd16d1119ea8927347045124cb286b29297e5", + "sha256:db1dab894cc139f67822a92910466531de5ea6034ddfd2b11c0d4c6257168073", + "sha256:e28bf44afa2b187cc9f41749138a64435bf340adfcacb5b2290c070ce99839d4", + "sha256:e5ea1cf0872ee455c03e5674b5bca5e3e68e159379c1af0903e89f5eba9ccc3a", + "sha256:e77363e8425325384f9d49272c54045bbed2f478e9dd698dbc65dbc37860eb0a", + "sha256:ee5defd1733fd6ec08b168bd4f5387d5b322f45ca9e0e6c817ea6c4cd36313e3", + "sha256:f1592791f8204ae9166de22ba7e6705fa4ebd02936c09436a1bb85aabca3e599", + "sha256:f2d1ec60d6d256bdf298cb86b78dd715980828f50c46701abc3b0a2b3f8a0dc0", + "sha256:f3ca78518bc6bc92828cd11867b121891d75cae4ea9e908d72030609b996db1b", + "sha256:f7b15f589593110ae767ce997775d645b47e5cbbf54fd322f8ebea6277466cec", + "sha256:fd1213c86e48dfdc5a0cc676551db467495a95a662d2396ecd58e719191446e1", + "sha256:ff74026a461eb0660366fb01c650c1d00f833a086b336bdad7ab00cc952072b3" ], "markers": "python_version >= '3.9'", - "version": "==7.6.4" + "version": "==7.6.9" }, "decorator": { "hashes": [ "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330", "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186" ], - "markers": "python_version >= '3.11'", + "markers": "python_version >= '3.5'", "version": "==5.1.1" }, "distlib": { @@ -2947,11 +2944,11 @@ }, "faker": { "hashes": [ - "sha256:3608c7fcac2acde0eaa6da28dae97628f18f14d54eaa2a92b96ae006f1621bd7", - "sha256:4cd0c5ea4bc1e4c902967f6e662f5f5da69f1674d9a94f54e516d27f3c2a6a16" + "sha256:1c925fc0e86a51fc46648b504078c88d0cd48da1da2595c4e712841cab43a1e4", + "sha256:d30c5f0e2796b8970de68978365247657486eb0311c5abe88d0b895b68dff05d" ], "markers": "python_version >= '3.8'", - "version": "==30.8.0" + "version": "==33.1.0" }, "filelock": { "hashes": [ @@ -3130,23 +3127,24 @@ "sha256:f406b22b7c9a9b4f8aa9d2ab13d6ae0ac3e85c9a809bd590ad53fed2bf70dc79", "sha256:f6ff3b14f2df4c41660a7dec01045a045653998784bf8cfcb5a525bdffffbc8f" ], + "markers": "python_version >= '3.7'", "version": "==3.1.1" }, - "html5lib-modern": { + "html5rdf": { "hashes": [ - "sha256:1fadbfc27ea955431270e4e79a4a4c290ba11c3a3098a95cc22dc73e312a1768", - "sha256:3458b6e31525ede4fcaac0ff42d9eeb5efaf755473768103cb56e0275caa8d99" + "sha256:1f519121bc366af3e485310dc8041d2e86e5173c1a320fac3dc9d2604069b83e", + "sha256:ace9b420ce52995bb4f05e7425eedf19e433c981dfe7a831ab391e2fa2e1a195" ], "markers": "python_version >= '3.8'", - "version": "==1.2" + "version": "==1.2.1" }, "identify": { "hashes": [ - "sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0", - "sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98" + "sha256:62f5dae9b5fef52c84cc188514e9ea4f3f636b1d8799ab5ebc475471f9e47a02", + "sha256:9edba65473324c2ea9684b1f944fe3191db3345e50b6d04571d10ed164f8d7bd" ], - "markers": "python_version >= '3.8'", - "version": "==2.6.1" + "markers": "python_version >= '3.9'", + "version": "==2.6.3" }, "idna": { "hashes": [ @@ -3183,19 +3181,19 @@ }, "ipython": { "hashes": [ - "sha256:0d0d15ca1e01faeb868ef56bc7ee5a0de5bd66885735682e8a322ae289a13d1a", - "sha256:530ef1e7bb693724d3cdc37287c80b07ad9b25986c007a53aa1857272dac3f35" + "sha256:85ec56a7e20f6c38fce7727dcca699ae4ffc85985aa7b23635a8008f918ae321", + "sha256:cb0a405a306d2995a5cbb9901894d240784a9f341394c6ba3f4fe8c6eb89ff6e" ], - "markers": "python_version >= '3.11'", - "version": "==8.28.0" + "markers": "python_version >= '3.10'", + "version": "==8.30.0" }, "jedi": { "hashes": [ - "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd", - "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0" + "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", + "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9" ], "markers": "python_version >= '3.6'", - "version": "==0.19.1" + "version": "==0.19.2" }, "lxml": { "hashes": [ @@ -3415,18 +3413,19 @@ }, "owlrl": { "hashes": [ - "sha256:57eca06b221edbbc682376c8d42e2ddffc99f61e82c0da02e26735592f08bacc", - "sha256:904e3310ff4df15101475776693d2427d1f8244ee9a6a9f9e13c3c57fae90b74" + "sha256:966136f303f08f3eb190f6631c31a03b1bc5744d6c15189d7fb638a563ee61d2", + "sha256:b4234191d1981ee7c551fa203cc0d21470c38e624e6795f3ecac55651dab26b1" ], - "version": "==6.0.2" + "markers": "python_version >= '3.8' and python_version < '4.0'", + "version": "==7.1.2" }, "packaging": { "hashes": [ - "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", - "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124" + "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", + "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f" ], "markers": "python_version >= '3.8'", - "version": "==24.1" + "version": "==24.2" }, "parso": { "hashes": [ @@ -3471,11 +3470,11 @@ }, "prettytable": { "hashes": [ - "sha256:7e23ca1e68bbfd06ba8de98bf553bf3493264c96d5e8a615c0471025deeba722", - "sha256:aa17083feb6c71da11a68b2c213b04675c4af4ce9c541762632ca3f2cb3546dd" + "sha256:77ca0ad1c435b6e363d7e8623d7cc4fcf2cf15513bf77a1c1b2e814930ac57cc", + "sha256:f04b3e1ba35747ac86e96ec33e3bb9748ce08e254dc2a1c6253945901beec804" ], - "markers": "python_version >= '3.8' and python_version < '3.12'", - "version": "==3.11.0" + "markers": "python_version >= '3.9'", + "version": "==3.12.0" }, "prompt-toolkit": { "hashes": [ @@ -3590,25 +3589,25 @@ "sha256:93d9577b88da0bbea8cc8334ee8b918ed014968fd2ec383e868fb8afb1ccef84", "sha256:cbf74e27246d595d9a74b186b810f6fbb86726dbf3b9532efb343f6d7294fe9c" ], - "markers": "python_version > '3.0'", + "markers": "python_version >= '3.9'", "version": "==3.2.0" }, "pyshacl": { "hashes": [ - "sha256:1442662263064ba8ab65714818f45b17e398240092ecc43d3f802ae9233ce03f", - "sha256:d41d7a052f7a5311ae89f8357d7a7ba37a88362204eda93141556c588c6a3ff6" + "sha256:a9ef654e72890c87d37b0e0ddae622fe46ac487dcda902d3c75724a913b41f0b", + "sha256:b12d735f724e5602b14e2819c91047cde53b7b26de472885ce54d9d79cbcdcfc" ], - "markers": "python_full_version >= '3.8.1' and python_full_version < '4.0.0'", - "version": "==0.28.0" + "markers": "python_version >= '3.9' and python_version < '4'", + "version": "==0.29.0" }, "pytest": { "hashes": [ - "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", - "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2" + "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", + "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==8.3.3" + "version": "==8.3.4" }, "pytest-asyncio": { "hashes": [ @@ -3621,12 +3620,12 @@ }, "pytest-cov": { "hashes": [ - "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652", - "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857" + "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", + "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0" ], "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==5.0.0" + "markers": "python_version >= '3.9'", + "version": "==6.0.0" }, "pytest-env": { "hashes": [ @@ -3719,6 +3718,7 @@ "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" ], + "markers": "python_version >= '3.8'", "version": "==6.0.2" }, "rdflib": { @@ -3726,11 +3726,11 @@ "html" ], "hashes": [ - "sha256:240c25c6e1b573ffa67aed23aae128e253c443c15291c9a01d8d392ea80c05b6", - "sha256:a29a8fccebd3d3a5f1b7e88d92dace1c89829018c7d29a6114fff4449c188b3b" + "sha256:164de86bd3564558802ca983d84f6616a4a1a420c7a17a8152f5016076b2913e", + "sha256:e590fa9a2c34ba33a667818b5a84be3fb8a4d85868f8038f17912ec84f912a25" ], - "markers": "python_full_version >= '3.8.1'", - "version": "==7.1.0" + "markers": "python_full_version >= '3.8.1' and python_full_version < '4.0.0'", + "version": "==7.1.1" }, "reproschema": { "hashes": [ @@ -3758,44 +3758,44 @@ }, "ruff": { "hashes": [ - "sha256:0cdf20c2b6ff98e37df47b2b0bd3a34aaa155f59a11182c1303cce79be715628", - "sha256:10842f69c245e78d6adec7e1db0a7d9ddc2fff0621d730e61657b64fa36f207e", - "sha256:194d6c46c98c73949a106425ed40a576f52291c12bc21399eb8f13a0f7073495", - "sha256:1eb54986f770f49edb14f71d33312d79e00e629a57387382200b1ef12d6a4ef9", - "sha256:211d877674e9373d4bb0f1c80f97a0201c61bcd1e9d045b6e9726adc42c156aa", - "sha256:214b88498684e20b6b2b8852c01d50f0651f3cc6118dfa113b4def9f14faaf06", - "sha256:47a86360cf62d9cd53ebfb0b5eb0e882193fc191c6d717e8bef4462bc3b9ea2b", - "sha256:496494d350c7fdeb36ca4ef1c9f21d80d182423718782222c29b3e72b3512737", - "sha256:4b406c2dce5be9bad59f2de26139a86017a517e6bcd2688da515481c05a2cb11", - "sha256:630fce3fefe9844e91ea5bbf7ceadab4f9981f42b704fae011bb8efcaf5d84be", - "sha256:82c2579b82b9973a110fab281860403b397c08c403de92de19568f32f7178598", - "sha256:9af971fe85dcd5eaed8f585ddbc6bdbe8c217fb8fcf510ea6bca5bdfff56040e", - "sha256:ab7d98c7eed355166f367597e513a6c82408df4181a937628dbec79abb2a1fe4", - "sha256:b641c7f16939b7d24b7bfc0be4102c56562a18281f84f635604e8a6989948914", - "sha256:d71672336e46b34e0c90a790afeac8a31954fd42872c1f6adaea1dff76fd44f9", - "sha256:dc452ba6f2bb9cf8726a84aa877061a2462afe9ae0ea1d411c53d226661c601d", - "sha256:f6c968509f767776f524a8430426539587d5ec5c662f6addb6aa25bc2e8195ec", - "sha256:ff4aabfbaaba880e85d394603b9e75d32b0693152e16fa659a3064a85df7fce2" + "sha256:1ca4e3a87496dc07d2427b7dd7ffa88a1e597c28dad65ae6433ecb9f2e4f022f", + "sha256:2aae99ec70abf43372612a838d97bfe77d45146254568d94926e8ed5bbb409ea", + "sha256:32096b41aaf7a5cc095fa45b4167b890e4c8d3fd217603f3634c92a541de7248", + "sha256:5fe716592ae8a376c2673fdfc1f5c0c193a6d0411f90a496863c99cd9e2ae25d", + "sha256:60f578c11feb1d3d257b2fb043ddb47501ab4816e7e221fbb0077f0d5d4e7b6f", + "sha256:705832cd7d85605cb7858d8a13d75993c8f3ef1397b0831289109e953d833d29", + "sha256:729850feed82ef2440aa27946ab39c18cb4a8889c1128a6d589ffa028ddcfc22", + "sha256:81c148825277e737493242b44c5388a300584d73d5774defa9245aaef55448b0", + "sha256:ac42caaa0411d6a7d9594363294416e0e48fc1279e1b0e948391695db2b3d5b1", + "sha256:b402ddee3d777683de60ff76da801fa7e5e8a71038f57ee53e903afbcefdaa58", + "sha256:b84f4f414dda8ac7f75075c1fa0b905ac0ff25361f42e6d5da681a465e0f78e5", + "sha256:c49ab4da37e7c457105aadfd2725e24305ff9bc908487a9bf8d548c6dad8bb3d", + "sha256:cbd5cf9b0ae8f30eebc7b360171bd50f59ab29d39f06a670b3e4501a36ba5897", + "sha256:d261d7850c8367704874847d95febc698a950bf061c9475d4a8b7689adc4f7fa", + "sha256:e769083da9439508833cfc7c23e351e1809e67f47c50248250ce1ac52c21fb93", + "sha256:ec016beb69ac16be416c435828be702ee694c0d722505f9c1f35e1b9c0cc1bf5", + "sha256:f05cdf8d050b30e2ba55c9b09330b51f9f97d36d4673213679b965d25a785f3c", + "sha256:fb88e2a506b70cfbc2de6fae6681c4f944f7dd5f2fe87233a7233d888bad73e8" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==0.7.0" + "version": "==0.8.2" }, "setuptools": { "hashes": [ - "sha256:753bb6ebf1f465a1912e19ed1d41f403a79173a9acf66a42e7e6aec45c3c16ec", - "sha256:a7fcb66f68b4d9e8e66b42f9876150a3371558f98fa32222ffaa5bced76406f8" + "sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6", + "sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d" ], - "markers": "python_version >= '3.8'", - "version": "==75.2.0" + "markers": "python_version >= '3.9'", + "version": "==75.6.0" }, "six": { "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", + "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", - "version": "==1.16.0" + "version": "==1.17.0" }, "stack-data": { "hashes": [ @@ -3897,11 +3897,11 @@ }, "virtualenv": { "hashes": [ - "sha256:2ca56a68ed615b8fe4326d11a0dca5dfbe8fd68510fb6c6349163bed3c15f2b2", - "sha256:44a72c29cceb0ee08f300b314848c86e57bf8d1f13107a5e671fb9274138d655" + "sha256:23eae1b4516ecd610481eda647f3a7c09aea295055337331bb4e6892ecce47b0", + "sha256:2c9c3262bb8e7b87ea801d715fae4495e6032450c71d2309be9550e7364049aa" ], "markers": "python_version >= '3.8'", - "version": "==20.27.0" + "version": "==20.28.0" }, "wcwidth": { "hashes": [ @@ -3912,11 +3912,11 @@ }, "zipp": { "hashes": [ - "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350", - "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29" + "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4", + "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931" ], - "markers": "python_version >= '3.8'", - "version": "==3.20.2" + "markers": "python_version >= '3.9'", + "version": "==3.21.0" }, "zope.event": { "hashes": [ @@ -3928,46 +3928,46 @@ }, "zope.interface": { "hashes": [ - "sha256:0de23bcb93401994ea00bc5c677ef06d420340ac0a4e9c10d80e047b9ce5af3f", - "sha256:179ad46ece518c9084cb272e4a69d266b659f7f8f48e51706746c2d8a426433e", - "sha256:190eeec67e023d5aac54d183fa145db0b898664234234ac54643a441da434616", - "sha256:1a2ed0852c25950cf430067f058f8d98df6288502ac313861d9803fe7691a9b3", - "sha256:1c4e1b4c06d9abd1037c088dae1566c85f344a3e6ae4350744c3f7f7259d9c67", - "sha256:1d0e23c6b746eb8ce04573cc47bcac60961ac138885d207bd6f57e27a1431ae8", - "sha256:2317e1d4dba68203a5227ea3057f9078ec9376275f9700086b8f0ffc0b358e1b", - "sha256:2d553e02b68c0ea5a226855f02edbc9eefd99f6a8886fa9f9bdf999d77f46585", - "sha256:3603ef82a9920bd0bfb505423cb7e937498ad971ad5a6141841e8f76d2fd5446", - "sha256:3defc925c4b22ac1272d544a49c6ba04c3eefcce3200319ee1be03d9270306dd", - "sha256:3e59f175e868f856a77c0a77ba001385c377df2104fdbda6b9f99456a01e102a", - "sha256:4284d664ef0ff7b709836d4de7b13d80873dc5faeffc073abdb280058bfac5e3", - "sha256:55c373becbd36a44d0c9be1d5271422fdaa8562d158fb44b4192297b3c67096c", - "sha256:5836b8fb044c6e75ba34dfaabc602493019eadfa0faf6ff25f4c4c356a71a853", - "sha256:5cdb7e7e5524b76d3ec037c1d81a9e2c7457b240fd4cb0a2476b65c3a5a6c81f", - "sha256:6650bd56ef350d37c8baccfd3ee8a0483ed6f8666e641e4b9ae1a1827b79f9e5", - "sha256:7395f13533318f150ee72adb55b29284b16e73b6d5f02ab21f173b3e83f242b8", - "sha256:7720322763aceb5e0a7cadcc38c67b839efe599f0887cbf6c003c55b1458c501", - "sha256:7cd5e3d910ac87652a09f6e5db8e41bc3b49cf08ddd2d73d30afc644801492cd", - "sha256:81744a7e61b598ebcf4722ac56a7a4f50502432b5b4dc7eb29075a89cf82d029", - "sha256:84e87eba6b77a3af187bae82d8de1a7c208c2a04ec9f6bd444fd091b811ad92e", - "sha256:8d0fe45be57b5219aa4b96e846631c04615d5ef068146de5a02ccd15c185321f", - "sha256:9595e478047ce752b35cfa221d7601a5283ccdaab40422e0dc1d4a334c70f580", - "sha256:99c14f0727c978639139e6cad7a60e82b7720922678d75aacb90cf4ef74a068c", - "sha256:9b1eed7670d564f1025d7cda89f99f216c30210e42e95de466135be0b4a499d9", - "sha256:9fad9bd5502221ab179f13ea251cb30eef7cf65023156967f86673aff54b53a0", - "sha256:ad339509dcfbbc99bf8e147db6686249c4032f26586699ec4c82f6e5909c9fe2", - "sha256:bcbeb44fc16e0078b3b68a95e43f821ae34dcbf976dde6985141838a5f23dd3d", - "sha256:c8e7b05dc6315a193cceaec071cc3cf1c180cea28808ccded0b1283f1c38ba73", - "sha256:ca95594d936ee349620900be5b46c0122a1ff6ce42d7d5cb2cf09dc84071ef16", - "sha256:d029fac6a80edae80f79c37e5e3abfa92968fe921886139b3ee470a1b177321a", - "sha256:d17e7fc814eaab93409b80819fd6d30342844345c27f3bc3c4b43c2425a8d267", - "sha256:d6821ef9870f32154da873fcde439274f99814ea452dd16b99fa0b66345c4b6b", - "sha256:e6503534b52bb1720ace9366ee30838a58a3413d3e197512f3338c8f34b5d89d", - "sha256:ed1df8cc01dd1e3970666a7370b8bfc7457371c58ba88c57bd5bca17ab198053", - "sha256:f1d52d052355e0c5c89e0630dd2ff7c0b823fd5f56286a663e92444761b35e25", - "sha256:f85b290e5b8b11814efb0d004d8ce6c9a483c35c462e8d9bf84abb93e79fa770" - ], - "markers": "python_version >= '3.8'", - "version": "==7.1.1" + "sha256:033b3923b63474800b04cba480b70f6e6243a62208071fc148354f3f89cc01b7", + "sha256:05b910a5afe03256b58ab2ba6288960a2892dfeef01336dc4be6f1b9ed02ab0a", + "sha256:086ee2f51eaef1e4a52bd7d3111a0404081dadae87f84c0ad4ce2649d4f708b7", + "sha256:0ef9e2f865721553c6f22a9ff97da0f0216c074bd02b25cf0d3af60ea4d6931d", + "sha256:1090c60116b3da3bfdd0c03406e2f14a1ff53e5771aebe33fec1edc0a350175d", + "sha256:144964649eba4c5e4410bb0ee290d338e78f179cdbfd15813de1a664e7649b3b", + "sha256:15398c000c094b8855d7d74f4fdc9e73aa02d4d0d5c775acdef98cdb1119768d", + "sha256:1909f52a00c8c3dcab6c4fad5d13de2285a4b3c7be063b239b8dc15ddfb73bd2", + "sha256:21328fcc9d5b80768bf051faa35ab98fb979080c18e6f84ab3f27ce703bce465", + "sha256:224b7b0314f919e751f2bca17d15aad00ddbb1eadf1cb0190fa8175edb7ede62", + "sha256:25e6a61dcb184453bb00eafa733169ab6d903e46f5c2ace4ad275386f9ab327a", + "sha256:27f926f0dcb058211a3bb3e0e501c69759613b17a553788b2caeb991bed3b61d", + "sha256:29caad142a2355ce7cfea48725aa8bcf0067e2b5cc63fcf5cd9f97ad12d6afb5", + "sha256:2ad9913fd858274db8dd867012ebe544ef18d218f6f7d1e3c3e6d98000f14b75", + "sha256:31d06db13a30303c08d61d5fb32154be51dfcbdb8438d2374ae27b4e069aac40", + "sha256:3e0350b51e88658d5ad126c6a57502b19d5f559f6cb0a628e3dc90442b53dd98", + "sha256:3f6771d1647b1fc543d37640b45c06b34832a943c80d1db214a37c31161a93f1", + "sha256:4893395d5dd2ba655c38ceb13014fd65667740f09fa5bb01caa1e6284e48c0cd", + "sha256:52e446f9955195440e787596dccd1411f543743c359eeb26e9b2c02b077b0519", + "sha256:550f1c6588ecc368c9ce13c44a49b8d6b6f3ca7588873c679bd8fd88a1b557b6", + "sha256:72cd1790b48c16db85d51fbbd12d20949d7339ad84fd971427cf00d990c1f137", + "sha256:7bd449c306ba006c65799ea7912adbbfed071089461a19091a228998b82b1fdb", + "sha256:7dc5016e0133c1a1ec212fc87a4f7e7e562054549a99c73c8896fa3a9e80cbc7", + "sha256:802176a9f99bd8cc276dcd3b8512808716492f6f557c11196d42e26c01a69a4c", + "sha256:80ecf2451596f19fd607bb09953f426588fc1e79e93f5968ecf3367550396b22", + "sha256:8b49f1a3d1ee4cdaf5b32d2e738362c7f5e40ac8b46dd7d1a65e82a4872728fe", + "sha256:8e7da17f53e25d1a3bde5da4601e026adc9e8071f9f6f936d0fe3fe84ace6d54", + "sha256:a102424e28c6b47c67923a1f337ede4a4c2bba3965b01cf707978a801fc7442c", + "sha256:a19a6cc9c6ce4b1e7e3d319a473cf0ee989cbbe2b39201d7c19e214d2dfb80c7", + "sha256:a71a5b541078d0ebe373a81a3b7e71432c61d12e660f1d67896ca62d9628045b", + "sha256:baf95683cde5bc7d0e12d8e7588a3eb754d7c4fa714548adcd96bdf90169f021", + "sha256:cab15ff4832580aa440dc9790b8a6128abd0b88b7ee4dd56abacbc52f212209d", + "sha256:ce290e62229964715f1011c3dbeab7a4a1e4971fd6f31324c4519464473ef9f2", + "sha256:d3a8ffec2a50d8ec470143ea3d15c0c52d73df882eef92de7537e8ce13475e8a", + "sha256:e204937f67b28d2dca73ca936d3039a144a081fc47a07598d44854ea2a106239", + "sha256:eb23f58a446a7f09db85eda09521a498e109f137b85fb278edb2e34841055398", + "sha256:f6dd02ec01f4468da0f234da9d9c8545c5412fef80bc590cc51d8dd084138a89" + ], + "markers": "python_version >= '3.8'", + "version": "==7.2" } } } diff --git a/src/apps/activities/api/activities.py b/src/apps/activities/api/activities.py index 41e6e85d47e..3b326ce7617 100644 --- a/src/apps/activities/api/activities.py +++ b/src/apps/activities/api/activities.py @@ -385,7 +385,9 @@ async def applet_activities_metadata_for_subject( ) # Fetch activities submissions by the subject - submitted_activities = await AnswerService(session, user.id, answer_session).get_submissions_by_subject(subject_id) + submissions_metadata = await AnswerService(session, user.id, answer_session).get_submissions_metadata_by_subject( + subject_id + ) # Fetch auto-assigned activity and flow IDs by applet ID auto_activity_ids = await ActivityService(session, user.id).get_activity_and_flow_ids_by_applet_id_auto(applet_id) @@ -393,7 +395,7 @@ async def applet_activities_metadata_for_subject( # Combine all assigned IDs and submitted activity IDs all_activity_ids = ( set(assigned_activities.activities.keys()) - | set(submitted_activities.activities.keys()) + | set(submissions_metadata.activities.keys()) | set(auto_activity_ids) ) @@ -411,7 +413,7 @@ async def applet_activities_metadata_for_subject( is_auto = activity_or_flow_id in auto_activity_ids # Get submission and assignment data if available - submission_data = submitted_activities.activities.get(activity_or_flow_id) + submission_data = submissions_metadata.activities.get(activity_or_flow_id) assignments_data = assigned_activities.activities.get(activity_or_flow_id) # Initialize sets for respondents and subjects @@ -420,14 +422,18 @@ async def applet_activities_metadata_for_subject( # Initialize submission counts respondent_submissions_count = 0 + respondent_last_submission_date = None subject_submissions_count = 0 + subject_last_submission_date = None # Update from submission data if submission_data: respondents.update(submission_data.respondents) subjects.update(submission_data.subjects) respondent_submissions_count = submission_data.respondent_submissions_count + respondent_last_submission_date = submission_data.respondent_last_submission_date subject_submissions_count = submission_data.subject_submissions_count + subject_last_submission_date = submission_data.subject_last_submission_date # Update from assignment data if assignments_data: @@ -464,7 +470,9 @@ async def applet_activities_metadata_for_subject( respondents_count=respondents_count, subjects_count=subjects_count, respondent_submissions_count=respondent_submissions_count, + respondent_last_submission_date=respondent_last_submission_date, subject_submissions_count=subject_submissions_count, + subject_last_submission_date=subject_last_submission_date, ) ) diff --git a/src/apps/activities/domain/activity.py b/src/apps/activities/domain/activity.py index 8f0c9cfe9f4..b0413e69467 100644 --- a/src/apps/activities/domain/activity.py +++ b/src/apps/activities/domain/activity.py @@ -162,8 +162,10 @@ class ActivitySubjectMetadata(PublicModel): activity_or_flow_id: uuid.UUID respondents_count: int respondent_submissions_count: int + respondent_last_submission_date: datetime | None subjects_count: int subject_submissions_count: int + subject_last_submission_date: datetime | None class ActivitiesMetadata(PublicModel): diff --git a/src/apps/activities/tests/test_activities.py b/src/apps/activities/tests/test_activities.py index 65494fc711b..f558c5bc066 100644 --- a/src/apps/activities/tests/test_activities.py +++ b/src/apps/activities/tests/test_activities.py @@ -1353,18 +1353,22 @@ async def test_assigned_activities_auto_assigned( assert result["targetActivitiesCountExisting"] == 2 assert result["targetActivitiesCountDeleted"] == 0 assert len(result["activitiesOrFlows"]) == 2 - flow_counters = next(item for item in result["activitiesOrFlows"] if item["activityOrFlowId"] == str(flow.id)) - activity_counters = next( + flow_metadata = next(item for item in result["activitiesOrFlows"] if item["activityOrFlowId"] == str(flow.id)) + activity_metadata = next( item for item in result["activitiesOrFlows"] if item["activityOrFlowId"] == str(activity.id) ) - assert flow_counters["respondentsCount"] == 1 - assert flow_counters["respondentSubmissionsCount"] == 0 - assert flow_counters["subjectsCount"] == 1 - assert flow_counters["subjectSubmissionsCount"] == 0 - assert activity_counters["respondentsCount"] == 1 - assert activity_counters["respondentSubmissionsCount"] == 0 - assert activity_counters["subjectsCount"] == 1 - assert activity_counters["subjectSubmissionsCount"] == 0 + assert flow_metadata["respondentsCount"] == 1 + assert flow_metadata["respondentSubmissionsCount"] == 0 + assert flow_metadata["respondentLastSubmissionDate"] is None + assert flow_metadata["subjectsCount"] == 1 + assert flow_metadata["subjectSubmissionsCount"] == 0 + assert flow_metadata["subjectLastSubmissionDate"] is None + assert activity_metadata["respondentsCount"] == 1 + assert activity_metadata["respondentSubmissionsCount"] == 0 + assert activity_metadata["respondentLastSubmissionDate"] is None + assert activity_metadata["subjectsCount"] == 1 + assert activity_metadata["subjectSubmissionsCount"] == 0 + assert activity_metadata["subjectLastSubmissionDate"] is None @pytest.mark.parametrize( "subject_type,result_order", @@ -1754,8 +1758,18 @@ async def test_assigned_activities_from_submission( activityOrFlow = result["activitiesOrFlows"][0] assert activityOrFlow["respondentsCount"] == (1 if subject_type == "target" else 0) assert activityOrFlow["respondentSubmissionsCount"] == (0 if subject_type == "target" else 1) + assert ( + activityOrFlow["respondentLastSubmissionDate"] is None + if subject_type == "target" + else activityOrFlow["respondentLastSubmissionDate"] is not None + ) assert activityOrFlow["subjectsCount"] == (0 if subject_type == "target" else 1) assert activityOrFlow["subjectSubmissionsCount"] == (1 if subject_type == "target" else 0) + assert ( + activityOrFlow["subjectLastSubmissionDate"] is not None + if subject_type == "target" + else activityOrFlow["subjectLastSubmissionDate"] is None + ) @pytest.mark.parametrize("subject_type", ["target", "respondent"]) async def test_assigned_hidden_activities( diff --git a/src/apps/answers/crud/answers.py b/src/apps/answers/crud/answers.py index 01ce9013e3a..38f439e3a10 100644 --- a/src/apps/answers/crud/answers.py +++ b/src/apps/answers/crud/answers.py @@ -1011,7 +1011,7 @@ async def get_activity_and_flow_ids_by_source_subject(self, source_subject_id: u return res.mappings().all() @staticmethod - def _query_submissions_by_subject(subject_column: InstrumentedAttribute, subject_id: uuid.UUID) -> Query: + def _query_submissions_metadata_by_subject(subject_column: InstrumentedAttribute, subject_id: uuid.UUID) -> Query: query: Query = ( select( func.count(func.distinct(AnswerSchema.submit_id)).label("submission_count"), @@ -1027,6 +1027,7 @@ def _query_submissions_by_subject(subject_column: InstrumentedAttribute, subject if subject_column == AnswerSchema.target_subject_id else AnswerSchema.target_subject_id ).label("subject_id"), + func.max(AnswerSchema.created_at).label("last_submission_date"), ) .where( subject_column == subject_id, @@ -1035,17 +1036,20 @@ def _query_submissions_by_subject(subject_column: InstrumentedAttribute, subject ) .group_by("activity_id", "subject_id") ) + return query - async def get_submissions_by_target_subject(self, target_subject_id: uuid.UUID) -> list[dict]: - query: Query = self._query_submissions_by_subject(AnswerSchema.target_subject_id, target_subject_id) + async def get_submissions_metadata_by_target_subject(self, target_subject_id: uuid.UUID) -> list[dict]: + query: Query = self._query_submissions_metadata_by_subject(AnswerSchema.target_subject_id, target_subject_id) res = await self._execute(query) return res.mappings().all() - async def get_submissions_by_respondent_subject(self, respondent_subject_id: uuid.UUID) -> list[dict]: - query: Query = self._query_submissions_by_subject(AnswerSchema.source_subject_id, respondent_subject_id) + async def get_submissions_metadata_by_respondent_subject(self, respondent_subject_id: uuid.UUID) -> list[dict]: + query: Query = self._query_submissions_metadata_by_subject( + AnswerSchema.source_subject_id, respondent_subject_id + ) res = await self._execute(query) diff --git a/src/apps/answers/domain/answers.py b/src/apps/answers/domain/answers.py index 8c64dd30a55..2072a991f71 100644 --- a/src/apps/answers/domain/answers.py +++ b/src/apps/answers/domain/answers.py @@ -719,9 +719,11 @@ class SubmissionsSubjectCounters(InternalModel): respondents: set[uuid.UUID] = Field(default_factory=set) subjects: set[uuid.UUID] = Field(default_factory=set) subject_submissions_count: int = 0 + subject_last_submission_date: datetime.datetime | None = None respondent_submissions_count: int = 0 + respondent_last_submission_date: datetime.datetime | None = None -class SubmissionsActivityCountBySubject(InternalModel): +class SubmissionsActivityMetadataBySubject(InternalModel): subject_id: uuid.UUID activities: dict[uuid.UUID, SubmissionsSubjectCounters] = Field(default_factory=dict) diff --git a/src/apps/answers/service.py b/src/apps/answers/service.py index aab7ce30774..6c6bb2adf2a 100644 --- a/src/apps/answers/service.py +++ b/src/apps/answers/service.py @@ -67,7 +67,7 @@ AppletSubmission, FilesCopyCheckResult, RespondentAnswerData, - SubmissionsActivityCountBySubject, + SubmissionsActivityMetadataBySubject, SubmissionsSubjectCounters, ) from apps.answers.errors import ( @@ -1979,9 +1979,13 @@ async def _filter_out_soft_deleted_subjects(self, submissions: list[dict]) -> se return existing_subject_ids - async def get_submissions_by_subject(self, subject_id: uuid.UUID) -> SubmissionsActivityCountBySubject: - submissions_target_coro = AnswersCRUD(self.answer_session).get_submissions_by_target_subject(subject_id) - submissions_respondent_coro = AnswersCRUD(self.answer_session).get_submissions_by_respondent_subject(subject_id) + async def get_submissions_metadata_by_subject(self, subject_id: uuid.UUID) -> SubmissionsActivityMetadataBySubject: + submissions_target_coro = AnswersCRUD(self.answer_session).get_submissions_metadata_by_target_subject( + subject_id + ) + submissions_respondent_coro = AnswersCRUD(self.answer_session).get_submissions_metadata_by_respondent_subject( + subject_id + ) submissions_target, submissions_respondent = await asyncio.gather( submissions_target_coro, submissions_respondent_coro @@ -1989,27 +1993,41 @@ async def get_submissions_by_subject(self, subject_id: uuid.UUID) -> Submissions existing_subject_ids = await self._filter_out_soft_deleted_subjects(submissions_target + submissions_respondent) - submissions_activity_count = SubmissionsActivityCountBySubject(subject_id=subject_id) + submissions_activity_metadata = SubmissionsActivityMetadataBySubject(subject_id=subject_id) for activity_submissions in submissions_target: - activity_counters = submissions_activity_count.activities.setdefault( + activity_metadata = submissions_activity_metadata.activities.setdefault( uuid.UUID(activity_submissions["activity_id"]), SubmissionsSubjectCounters() ) respondent_subject_id = activity_submissions["subject_id"] if respondent_subject_id in existing_subject_ids: - activity_counters.respondents.add(respondent_subject_id) - activity_counters.subject_submissions_count += activity_submissions["submission_count"] + activity_metadata.respondents.add(respondent_subject_id) + activity_metadata.subject_submissions_count += activity_submissions["submission_count"] + activity_metadata.subject_last_submission_date = ( + activity_submissions["last_submission_date"] + if not activity_metadata.subject_last_submission_date + else max( + activity_metadata.subject_last_submission_date, activity_submissions["last_submission_date"] + ) + ) for activity_submissions in submissions_respondent: - activity_counters = submissions_activity_count.activities.setdefault( + activity_metadata = submissions_activity_metadata.activities.setdefault( uuid.UUID(activity_submissions["activity_id"]), SubmissionsSubjectCounters() ) target_subject_id = activity_submissions["subject_id"] if target_subject_id in existing_subject_ids: - activity_counters.subjects.add(target_subject_id) - activity_counters.respondent_submissions_count += activity_submissions["submission_count"] + activity_metadata.subjects.add(target_subject_id) + activity_metadata.respondent_submissions_count += activity_submissions["submission_count"] + activity_metadata.respondent_last_submission_date = ( + activity_submissions["last_submission_date"] + if not activity_metadata.respondent_last_submission_date + else max( + activity_metadata.respondent_last_submission_date, activity_submissions["last_submission_date"] + ) + ) - return submissions_activity_count + return submissions_activity_metadata class ReportServerService: diff --git a/src/apps/authentication/api/auth.py b/src/apps/authentication/api/auth.py index b220b8e6777..a7997e1c2e1 100644 --- a/src/apps/authentication/api/auth.py +++ b/src/apps/authentication/api/auth.py @@ -1,5 +1,5 @@ import uuid -from datetime import datetime +from datetime import datetime, timezone import jwt from fastapi import Body, Depends @@ -86,10 +86,9 @@ async def refresh_access_token( # check transition key transition_key = settings.authentication.refresh_token.transition_key transition_expire_date = settings.authentication.refresh_token.transition_expire_date + today = datetime.now(timezone.utc).date() - if not ( - transition_key and transition_expire_date and transition_expire_date > datetime.utcnow().date() - ): + if not (transition_key and transition_expire_date and transition_expire_date > today): raise payload = jwt.decode( schema.refresh_token, diff --git a/src/apps/authentication/tests/test_auth.py b/src/apps/authentication/tests/test_auth.py index 4464aff35d3..5e34ce216dc 100644 --- a/src/apps/authentication/tests/test_auth.py +++ b/src/apps/authentication/tests/test_auth.py @@ -109,7 +109,7 @@ async def test_refresh_token_key_transition(self, client, tom: User, tom_create: token_data = TokenPayload(**payload) new_token_key = "new token key" - transition_expire_date = datetime.date.today() + datetime.timedelta(days=1) + transition_expire_date = datetime.datetime.now(datetime.timezone.utc).date() + datetime.timedelta(days=1) # refresh access token, check refresh token not changed _status_code, _token = await self._request_refresh_token(client, refresh_token) @@ -129,7 +129,7 @@ async def test_refresh_token_key_transition(self, client, tom: User, tom_create: # check transition expire date with mock.patch("apps.authentication.api.auth.datetime") as date_mock: - date_mock.utcnow().date.return_value = transition_expire_date + datetime.timedelta(days=1) + date_mock.now().date.return_value = transition_expire_date + datetime.timedelta(days=1) _status_code, _ = await self._request_refresh_token(client, refresh_token) assert _status_code == http.HTTPStatus.BAD_REQUEST From ecec6feac0e4fe02764c3f86e20b0110b6918f00 Mon Sep 17 00:00:00 2001 From: Kenroy Gobourne <14842108+sultanofcardio@users.noreply.github.com> Date: Tue, 10 Dec 2024 12:17:23 -0500 Subject: [PATCH 03/10] chore: Include extra data in call to JIRA webhook (#1665) Whenever a release candidate deployment happens from this repository, a GitHub Actions workflow attempts to process the tickets it contains, and consumes a Jira webhook that triggers an automation to move those tickets into the "To Be Tested" column. I recently updated that automation to also leave a comment on the ticket when the deployment happens This PR adds more details to the webhook call so that the comment may include more details about the deployment. These details are: - The release candidate tag - The repository URL --- .github/workflows/update-jira-tickets.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/update-jira-tickets.yaml b/.github/workflows/update-jira-tickets.yaml index bf30629e1ea..b9c11b48f67 100644 --- a/.github/workflows/update-jira-tickets.yaml +++ b/.github/workflows/update-jira-tickets.yaml @@ -103,6 +103,8 @@ jobs: echo "tickets=${jiraTickets}" >> $GITHUB_OUTPUT - name: Periodically ping Jenkins for current tag build status + env: + REPO_URL: "${{ github.server_url }}/${{ github.repository }}" run: | repoName=${GITHUB_REPOSITORY##*/} currentTag="${{ steps.get-tag.outputs.tag }}" @@ -124,7 +126,7 @@ jobs: if [[ "$result" == "SUCCESS" ]]; then echo "Build successful! Submitting ticket numbers to Jira" tickets="${{ steps.jira-tickets.outputs.tickets }}" - json="{ \"issues\": $(echo "${tickets}" | jq -R -s -c 'split(" ")[:-1]') }" + json="{ \"issues\": $(echo "${tickets}" | jq -R -s -c 'split(" ")[:-1]'), \"data\": { \"tag\": \"${currentTag}\", \"repository\": \"${REPO_URL}\" } }" curl -X POST -H 'Content-Type: application/json' --url "${JIRA_WEBHOOK_URL}" --data "$json" break elif [[ "$result" != "null" ]]; then From 9a74e6e7881cb3779dd980286da1aeaa556814d0 Mon Sep 17 00:00:00 2001 From: Andrew Weiland Date: Wed, 11 Dec 2024 08:59:59 -0500 Subject: [PATCH 04/10] chore: Add structured logging for DataDog integration (M2-8041) (#1675) * Adding DD dependencies * Better json logging * More logging * Structured logging * More logging * docker tweak * Fixes * fixed test suite * Minor refactor * Tweaks * Datadog in feature env * Fixed startup * sidecars * Fixing manifest * Works? * Datadog tweaks * Patching works * test fixes * Manifest update * fixed build/deploy --- .dockerignore | 2 + .env.default | 7 +- .github/workflows/pr-open.yml | 1 + .github/workflows/run_build_deploy.yaml | 4 +- .gitignore | 1 + Pipfile | 10 +- Pipfile.lock | 270 ++++++++++++------ compose/fastapi/Dockerfile | 5 + compose/fastapi/ecs-start-feature | 2 +- compose/fastapi/start | 9 +- compose/fastapi/start-datadog | 15 + .../mindlogger-backend/addons/svc-role.yaml | 7 + copilot/mindlogger-backend/manifest.yml | 72 ++++- docker-compose.yaml | 2 +- src/infrastructure/app.py | 21 ++ src/infrastructure/datadog.py | 202 +++++++++++++ src/infrastructure/http/execeptions.py | 6 + src/infrastructure/logger.py | 30 +- src/main.py | 16 +- uvicorn_disable_logging.json | 40 +++ 20 files changed, 618 insertions(+), 104 deletions(-) create mode 100644 compose/fastapi/start-datadog create mode 100644 src/infrastructure/datadog.py create mode 100644 uvicorn_disable_logging.json diff --git a/.dockerignore b/.dockerignore index 5b0e73d585c..d2898a3b002 100644 --- a/.dockerignore +++ b/.dockerignore @@ -7,3 +7,5 @@ docker-compose.yaml *.md *.rst venv*/ +allure-results +.git \ No newline at end of file diff --git a/.env.default b/.env.default index bccdc69cc7e..6fb8101f98f 100644 --- a/.env.default +++ b/.env.default @@ -94,4 +94,9 @@ OTEL_EXPORTER_OTLP_TRACES_ENDPOINT= # OTEL_TRACES_EXPORTER # OTEL_EXPORTER_OTLP_CERTIFICATE -MULTI_INFORMANT__TEMP_RELATION_EXPIRY_SECS=86400 \ No newline at end of file +MULTI_INFORMANT__TEMP_RELATION_EXPIRY_SECS=86400 + +# False for local dev +DD_TRACE_ENABLED=false +DD_LOGS_ENABLED=false +LOG_JSON_FORMAT=false \ No newline at end of file diff --git a/.github/workflows/pr-open.yml b/.github/workflows/pr-open.yml index 70eb82d9f63..26ae6c6dde6 100644 --- a/.github/workflows/pr-open.yml +++ b/.github/workflows/pr-open.yml @@ -49,6 +49,7 @@ jobs: permissions: issues: write pull-requests: write + discussions: write needs: [ run-unit-tests ] steps: - name: Post the link to the report diff --git a/.github/workflows/run_build_deploy.yaml b/.github/workflows/run_build_deploy.yaml index eba2cf403e9..bc48a18cfec 100644 --- a/.github/workflows/run_build_deploy.yaml +++ b/.github/workflows/run_build_deploy.yaml @@ -2,8 +2,8 @@ name: Build and Deploy on: push: -# branches: -# - develop + branches: + - develop workflow_dispatch: {} diff --git a/.gitignore b/.gitignore index bdb7dc1d53f..b08efd43f93 100644 --- a/.gitignore +++ b/.gitignore @@ -62,3 +62,4 @@ venv/ # MacOS .DS_Store + diff --git a/Pipfile b/Pipfile index bd80fd374cd..161b11d5e8a 100644 --- a/Pipfile +++ b/Pipfile @@ -51,8 +51,14 @@ taskiq = { extras = ["reload"], version = "==0.11.7" } taskiq-aio-pika = "==0.4.1" taskiq-fastapi = "==0.3.2" taskiq-redis = "==1.0.2" -typer = "==0.15.1" -uvicorn = { extras = ["standard"], version = "==0.32.1" } +typer = "==0.12.5" +uvicorn = { extras = ["standard"], version = "==0.32.0" } +pyjwt = "==2.9.0" +ddtrace = "==2.17.2" +bytecode = "==0.16.0" +structlog = "==24.4.0" +asgi-correlation-id = "==4.3.4" + [dev-packages] allure-pytest = "==2.13.5" diff --git a/Pipfile.lock b/Pipfile.lock index 2d6005f6f8c..918ec77a790 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "8372ca972d5ba9b60fc31e38f4767a9ac379a32b80a59bbfbeb4f9f4fbd26444" + "sha256": "1c3202a870592cdd50f1677fbec2bd33d63fc395b8b4b7d28abbedaf0dc33023" }, "pipfile-spec": 6, "requires": { @@ -166,6 +166,15 @@ "markers": "python_version >= '3.9'", "version": "==4.7.0" }, + "asgi-correlation-id": { + "hashes": [ + "sha256:36ce69b06c7d96b4acb89c7556a4c4f01a972463d3d49c675026cbbd08e9a0a2", + "sha256:ea6bc310380373cb9f731dc2e8b2b6fb978a76afe33f7a2384f697b8d6cd811d" + ], + "index": "pypi", + "markers": "python_version >= '3.8' and python_version < '4.0'", + "version": "==4.3.4" + }, "asgiref": { "hashes": [ "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47", @@ -306,11 +315,20 @@ }, "botocore": { "hashes": [ - "sha256:17b778016644e9342ca3ff2f430c1d1db0c6126e9b41a57cff52ac58e7a455e0", - "sha256:3faa27d65841499762228902d7e215fa99a4c2fdc76c9113e1c3f339bdf685b8" + "sha256:8a6a0f5ad119e38d850571df8c625dbad66aec1b20c15f84cdcb95258f9f1edb", + "sha256:b2e3ecdd1769f011f72c4c0d0094570ba125f4ca327f24269e4d68eb5d9878b9" ], "markers": "python_version >= '3.8'", - "version": "==1.35.77" + "version": "==1.35.73" + }, + "bytecode": { + "hashes": [ + "sha256:06676a3c3bccc9d3dc73ee625650ea57df2bc117358826f4f290f0e1faa42292", + "sha256:76080b7c0eb9e7e17f961d61fd06e933aa47f3b753770a3249537439d8203a25" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==0.16.0" }, "cachecontrol": { "hashes": [ @@ -561,6 +579,73 @@ "markers": "python_version >= '3.7'", "version": "==43.0.3" }, + "ddtrace": { + "hashes": [ + "sha256:03d5775bd783c3cec504153c1937864e3fb43e587389501d9c6d1a43e2495f8d", + "sha256:07757f5f0dc59e2462d1f20f4df4a4d794daaa2a040c78d1c65a7a891651843d", + "sha256:08d8c669778960bcb8ccbd081ba5c2302cda76994df60d392f77faa136fef342", + "sha256:09fbb9b6297ae5c31dae3b38c39e07852b17169627399846aa9ff7778057f4b3", + "sha256:13b5ea46d9876892acf427c1531bf48763c3ed8fc6b0bf48bd5eac8480c082c2", + "sha256:159df47a155cbcde7f6ab378cedfe26653818468ea715b77388cf029e35a0fed", + "sha256:16962c84897617d9ee75792a0f5214c0c48ab8e34e156a73dec9eab6267e2054", + "sha256:16d49ba58cec4233e1bce5afb5c9bf81194407f934557f104e6eea9ae408b7c5", + "sha256:1733d74bdb499ce7dc019d9902e2771618fd86c68e183f47d8006b851d2aabb6", + "sha256:1f10fd6863fce1ad9356f7bb077f496faec412dd047e8f983c34bfdfd52f86ae", + "sha256:1f9be863096c3281640d71e140eea019d646cdd033ac9a75be4df2496f27f0e7", + "sha256:205b98c5cda2c3147947a0d90ac4a26a19b261a043a588968cdc42599819c33a", + "sha256:20950e3a51a17b56dcd304b6e3b95967815b220d304c52e99f7e68e54ff64d48", + "sha256:211b00ca14a51342442db04a4b9b4792bc9e4f677e4aa18dd12ea1016f01941a", + "sha256:2171e5f378d888f8ef9b99d83aa758d7305f5dcfc353f48c6d77094ed46256e2", + "sha256:23572aca43a809c67e8bf9de8aa1f2a461a07643d94c74bee0284a242e6e3c86", + "sha256:2506473fbc8fefef8c819df15cf80036d12b64dde03457fa20814846508f57e7", + "sha256:25ef8a180ce061059b34ceecc11ed242458c5d995dc651555cd345ceea5c05da", + "sha256:2671a9278bcffd83bb6ce4894c0ff8b4ed17621a3833fe681ec58b6bc327b15a", + "sha256:2e18dfbdb1a0b3376539e1a5f56fbac591fb5c54cee633b0f9712e365fd4f2e0", + "sha256:344ada1fe450b7f2ee709c059248dad48bf0e3c6cffd57b81f7bffbcd02c472e", + "sha256:383af2c65638001f4050b7c188399d5d8036241bc7dc2c07db460619a0b836c6", + "sha256:43dd59f00cad29b1dd88aae26d42856da281946218f2f65451af1dc8e873a88c", + "sha256:4acd7096a0f2c2ab05263584b1442576a9a97941e9c2c55ab6eab61860e69518", + "sha256:4b2271eb37d6287001c4b85e3591b14b1cd48978043f0bf7a3caeb92a99747e6", + "sha256:520eedb1ad248e3da81f203cdde19d300b17c59e72d2b7b69028eeb98b00d5e8", + "sha256:54826b3a28a6c2d6b277969c90cd8963e5c56afea6ad69e87a48df611bf28f49", + "sha256:55e97f2dd32a28129833b42375fa0f3eab6b8a5de10738d4d613404e4f007355", + "sha256:59f722180291d3d58a260deb811943ec1fb8f9ca3c1f2e2772903ff1e34666e0", + "sha256:653a397eaa84baf6b2f1c584341ad79c115efbc68c10352b542fc4cf23d3b797", + "sha256:6551f9e15fdd9b84f2dadad59b1ca3448ebb11b333b2d5ddb6aed27f656f6b0d", + "sha256:67ed43c15259cb17a38ebc65b689ff8ee10b151221bd80b46cb27fa99df2696d", + "sha256:685029a27af474fe0d38e39ff451387647668043d2258e64a520651c50613db1", + "sha256:6b9b93d3406107e4223bfdcf26f3275b7a216ddb9a1e7eacb06b25f55416c153", + "sha256:6d2a555ad617f999140e60d9dc9a9a1ff6eeade39bc0b8101e664489b25756d0", + "sha256:79a08f9461de39721c234d376ac87ef43e615c9383469a292e9d74ac7759bc20", + "sha256:7f31b6e5d09019c8d70a7336b19825963c8c2193e12ea0778332327f33bf54a8", + "sha256:8ecf615b2d54edcf8b2c99bf4cdce4a96c6d7409f3e7cf8cc4e43f8e2957e4a5", + "sha256:9124c1991c7601c6aebe36762e8a616395beb89b8a6345957486c46657f1d8fd", + "sha256:9386da2efbb783a0945a2fec53e03e88ccc9dfcdbde04b7bdd382415ccb60764", + "sha256:a192e13c36e1690ffc31f616242e947f84db3c41906882b664632266cd43aa22", + "sha256:a2fe14c805591b887e36c75309fac788022e9391a02c27f959cf85843102eb95", + "sha256:a309d29b999fff7fee64e654e50f591c989d90d0b4f6c8b2b40852ffb361fcde", + "sha256:a605204be072643a66eb7c76d884568d802325fe0fb7a46cae54cad7104b5515", + "sha256:add2d7a8ce598c0d6d3f07d38fd95bb0503b8262b62d9924b7514392cd714cef", + "sha256:c04ea708d1fe330f39e0928642e14cdbe4fd26eeef0e45fceca9675c11f5201c", + "sha256:c8d96c4eed6ca0c8256351145cbbc80fdeea2c3d42d6e72006afbb14016111e5", + "sha256:d4df3a12351a860508787579cc43542930f0b0684472ef3069f90211e5e6ee1d", + "sha256:d998b4f570b98e09ca357e1f9c69c02f088ed88ecc1dbfdf9b9639709c6e4413", + "sha256:d9a565d4037f397360318225c6daede194ac410587fffde13f659ddbd3a4f3a6", + "sha256:d9dbb21007f143aef6a72cc3e130bc7dcbb4617aebc311d5e5d5bef274f6f53e", + "sha256:dda4bddec8debb5461a95b6b0ad8148952c4f5a19b51e9b8aca29aa349f719fc", + "sha256:e47e52524f5296159c2183a94070e00904d89cbe104ad19edbe4b879fb5d2b06", + "sha256:ea20097bbfc9295473542500f5e8c2ce7425e0caeab8a842c257075640da1f93", + "sha256:ec770fc73bc102bf07931b3267bdd515a83a6588b7724d2406b175df7c7c66ed", + "sha256:ed2a3a03b15206a1bdea55fc542f3f1aea5d7cbd0b3242b9ee12c286f1a089a5", + "sha256:ee33ae6ee2e4bb2c73f4fcacead3434e70b4bb680698e999c4ba60f9dc624c2d", + "sha256:f367b32a17537742c5a5a3373545c4d75cec1e447ce81da30feb1b221283cb30", + "sha256:f99ae5a54400781ef752eaf1c8f77c670cd7381eaba72293400cd6bc9e32ec56", + "sha256:fef6b3bb9faf1f90d8a7e8c94dec5f2d6874be84fb86715f7525a2e0b1f70ff1" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==2.17.2" + }, "deprecated": { "hashes": [ "sha256:353bc4a8ac4bfc96800ddab349d89c25dec1079f65fd53acdcc1e0b975b21320", @@ -585,13 +670,13 @@ "markers": "python_version >= '3.5'", "version": "==1.3.1" }, - "exceptiongroup": { + "envier": { "hashes": [ - "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", - "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" + "sha256:3309a01bb3d8850c9e7a31a5166d5a836846db2faecb79b9cb32654dd50ca9f9", + "sha256:73609040a76be48bbcb97074d9969666484aa0de706183a6e9ef773156a8a6a9" ], "markers": "python_version >= '3.7'", - "version": "==1.2.2" + "version": "==0.6.1" }, "fastapi": { "hashes": [ @@ -729,11 +814,11 @@ "grpc" ], "hashes": [ - "sha256:10d82ac0fca69c82a25b3efdeefccf6f28e02ebb97925a8cce8edbfe379929d9", - "sha256:e255640547a597a4da010876d333208ddac417d60add22b6851a0c66a831fcaf" + "sha256:2ceb087315e6af43f256704b871d99326b1f12a9d6ce99beaedec99ba26a0ace", + "sha256:c20100d4c4c41070cf365f1d8ddf5365915291b5eb11b83829fbd1c999b5122f" ], - "markers": "python_version >= '3.7'", - "version": "==2.24.0" + "markers": "platform_python_implementation != 'PyPy'", + "version": "==2.23.0" }, "google-api-python-client": { "hashes": [ @@ -2053,12 +2138,13 @@ }, "sentry-sdk": { "hashes": [ - "sha256:467df6e126ba242d39952375dd816fbee0f217d119bf454a8ce74cf1e7909e8d", - "sha256:ebdc08228b4d131128e568d696c210d846e5b9d70aa0327dec6b1272d9d40b84" + + "sha256:7b0b3b709dee051337244a09a30dbf6e95afe0d34a1f8b430d45e0982a7c125b", + "sha256:ee4a4d2ae8bfe3cac012dcf3e4607975904c137e1738116549fc3dbbb6ff0e36" ], "index": "pypi", "markers": "python_version >= '3.6'", - "version": "==2.19.2" + "version": "==2.19.0" }, "setuptools": { "hashes": [ @@ -2162,6 +2248,15 @@ "markers": "python_version >= '3.8'", "version": "==0.41.3" }, + "structlog": { + "hashes": [ + "sha256:597f61e80a91cc0749a9fd2a098ed76715a1c8a01f73e336b746504d1aad7610", + "sha256:b27bfecede327a6d2da5fbc96bd859f114ecc398a6389d664f62085ee7ae6fc4" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==24.4.0" + }, "taskiq": { "extras": [ "reload" @@ -2403,7 +2498,6 @@ "sha256:fbd0ab7a9943bbddb87cbc2bf2f09317e74c77dc55b1f5657f81d04666c25269", "sha256:ffd98a299b0a74d1b704ef0ed959efb753e656a4e0425c14e46ae4c3cbdd2919" ], - "markers": "python_version >= '3.9'", "version": "==1.0.0" }, "websockets": { @@ -2478,7 +2572,6 @@ "sha256:f6cf0ad281c979306a6a34242b371e90e891bce504509fb6bb5246bbbf31e7b6", "sha256:f95ba34d71e2fa0c5d225bde3b3bdb152e957150100e75c86bc7f3964c450d89" ], - "markers": "python_version >= '3.9'", "version": "==14.1" }, "wrapt": { @@ -2552,6 +2645,15 @@ "markers": "python_version >= '3.8'", "version": "==1.17.0" }, + "xmltodict": { + "hashes": [ + "sha256:201e7c28bb210e374999d1dde6382923ab0ed1a8a5faeece48ab525b7810a553", + "sha256:20cc7d723ed729276e808f26fb6b3599f786cbc37e06c65e192ba77c40f20aac" + ], + "markers": "python_version >= '3.6'", + "version": "==0.14.2" + + }, "yarl": { "hashes": [ "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba", @@ -2846,71 +2948,72 @@ "toml" ], "hashes": [ - "sha256:0824a28ec542a0be22f60c6ac36d679e0e262e5353203bea81d44ee81fe9c6d4", - "sha256:085161be5f3b30fd9b3e7b9a8c301f935c8313dcf928a07b116324abea2c1c2c", - "sha256:0ae1387db4aecb1f485fb70a6c0148c6cdaebb6038f1d40089b1fc84a5db556f", - "sha256:0d59fd927b1f04de57a2ba0137166d31c1a6dd9e764ad4af552912d70428c92b", - "sha256:0f957943bc718b87144ecaee70762bc2bc3f1a7a53c7b861103546d3a403f0a6", - "sha256:13a9e2d3ee855db3dd6ea1ba5203316a1b1fd8eaeffc37c5b54987e61e4194ae", - "sha256:1a330812d9cc7ac2182586f6d41b4d0fadf9be9049f350e0efb275c8ee8eb692", - "sha256:22be16571504c9ccea919fcedb459d5ab20d41172056206eb2994e2ff06118a4", - "sha256:2d10e07aa2b91835d6abec555ec8b2733347956991901eea6ffac295f83a30e4", - "sha256:35371f8438028fdccfaf3570b31d98e8d9eda8bb1d6ab9473f5a390969e98717", - "sha256:3c026eb44f744acaa2bda7493dad903aa5bf5fc4f2554293a798d5606710055d", - "sha256:41ff7b0da5af71a51b53f501a3bac65fb0ec311ebed1632e58fc6107f03b9198", - "sha256:4401ae5fc52ad8d26d2a5d8a7428b0f0c72431683f8e63e42e70606374c311a1", - "sha256:44349150f6811b44b25574839b39ae35291f6496eb795b7366fef3bd3cf112d3", - "sha256:447af20e25fdbe16f26e84eb714ba21d98868705cb138252d28bc400381f6ffb", - "sha256:4a8d8977b0c6ef5aeadcb644da9e69ae0dcfe66ec7f368c89c72e058bd71164d", - "sha256:4e12ae8cc979cf83d258acb5e1f1cf2f3f83524d1564a49d20b8bec14b637f08", - "sha256:592ac539812e9b46046620341498caf09ca21023c41c893e1eb9dbda00a70cbf", - "sha256:5e6b86b5847a016d0fbd31ffe1001b63355ed309651851295315031ea7eb5a9b", - "sha256:608a7fd78c67bee8936378299a6cb9f5149bb80238c7a566fc3e6717a4e68710", - "sha256:61f70dc68bd36810972e55bbbe83674ea073dd1dcc121040a08cdf3416c5349c", - "sha256:65dad5a248823a4996724a88eb51d4b31587aa7aa428562dbe459c684e5787ae", - "sha256:777abfab476cf83b5177b84d7486497e034eb9eaea0d746ce0c1268c71652077", - "sha256:7e216d8044a356fc0337c7a2a0536d6de07888d7bcda76febcb8adc50bdbbd00", - "sha256:85d9636f72e8991a1706b2b55b06c27545448baf9f6dbf51c4004609aacd7dcb", - "sha256:899b8cd4781c400454f2f64f7776a5d87bbd7b3e7f7bda0cb18f857bb1334664", - "sha256:8a289d23d4c46f1a82d5db4abeb40b9b5be91731ee19a379d15790e53031c014", - "sha256:8d2dfa71665a29b153a9681edb1c8d9c1ea50dfc2375fb4dac99ea7e21a0bcd9", - "sha256:8e3c3e38930cfb729cb8137d7f055e5a473ddaf1217966aa6238c88bd9fd50e6", - "sha256:8f8770dfc6e2c6a2d4569f411015c8d751c980d17a14b0530da2d7f27ffdd88e", - "sha256:932fc826442132dde42ee52cf66d941f581c685a6313feebed358411238f60f9", - "sha256:96d636c77af18b5cb664ddf12dab9b15a0cfe9c0bde715da38698c8cea748bfa", - "sha256:97ddc94d46088304772d21b060041c97fc16bdda13c6c7f9d8fcd8d5ae0d8611", - "sha256:98caba4476a6c8d59ec1eb00c7dd862ba9beca34085642d46ed503cc2d440d4b", - "sha256:9901d36492009a0a9b94b20e52ebfc8453bf49bb2b27bca2c9706f8b4f5a554a", - "sha256:99e266ae0b5d15f1ca8d278a668df6f51cc4b854513daab5cae695ed7b721cf8", - "sha256:9c38bf15a40ccf5619fa2fe8f26106c7e8e080d7760aeccb3722664c8656b030", - "sha256:a27801adef24cc30871da98a105f77995e13a25a505a0161911f6aafbd66e678", - "sha256:abd3e72dd5b97e3af4246cdada7738ef0e608168de952b837b8dd7e90341f015", - "sha256:adb697c0bd35100dc690de83154627fbab1f4f3c0386df266dded865fc50a902", - "sha256:b12c6b18269ca471eedd41c1b6a1065b2f7827508edb9a7ed5555e9a56dcfc97", - "sha256:b9389a429e0e5142e69d5bf4a435dd688c14478a19bb901735cdf75e57b13845", - "sha256:ba9e7484d286cd5a43744e5f47b0b3fb457865baf07bafc6bee91896364e1419", - "sha256:bb5555cff66c4d3d6213a296b360f9e1a8e323e74e0426b6c10ed7f4d021e464", - "sha256:be57b6d56e49c2739cdf776839a92330e933dd5e5d929966fbbd380c77f060be", - "sha256:c69e42c892c018cd3c8d90da61d845f50a8243062b19d228189b0224150018a9", - "sha256:ccc660a77e1c2bf24ddbce969af9447a9474790160cfb23de6be4fa88e3951c7", - "sha256:d5275455b3e4627c8e7154feaf7ee0743c2e7af82f6e3b561967b1cca755a0be", - "sha256:d75cded8a3cff93da9edc31446872d2997e327921d8eed86641efafd350e1df1", - "sha256:d872ec5aeb086cbea771c573600d47944eea2dcba8be5f3ee649bfe3cb8dc9ba", - "sha256:d891c136b5b310d0e702e186d70cd16d1119ea8927347045124cb286b29297e5", - "sha256:db1dab894cc139f67822a92910466531de5ea6034ddfd2b11c0d4c6257168073", - "sha256:e28bf44afa2b187cc9f41749138a64435bf340adfcacb5b2290c070ce99839d4", - "sha256:e5ea1cf0872ee455c03e5674b5bca5e3e68e159379c1af0903e89f5eba9ccc3a", - "sha256:e77363e8425325384f9d49272c54045bbed2f478e9dd698dbc65dbc37860eb0a", - "sha256:ee5defd1733fd6ec08b168bd4f5387d5b322f45ca9e0e6c817ea6c4cd36313e3", - "sha256:f1592791f8204ae9166de22ba7e6705fa4ebd02936c09436a1bb85aabca3e599", - "sha256:f2d1ec60d6d256bdf298cb86b78dd715980828f50c46701abc3b0a2b3f8a0dc0", - "sha256:f3ca78518bc6bc92828cd11867b121891d75cae4ea9e908d72030609b996db1b", - "sha256:f7b15f589593110ae767ce997775d645b47e5cbbf54fd322f8ebea6277466cec", - "sha256:fd1213c86e48dfdc5a0cc676551db467495a95a662d2396ecd58e719191446e1", - "sha256:ff74026a461eb0660366fb01c650c1d00f833a086b336bdad7ab00cc952072b3" + "sha256:093896e530c38c8e9c996901858ac63f3d4171268db2c9c8b373a228f459bbc5", + "sha256:09b9f848b28081e7b975a3626e9081574a7b9196cde26604540582da60235fdf", + "sha256:0b0c69f4f724c64dfbfe79f5dfb503b42fe6127b8d479b2677f2b227478db2eb", + "sha256:13618bed0c38acc418896005732e565b317aa9e98d855a0e9f211a7ffc2d6638", + "sha256:13690e923a3932e4fad4c0ebfb9cb5988e03d9dcb4c5150b5fcbf58fd8bddfc4", + "sha256:177f01eeaa3aee4a5ffb0d1439c5952b53d5010f86e9d2667963e632e30082cc", + "sha256:193e3bffca48ad74b8c764fb4492dd875038a2f9925530cb094db92bb5e47bed", + "sha256:1defe91d41ce1bd44b40fabf071e6a01a5aa14de4a31b986aa9dfd1b3e3e414a", + "sha256:1f188a2402f8359cf0c4b1fe89eea40dc13b52e7b4fd4812450da9fcd210181d", + "sha256:202a2d645c5a46b84992f55b0a3affe4f0ba6b4c611abec32ee88358db4bb649", + "sha256:24eda3a24a38157eee639ca9afe45eefa8d2420d49468819ac5f88b10de84f4c", + "sha256:2e4e0f60cb4bd7396108823548e82fdab72d4d8a65e58e2c19bbbc2f1e2bfa4b", + "sha256:379c111d3558272a2cae3d8e57e6b6e6f4fe652905692d54bad5ea0ca37c5ad4", + "sha256:37cda8712145917105e07aab96388ae76e787270ec04bcb9d5cc786d7cbb8443", + "sha256:38c51297b35b3ed91670e1e4efb702b790002e3245a28c76e627478aa3c10d83", + "sha256:3985b9be361d8fb6b2d1adc9924d01dec575a1d7453a14cccd73225cb79243ee", + "sha256:3988665ee376abce49613701336544041f2117de7b7fbfe91b93d8ff8b151c8e", + "sha256:3ac47fa29d8d41059ea3df65bd3ade92f97ee4910ed638e87075b8e8ce69599e", + "sha256:3b4b4299dd0d2c67caaaf286d58aef5e75b125b95615dda4542561a5a566a1e3", + "sha256:3ea8bb1ab9558374c0ab591783808511d135a833c3ca64a18ec927f20c4030f0", + "sha256:3fe47da3e4fda5f1abb5709c156eca207eacf8007304ce3019eb001e7a7204cb", + "sha256:428ac484592f780e8cd7b6b14eb568f7c85460c92e2a37cb0c0e5186e1a0d076", + "sha256:44e6c85bbdc809383b509d732b06419fb4544dca29ebe18480379633623baafb", + "sha256:4674f0daa1823c295845b6a740d98a840d7a1c11df00d1fd62614545c1583787", + "sha256:4be32da0c3827ac9132bb488d331cb32e8d9638dd41a0557c5569d57cf22c9c1", + "sha256:4db3ed6a907b555e57cc2e6f14dc3a4c2458cdad8919e40b5357ab9b6db6c43e", + "sha256:5c52a036535d12590c32c49209e79cabaad9f9ad8aa4cbd875b68c4d67a9cbce", + "sha256:629a1ba2115dce8bf75a5cce9f2486ae483cb89c0145795603d6554bdc83e801", + "sha256:62a66ff235e4c2e37ed3b6104d8b478d767ff73838d1222132a7a026aa548764", + "sha256:63068a11171e4276f6ece913bde059e77c713b48c3a848814a6537f35afb8365", + "sha256:63c19702db10ad79151a059d2d6336fe0c470f2e18d0d4d1a57f7f9713875dcf", + "sha256:644ec81edec0f4ad17d51c838a7d01e42811054543b76d4ba2c5d6af741ce2a6", + "sha256:6535d996f6537ecb298b4e287a855f37deaf64ff007162ec0afb9ab8ba3b8b71", + "sha256:6f4548c5ead23ad13fb7a2c8ea541357474ec13c2b736feb02e19a3085fac002", + "sha256:716a78a342679cd1177bc8c2fe957e0ab91405bd43a17094324845200b2fddf4", + "sha256:74610105ebd6f33d7c10f8907afed696e79c59e3043c5f20eaa3a46fddf33b4c", + "sha256:768939f7c4353c0fac2f7c37897e10b1414b571fd85dd9fc49e6a87e37a2e0d8", + "sha256:86cffe9c6dfcfe22e28027069725c7f57f4b868a3f86e81d1c62462764dc46d4", + "sha256:8aae5aea53cbfe024919715eca696b1a3201886ce83790537d1c3668459c7146", + "sha256:8b2b8503edb06822c86d82fa64a4a5cb0760bb8f31f26e138ec743f422f37cfc", + "sha256:912e95017ff51dc3d7b6e2be158dedc889d9a5cc3382445589ce554f1a34c0ea", + "sha256:9a7b8ac36fd688c8361cbc7bf1cb5866977ece6e0b17c34aa0df58bda4fa18a4", + "sha256:9e89d5c8509fbd6c03d0dd1972925b22f50db0792ce06324ba069f10787429ad", + "sha256:ae270e79f7e169ccfe23284ff5ea2d52a6f401dc01b337efb54b3783e2ce3f28", + "sha256:b07c25d52b1c16ce5de088046cd2432b30f9ad5e224ff17c8f496d9cb7d1d451", + "sha256:b39e6011cd06822eb964d038d5dff5da5d98652b81f5ecd439277b32361a3a50", + "sha256:bd55f8fc8fa494958772a2a7302b0354ab16e0b9272b3c3d83cdb5bec5bd1779", + "sha256:c15b32a7aca8038ed7644f854bf17b663bc38e1671b5d6f43f9a2b2bd0c46f63", + "sha256:c1b4474beee02ede1eef86c25ad4600a424fe36cff01a6103cb4533c6bf0169e", + "sha256:c79c0685f142ca53256722a384540832420dff4ab15fec1863d7e5bc8691bdcc", + "sha256:c9ebfb2507751f7196995142f057d1324afdab56db1d9743aab7f50289abd022", + "sha256:d7ad66e8e50225ebf4236368cc43c37f59d5e6728f15f6e258c8639fa0dd8e6d", + "sha256:d82ab6816c3277dc962cfcdc85b1efa0e5f50fb2c449432deaf2398a2928ab94", + "sha256:d9fd2547e6decdbf985d579cf3fc78e4c1d662b9b0ff7cc7862baaab71c9cc5b", + "sha256:de38add67a0af869b0d79c525d3e4588ac1ffa92f39116dbe0ed9753f26eba7d", + "sha256:e19122296822deafce89a0c5e8685704c067ae65d45e79718c92df7b3ec3d331", + "sha256:e44961e36cb13c495806d4cac67640ac2866cb99044e210895b506c26ee63d3a", + "sha256:e4c81ed2820b9023a9a90717020315e63b17b18c274a332e3b6437d7ff70abe0", + "sha256:e683e6ecc587643f8cde8f5da6768e9d165cd31edf39ee90ed7034f9ca0eefee", + "sha256:f39e2f3530ed1626c66e7493be7a8423b023ca852aacdc91fb30162c350d2a92", + "sha256:f56f49b2553d7dd85fd86e029515a221e5c1f8cb3d9c38b470bc38bde7b8445a", + "sha256:fb9fc32399dca861584d96eccd6c980b69bbcd7c228d06fb74fe53e007aa8ef9" ], "markers": "python_version >= '3.9'", - "version": "==7.6.9" + "version": "==7.6.8" + }, "decorator": { "hashes": [ @@ -3135,7 +3238,6 @@ "sha256:1f519121bc366af3e485310dc8041d2e86e5173c1a320fac3dc9d2604069b83e", "sha256:ace9b420ce52995bb4f05e7425eedf19e433c981dfe7a831ab391e2fa2e1a195" ], - "markers": "python_version >= '3.8'", "version": "==1.2.1" }, "identify": { @@ -3184,7 +3286,9 @@ "sha256:85ec56a7e20f6c38fce7727dcca699ae4ffc85985aa7b23635a8008f918ae321", "sha256:cb0a405a306d2995a5cbb9901894d240784a9f341394c6ba3f4fe8c6eb89ff6e" ], - "markers": "python_version >= '3.10'", + + "markers": "python_version >= '3.11'", + "version": "==8.30.0" }, "jedi": { @@ -3473,7 +3577,7 @@ "sha256:77ca0ad1c435b6e363d7e8623d7cc4fcf2cf15513bf77a1c1b2e814930ac57cc", "sha256:f04b3e1ba35747ac86e96ec33e3bb9748ce08e254dc2a1c6253945901beec804" ], - "markers": "python_version >= '3.9'", + "markers": "python_version >= '3.8' and python_version < '3.12'", "version": "==3.12.0" }, "prompt-toolkit": { diff --git a/compose/fastapi/Dockerfile b/compose/fastapi/Dockerfile index bb6fd504ebd..b87032c7669 100644 --- a/compose/fastapi/Dockerfile +++ b/compose/fastapi/Dockerfile @@ -37,6 +37,11 @@ RUN sed -i 's/\r$//g' /fastapi-entrypoint && chmod +x /fastapi-entrypoint COPY --chown=code:code ./compose/fastapi/start /fastapi-start RUN sed -i 's/\r$//g' /fastapi-start && chmod +x /fastapi-start +COPY --chown=code:code ./compose/fastapi/start-datadog /fastapi-start-datadog +RUN sed -i 's/\r$//g' /fastapi-start-datadog && chmod +x /fastapi-start-datadog + + + COPY --chown=code:code ./compose/fastapi/migrate /fastapi-migrate RUN sed -i 's/\r$//g' /fastapi-migrate && chmod +x /fastapi-migrate diff --git a/compose/fastapi/ecs-start-feature b/compose/fastapi/ecs-start-feature index 55127c6f89f..4872f435e78 100644 --- a/compose/fastapi/ecs-start-feature +++ b/compose/fastapi/ecs-start-feature @@ -4,4 +4,4 @@ set -eo pipefail set -o nounset ENV=testing /fastapi-migrate -/fastapi-start \ No newline at end of file +/fastapi-start-datadog \ No newline at end of file diff --git a/compose/fastapi/start b/compose/fastapi/start index 8eed1f2ce1c..03c782799e7 100644 --- a/compose/fastapi/start +++ b/compose/fastapi/start @@ -8,6 +8,9 @@ set -o nounset export UVICORN_HOST="0.0.0.0" export UVICORN_PORT=80 -opentelemetry-instrument \ - --logs_exporter otlp \ - uvicorn src.main:app --reload --host ${UVICORN_HOST} --port ${UVICORN_PORT} --proxy-headers +#opentelemetry-instrument \ +# --logs_exporter otlp \ +# uvicorn src.main:app --reload --host ${UVICORN_HOST} --port ${UVICORN_PORT} --proxy-headers + + +uvicorn src.main:app --reload --host ${UVICORN_HOST} --port ${UVICORN_PORT} --proxy-headers diff --git a/compose/fastapi/start-datadog b/compose/fastapi/start-datadog new file mode 100644 index 00000000000..77f82aad692 --- /dev/null +++ b/compose/fastapi/start-datadog @@ -0,0 +1,15 @@ +#!/bin/bash + +set -o errexit +set -o pipefail +set -o nounset + +# https://www.uvicorn.org/settings/ +export UVICORN_HOST="0.0.0.0" +export UVICORN_PORT=80 + + +LOG_JSON_FORMAT=true DD_TRACE_ENABLED=true uvicorn main:app \ + --host ${UVICORN_HOST} --port ${UVICORN_PORT} \ + --reload --proxy-headers \ + --log-config uvicorn_disable_logging.json diff --git a/copilot/mindlogger-backend/addons/svc-role.yaml b/copilot/mindlogger-backend/addons/svc-role.yaml index aa504c5e431..a4ad8a54565 100644 --- a/copilot/mindlogger-backend/addons/svc-role.yaml +++ b/copilot/mindlogger-backend/addons/svc-role.yaml @@ -39,6 +39,13 @@ Resources: - "arn:aws:s3:::cmiml-feature-answer/*" - "arn:aws:s3:::cmiml-feature-operations/*" + - Sid: DataDogAgent + Effect: Allow + Action: + - "ecs:ListClusters" + - "ecs:ListContainerInstances" + - "ecs:DescribeContainerInstances" + Resource: ["*"] Outputs: diff --git a/copilot/mindlogger-backend/manifest.yml b/copilot/mindlogger-backend/manifest.yml index a1cd1e0ef4f..ca4e006aeb8 100644 --- a/copilot/mindlogger-backend/manifest.yml +++ b/copilot/mindlogger-backend/manifest.yml @@ -56,7 +56,19 @@ storage: efs: false path: /app/uploads read_only: false - + # For Datadog +# sock: +# efs: false +# path: '/var/run/docker.sock' +# read_only: true +# proc: +# efs: false +# path: '/proc/' +# read_only: true +# cgroup: +# efs: false +# path: '/sys/fs/cgroup/' +# read_only: true variables: # Python configurations @@ -119,6 +131,10 @@ variables: # CDN__LEGACY_ACCESS_KEY: CDN__TTL_SIGNED_URLS: 3600 + DD_ENV: feature + DD_SERVICE: backend-api + DD_VERSION: ${COPILOT_ENVIRONMENT_NAME} + # jsonld converter JSONLD_CONVERTER__PROTOCOL_PASSWORD: @@ -158,4 +174,56 @@ taskdef_overrides: value: Name: "nofile" SoftLimit: 1048576 - HardLimit: 1048576 \ No newline at end of file + HardLimit: 1048576 + +logging: + destination: + Name: "datadog" + Host: "http-intake.logs.datadoghq.com" + dd_service: "backend-api" + dd_source: "backend" + dd_message_key: "log" + dd_tags: "project:fluentbit" + TLS: "on" + provider: "ecs" + configFilePath: "/fluent-bit/configs/parse-json.conf" + enableMetadata: true + secretOptions: + apikey: + secretsmanager: "cmiml-feature-${COPILOT_ENVIRONMENT_NAME}:DD_API_KEY::" + + +sidecars: + datadog: + image: public.ecr.aws/datadog/agent:7 + variables: + ECS_FARGATE: true + DD_SITE: us5.datadoghq.com + DD_ENV: ${COPILOT_ENVIRONMENT_NAME} + DD_LOGS_ENABLED: true + DD_LOGS_CONFIG_CONTAINER_COLLECT_ALL: true + DD_CONTAINER_EXCLUDE: name:datadog-agent + DD_APM_ENABLED: true + secrets: + DD_API_KEY: + secretsmanager: "cmiml-feature-${COPILOT_ENVIRONMENT_NAME}:DD_API_KEY::" + + #/copilot/${COPILOT_APPLICATION_NAME}/${COPILOT_ENVIRONMENT_NAME}/secrets/DATADOG_API_KEY +# mount_points: +# - source_volume: sock +# path: '/var/run/docker.sock' +# - source_volume: proc +# path: '/proc/' +# - source_volume: cgroup +# path: '/sys/fs/cgroup/' + +# firelens: +# essential: true +# image: amazon/aws-for-fluent-bit:stable +# name: log_router +# firelensConfiguration: +# type: fluentbit +# options: +# enable-ecs-log-metadata: 'true' +# config-file-type: file +# config-file-value: "/fluent-bit/configs/parse-json.conf" \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml index 41b80843da8..d0567b558c9 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -44,7 +44,7 @@ services: args: - PIPENV_EXTRA_ARGS=--dev entrypoint: /fastapi-entrypoint - command: /fastapi-start + command: /fastapi-start-datadog env_file: .env depends_on: - postgres diff --git a/src/infrastructure/app.py b/src/infrastructure/app.py index 54f5f15583b..786b11e3e08 100644 --- a/src/infrastructure/app.py +++ b/src/infrastructure/app.py @@ -1,6 +1,7 @@ from typing import Iterable, Type import sentry_sdk +from asgi_correlation_id import CorrelationIdMiddleware from fastapi import FastAPI from fastapi.exceptions import RequestValidationError from fastapi.routing import APIRouter @@ -28,6 +29,7 @@ import middlewares as middlewares_ from apps.shared.exception import BaseError from config import settings +from infrastructure.datadog import StructuredLoggingMiddleware from infrastructure.http.execeptions import ( custom_base_errors_handler, pydantic_validation_errors_handler, @@ -77,6 +79,8 @@ ), (middlewares_.InternalizationMiddleware, {}), (middlewares_.CORSMiddleware, middlewares_.cors_options), + (StructuredLoggingMiddleware, {}), + (CorrelationIdMiddleware, {}), ) @@ -108,4 +112,21 @@ def create_app(): # https://github.com/Tufin/oasdiff/issues/52 app.openapi_version = "3.0.3" + # UGLY HACK + # Datadog's `TraceMiddleware` is applied as the very first middleware + # in the list, by patching `FastAPI` constructor. + # Unfortunately that means that it is the innermost middleware, so the trace/span are + # created last in the middleware + # chain. Because we want to add the trace_id/span_id in the access log, + # we need to extract it from the middleware list, + # put it back as the outermost middleware, and rebuild the middleware stack. + # tracing_middleware = next( + # (m for m in app.user_middleware if m.cls == TraceMiddleware), None + # ) + # if tracing_middleware is not None: + # app.user_middleware = [m for m in app.user_middleware if m.cls != TraceMiddleware] + # + # app.user_middleware.insert(0, tracing_middleware) + # app.middleware_stack = app.build_middleware_stack() + return app diff --git a/src/infrastructure/datadog.py b/src/infrastructure/datadog.py new file mode 100644 index 00000000000..bc0bd93dab9 --- /dev/null +++ b/src/infrastructure/datadog.py @@ -0,0 +1,202 @@ +import logging +import sys +import time + +import structlog +from asgi_correlation_id.context import correlation_id +from ddtrace import tracer +from fastapi import Request, Response +from starlette.middleware.base import BaseHTTPMiddleware +from structlog.types import EventDict, Processor +from uvicorn.protocols.utils import get_path_with_query_string + + +# Much of this is borrowed from: https://gist.github.com/Brymes/cd8f9f138e12845417a246822f64ca26 + + +# https://github.com/hynek/structlog/issues/35#issuecomment-591321744 +def rename_event_key(_, __, event_dict: EventDict) -> EventDict: + """ + Log entries keep the text message in the `event` field, but Datadog + uses the `message` field. This processor moves the value from one field to + the other. + See https://github.com/hynek/structlog/issues/35#issuecomment-591321744 + """ + event_dict["message"] = event_dict.pop("event") + return event_dict + + +def drop_color_message_key(_, __, event_dict: EventDict) -> EventDict: + """ + Uvicorn logs the message a second time in the extra `color_message`, but we don't + need it. This processor drops the key from the event dict if it exists. + """ + event_dict.pop("color_message", None) + return event_dict + + +def tracer_injection(_, __, event_dict: EventDict) -> EventDict: + """ + Inject Datadog trace info into the event dict. + """ + # get correlation ids from current tracer context + span = tracer.current_span() + trace_id, span_id = (span.trace_id, span.span_id) if span else (None, None) + + # add ids to structlog event dictionary + event_dict["dd.trace_id"] = str(trace_id or 0) + event_dict["dd.span_id"] = str(span_id or 0) + + return event_dict + + +def setup_structured_logging(json_logs: bool = False, log_level: str = "INFO"): + """ + Setup logging for the application. + """ + timestamper = structlog.processors.TimeStamper(fmt="iso") + + shared_processors: list[Processor] = [ + structlog.contextvars.merge_contextvars, + structlog.stdlib.add_logger_name, + structlog.stdlib.add_log_level, + structlog.stdlib.PositionalArgumentsFormatter(), + structlog.stdlib.ExtraAdder(), + drop_color_message_key, + tracer_injection, + timestamper, + structlog.processors.dict_tracebacks, + structlog.processors.StackInfoRenderer(), + ] + + if json_logs: + # We rename the `event` key to `message` only in JSON logs, as Datadog looks for the + # `message` key but the pretty ConsoleRenderer looks for `event` + shared_processors.append(rename_event_key) + # Format the exception only for JSON logs, as we want to pretty-print them when + # using the ConsoleRenderer + shared_processors.append(structlog.processors.format_exc_info) + + structlog.configure( + processors=shared_processors + + [ + # Prepare event dict for `ProcessorFormatter`. + structlog.stdlib.ProcessorFormatter.wrap_for_formatter, + ], + logger_factory=structlog.stdlib.LoggerFactory(), + cache_logger_on_first_use=True, + ) + + log_renderer: structlog.types.Processor + if json_logs: + log_renderer = structlog.processors.JSONRenderer() + else: + log_renderer = structlog.dev.ConsoleRenderer() + + formatter = structlog.stdlib.ProcessorFormatter( + # These run ONLY on `logging` entries that do NOT originate within + # structlog. + foreign_pre_chain=shared_processors, + # These run on ALL entries after the pre_chain is done. + processors=[ + # Remove _record & _from_structlog. + structlog.stdlib.ProcessorFormatter.remove_processors_meta, + log_renderer, + ], + ) + + handler = logging.StreamHandler() + # Use OUR `ProcessorFormatter` to format all `logging` entries. + handler.setFormatter(formatter) + root_logger = logging.getLogger() + root_logger.addHandler(handler) + root_logger.setLevel(log_level.upper()) + + for _log in ["uvicorn", "uvicorn.error", "ddtrace.internal.writer.writer"]: + # Clear the log handlers for uvicorn loggers, and enable propagation + # so the messages are caught by our root logger and formatted correctly + # by structlog + logging.getLogger(_log).handlers.clear() + logging.getLogger(_log).propagate = True + + # Since we re-create the access logs ourselves, to add all information + # in the structured log (see the `DataDogLoggingMiddleware`), we clear + # the handlers and prevent the logs to propagate to a logger higher up in the + # hierarchy (effectively rendering them silent). + logging.getLogger("uvicorn.access").handlers.clear() + logging.getLogger("uvicorn.access").propagate = False + + # def handle_exception(exc_type, exc_value, exc_traceback): + # """ + # Log any uncaught exception instead of letting it be printed by Python + # (but leave KeyboardInterrupt untouched to allow users to Ctrl+C to stop) + # See https://stackoverflow.com/a/16993115/3641865 + # """ + # if issubclass(exc_type, KeyboardInterrupt): + # sys.__excepthook__(exc_type, exc_value, exc_traceback) + # return + # + # root_logger.error( + # "Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback) + # ) + # + # sys.excepthook = handle_exception + + +class StructuredLoggingMiddleware(BaseHTTPMiddleware): + """ + This class makes structured access logs in the application + """ + + async def dispatch(self, request: Request, call_next) -> Response: + structlog.contextvars.clear_contextvars() + # These context vars will be added to all log entries emitted during the request + request_id = correlation_id.get() + structlog.contextvars.bind_contextvars(request_id=request_id) + + start_time = time.perf_counter_ns() + # If the call_next raises an error, we still want to return our own 500 response, + # so we can add headers to it (process time, request ID...) + # response = Response(status_code=500) + + response = await call_next(request) + + access_logger = structlog.stdlib.get_logger("api.access") + process_time = time.perf_counter_ns() - start_time + status_code = response.status_code + url = get_path_with_query_string(request.scope) + client_host = request.client.host + client_port = request.client.port + real_host = request.headers.get("X-Forwarded-For", client_host) + http_method = request.method + http_version = request.scope["http_version"] + # Recreate the Uvicorn access log format, but add all parameters as structured information + + if 400 < status_code < 500: + access_logger.warn( + f"""{real_host}:{client_port} - "{http_method} {url} HTTP/{http_version}" {status_code}""", + http={ + "url": str(request.url), + "status_code": status_code, + "method": http_method, + "request_id": request_id, + "version": http_version, + }, + network={"client": {"ip": real_host, "port": client_port}}, + duration=process_time, + ) + else: + access_logger.info( + f"""{real_host}:{client_port} - "{http_method} {url} HTTP/{http_version}" {status_code}""", + http={ + "url": str(request.url), + "status_code": status_code, + "method": http_method, + "request_id": request_id, + "version": http_version, + }, + network={"client": {"ip": real_host, "port": client_port}}, + duration=process_time, + ) + # response.headers["X-Process-Time"] = str(process_time / 10 ** 9) + return response diff --git a/src/infrastructure/http/execeptions.py b/src/infrastructure/http/execeptions.py index 66a1c5b9df1..ef84f9bcd1d 100644 --- a/src/infrastructure/http/execeptions.py +++ b/src/infrastructure/http/execeptions.py @@ -13,6 +13,10 @@ def custom_base_errors_handler(_: Request, error: BaseError) -> JSONResponse: """This function is called if the BaseError was raised.""" + # TODO Some unit tests check for error messages. Might be bad? If the erroring endpoint doesn't log anything + # TODO then there is nothing in the log. Logging here ensures errors actually get logged. + # logger.error(error) + response = ErrorResponseMulti( result=[ ErrorResponse( @@ -23,6 +27,8 @@ def custom_base_errors_handler(_: Request, error: BaseError) -> JSONResponse: ] ) + + return JSONResponse( response.dict(by_alias=True), status_code=error.status_code, diff --git a/src/infrastructure/logger.py b/src/infrastructure/logger.py index fd8a4eef0f5..1d64bf60987 100644 --- a/src/infrastructure/logger.py +++ b/src/infrastructure/logger.py @@ -1,10 +1,24 @@ import logging +import os -fmt = "%(levelname)s: %(message)s" -logger = logging.getLogger() -logger.setLevel(logging.INFO) -formatter = logging.Formatter(fmt) -handler = logging.StreamHandler() -handler.setLevel(logging.INFO) -handler.setFormatter(formatter) -logger.addHandler(handler) +import structlog +from pydantic.tools import parse_obj_as + +from infrastructure.datadog import setup_structured_logging + +if os.environ.get("ENV") == "testing": + # Some tests check logging output, so use the old logger + fmt = "%(levelname)s: %(message)s" + logger = logging.getLogger() + logger.setLevel(logging.INFO) + formatter = logging.Formatter(fmt) + handler = logging.StreamHandler() + handler.setLevel(logging.INFO) + handler.setFormatter(formatter) + logger.addHandler(handler) +else: + # Default to structured logger, enable JSON format if env set + LOG_JSON_FORMAT = parse_obj_as(bool, os.getenv("LOG_JSON_FORMAT", False)) + LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO") + setup_structured_logging(json_logs=LOG_JSON_FORMAT, log_level=LOG_LEVEL) + logger = structlog.stdlib.get_logger("api") diff --git a/src/main.py b/src/main.py index d503ae91768..77b765dad02 100644 --- a/src/main.py +++ b/src/main.py @@ -1,8 +1,22 @@ +import os +import logging + +# Import DataDog tracer ASAP +if os.getenv("DD_TRACE_ENABLED", "false").lower() == "true": + logging.getLogger("main").setLevel(logging.INFO) + logging.getLogger("main").addHandler(logging.StreamHandler()) + logging.getLogger("main").info("Enabling Datadog") + # import ddtrace.auto # noqa + from ddtrace import patch + # Manually patch. The auto patcher throws some errors in AMQP (which it doesn't support so why patch it??) + patch(sqlalchemy=True, fastapi=True, botocore=True, asyncpg=True, httpx=True, jinja2=True, + requests=True, starlette=True, structlog=True) + + from infrastructure.app import create_app app = create_app() - # @app.on_event("startup") # async def create_superuser(): # print("Create/Update superuser") diff --git a/uvicorn_disable_logging.json b/uvicorn_disable_logging.json new file mode 100644 index 00000000000..106ce37b039 --- /dev/null +++ b/uvicorn_disable_logging.json @@ -0,0 +1,40 @@ +{ + "version": 1, + "disable_existing_loggers": false, + "formatters": { + "default": { + "()": "uvicorn.logging.DefaultFormatter", + "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s" + }, + "access": { + "()": "uvicorn.logging.AccessFormatter", + "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s" + } + }, + "handlers": { + "default": { + "formatter": "default", + "class": "logging.NullHandler" + }, + "access": { + "formatter": "access", + "class": "logging.NullHandler" + } + }, + "loggers": { + "uvicorn.error": { + "level": "INFO", + "handlers": [ + "default" + ], + "propagate": false + }, + "uvicorn.access": { + "level": "INFO", + "handlers": [ + "access" + ], + "propagate": false + } + } +} \ No newline at end of file From 762b608d0ea67bcde77d96b91b3ccf25a5137395 Mon Sep 17 00:00:00 2001 From: Andrew Weiland Date: Wed, 11 Dec 2024 09:08:13 -0500 Subject: [PATCH 05/10] fixed bad Pipfile --- Pipfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Pipfile b/Pipfile index 161b11d5e8a..688564ac7c4 100644 --- a/Pipfile +++ b/Pipfile @@ -53,7 +53,6 @@ taskiq-fastapi = "==0.3.2" taskiq-redis = "==1.0.2" typer = "==0.12.5" uvicorn = { extras = ["standard"], version = "==0.32.0" } -pyjwt = "==2.9.0" ddtrace = "==2.17.2" bytecode = "==0.16.0" structlog = "==24.4.0" From d9a585917b0e045b035341af24711e805d79248a Mon Sep 17 00:00:00 2001 From: Andrew Weiland Date: Wed, 11 Dec 2024 09:23:06 -0500 Subject: [PATCH 06/10] Fixed lock file --- Pipfile.lock | 330 ++++++++++++++++++++++++++------------------------- 1 file changed, 168 insertions(+), 162 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 918ec77a790..a23265985d1 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "1c3202a870592cdd50f1677fbec2bd33d63fc395b8b4b7d28abbedaf0dc33023" + "sha256": "980c099605c562ac8513820d821a24c5a3ae56b87ea0ad67f609c5b2ec7f39ea" }, "pipfile-spec": 6, "requires": { @@ -315,11 +315,11 @@ }, "botocore": { "hashes": [ - "sha256:8a6a0f5ad119e38d850571df8c625dbad66aec1b20c15f84cdcb95258f9f1edb", - "sha256:b2e3ecdd1769f011f72c4c0d0094570ba125f4ca327f24269e4d68eb5d9878b9" + "sha256:41c37bd7c0326f25122f33ec84fb80fc0a14d7fcc9961431b0e57568e88c9cb5", + "sha256:6905036c25449ae8dba5e950e4b908e4b8a6fe6b516bf61e007ecb62fa21f323" ], "markers": "python_version >= '3.8'", - "version": "==1.35.73" + "version": "==1.35.78" }, "bytecode": { "hashes": [ @@ -678,6 +678,14 @@ "markers": "python_version >= '3.7'", "version": "==0.6.1" }, + "exceptiongroup": { + "hashes": [ + "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", + "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" + ], + "markers": "python_version >= '3.7'", + "version": "==1.2.2" + }, "fastapi": { "hashes": [ "sha256:9ec46f7addc14ea472958a96aae5b5de65f39721a46aaf5705c480d9a8b76654", @@ -814,11 +822,11 @@ "grpc" ], "hashes": [ - "sha256:2ceb087315e6af43f256704b871d99326b1f12a9d6ce99beaedec99ba26a0ace", - "sha256:c20100d4c4c41070cf365f1d8ddf5365915291b5eb11b83829fbd1c999b5122f" + "sha256:10d82ac0fca69c82a25b3efdeefccf6f28e02ebb97925a8cce8edbfe379929d9", + "sha256:e255640547a597a4da010876d333208ddac417d60add22b6851a0c66a831fcaf" ], - "markers": "platform_python_implementation != 'PyPy'", - "version": "==2.23.0" + "markers": "python_version >= '3.7'", + "version": "==2.24.0" }, "google-api-python-client": { "hashes": [ @@ -2138,13 +2146,12 @@ }, "sentry-sdk": { "hashes": [ - - "sha256:7b0b3b709dee051337244a09a30dbf6e95afe0d34a1f8b430d45e0982a7c125b", - "sha256:ee4a4d2ae8bfe3cac012dcf3e4607975904c137e1738116549fc3dbbb6ff0e36" + "sha256:467df6e126ba242d39952375dd816fbee0f217d119bf454a8ce74cf1e7909e8d", + "sha256:ebdc08228b4d131128e568d696c210d846e5b9d70aa0327dec6b1272d9d40b84" ], "index": "pypi", "markers": "python_version >= '3.6'", - "version": "==2.19.0" + "version": "==2.19.2" }, "setuptools": { "hashes": [ @@ -2305,12 +2312,12 @@ }, "typer": { "hashes": [ - "sha256:7994fb7b8155b64d3402518560648446072864beefd44aa2dc36972a5972e847", - "sha256:a0588c0a7fa68a1978a069818657778f86abe6ff5ea6abf472f940a08bfe4f0a" + "sha256:62fe4e471711b147e3365034133904df3e235698399bc4de2b36c8579298d52b", + "sha256:f592f089bedcc8ec1b974125d64851029c3b1af145f04aca64d69410f0c9b722" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==0.15.1" + "version": "==0.12.5" }, "typing-extensions": { "hashes": [ @@ -2341,11 +2348,11 @@ "standard" ], "hashes": [ - "sha256:82ad92fd58da0d12af7482ecdb5f2470a04c9c9a53ced65b9bbb4a205377602e", - "sha256:ee9519c246a72b1c084cea8d3b44ed6026e78a4a309cbedae9c37e4cb9fbb175" + "sha256:60b8f3a5ac027dcd31448f411ced12b5ef452c646f76f02f8cc3f25d8d26fd82", + "sha256:f78b36b143c16f54ccdb8190d0a26b5f1901fe5a3c777e1ab29f26391af8551e" ], "markers": "python_version >= '3.8'", - "version": "==0.32.1" + "version": "==0.32.0" }, "uvloop": { "hashes": [ @@ -2426,79 +2433,80 @@ }, "watchfiles": { "hashes": [ - "sha256:06d828fe2adc4ac8a64b875ca908b892a3603d596d43e18f7948f3fef5fc671c", - "sha256:074c7618cd6c807dc4eaa0982b4a9d3f8051cd0b72793511848fd64630174b17", - "sha256:09551237645d6bff3972592f2aa5424df9290e7a2e15d63c5f47c48cde585935", - "sha256:0fc3bf0effa2d8075b70badfdd7fb839d7aa9cea650d17886982840d71fdeabf", - "sha256:12ab123135b2f42517f04e720526d41448667ae8249e651385afb5cda31fedc0", - "sha256:13a4f9ee0cd25682679eea5c14fc629e2eaa79aab74d963bc4e21f43b8ea1877", - "sha256:1d19df28f99d6a81730658fbeb3ade8565ff687f95acb59665f11502b441be5f", - "sha256:1e176b6b4119b3f369b2b4e003d53a226295ee862c0962e3afd5a1c15680b4e3", - "sha256:1ee5edc939f53466b329bbf2e58333a5461e6c7b50c980fa6117439e2c18b42d", - "sha256:1f73c2147a453315d672c1ad907abe6d40324e34a185b51e15624bc793f93cc6", - "sha256:1ff236d7a3f4b0a42f699a22fc374ba526bc55048a70cbb299661158e1bb5e1f", - "sha256:245fab124b9faf58430da547512d91734858df13f2ddd48ecfa5e493455ffccb", - "sha256:28babb38cf2da8e170b706c4b84aa7e4528a6fa4f3ee55d7a0866456a1662041", - "sha256:28fb64b5843d94e2c2483f7b024a1280662a44409bedee8f2f51439767e2d107", - "sha256:29cf884ad4285d23453c702ed03d689f9c0e865e3c85d20846d800d4787de00f", - "sha256:2a825ba4b32c214e3855b536eb1a1f7b006511d8e64b8215aac06eb680642d84", - "sha256:2ac778a460ea22d63c7e6fb0bc0f5b16780ff0b128f7f06e57aaec63bd339285", - "sha256:2c2696611182c85eb0e755b62b456f48debff484b7306b56f05478b843ca8ece", - "sha256:2d9c0518fabf4a3f373b0a94bb9e4ea7a1df18dec45e26a4d182aa8918dee855", - "sha256:2de52b499e1ab037f1a87cb8ebcb04a819bf087b1015a4cf6dcf8af3c2a2613e", - "sha256:37566c844c9ce3b5deb964fe1a23378e575e74b114618d211fbda8f59d7b5dab", - "sha256:3d94fd83ed54266d789f287472269c0def9120a2022674990bd24ad989ebd7a0", - "sha256:48051d1c504448b2fcda71c5e6e3610ae45de6a0b8f5a43b961f250be4bdf5a8", - "sha256:487d15927f1b0bd24e7df921913399bb1ab94424c386bea8b267754d698f8f0e", - "sha256:4a3b33c3aefe9067ebd87846806cd5fc0b017ab70d628aaff077ab9abf4d06b3", - "sha256:4ff9c7e84e8b644a8f985c42bcc81457240316f900fc72769aaedec9d088055a", - "sha256:533a7cbfe700e09780bb31c06189e39c65f06c7f447326fee707fd02f9a6e945", - "sha256:53ae447f06f8f29f5ab40140f19abdab822387a7c426a369eb42184b021e97eb", - "sha256:550109001920a993a4383b57229c717fa73627d2a4e8fcb7ed33c7f1cddb0c85", - "sha256:5bbd0311588c2de7f9ea5cf3922ccacfd0ec0c1922870a2be503cc7df1ca8be7", - "sha256:5dccfc70480087567720e4e36ec381bba1ed68d7e5f368fe40c93b3b1eba0105", - "sha256:5f75cd42e7e2254117cf37ff0e68c5b3f36c14543756b2da621408349bd9ca7c", - "sha256:648e2b6db53eca6ef31245805cd528a16f56fa4cc15aeec97795eaf713c11435", - "sha256:774ef36b16b7198669ce655d4f75b4c3d370e7f1cbdfb997fb10ee98717e2058", - "sha256:8a2127cd68950787ee36753e6d401c8ea368f73beaeb8e54df5516a06d1ecd82", - "sha256:90004553be36427c3d06ec75b804233f8f816374165d5225b93abd94ba6e7234", - "sha256:905f69aad276639eff3893759a07d44ea99560e67a1cf46ff389cd62f88872a2", - "sha256:9122b8fdadc5b341315d255ab51d04893f417df4e6c1743b0aac8bf34e96e025", - "sha256:9272fdbc0e9870dac3b505bce1466d386b4d8d6d2bacf405e603108d50446940", - "sha256:936f362e7ff28311b16f0b97ec51e8f2cc451763a3264640c6ed40fb252d1ee4", - "sha256:947ccba18a38b85c366dafeac8df2f6176342d5992ca240a9d62588b214d731f", - "sha256:95dc785bc284552d044e561b8f4fe26d01ab5ca40d35852a6572d542adfeb4bc", - "sha256:95de85c254f7fe8cbdf104731f7f87f7f73ae229493bebca3722583160e6b152", - "sha256:9b4fb98100267e6a5ebaff6aaa5d20aea20240584647470be39fe4823012ac96", - "sha256:9c01446626574561756067f00b37e6b09c8622b0fc1e9fdbc7cbcea328d4e514", - "sha256:9c9a8d8fd97defe935ef8dd53d562e68942ad65067cd1c54d6ed8a088b1d931d", - "sha256:9e1d9284cc84de7855fcf83472e51d32daf6f6cecd094160192628bc3fee1b78", - "sha256:a0abf173975eb9dd17bb14c191ee79999e650997cc644562f91df06060610e62", - "sha256:a2218e78e2c6c07b1634a550095ac2a429026b2d5cbcd49a594f893f2bb8c936", - "sha256:a5a7a06cfc65e34fd0a765a7623c5ba14707a0870703888e51d3d67107589817", - "sha256:b2bca898c1dc073912d3db7fa6926cc08be9575add9e84872de2c99c688bac4e", - "sha256:b46e15c34d4e401e976d6949ad3a74d244600d5c4b88c827a3fdf18691a46359", - "sha256:b551c465a59596f3d08170bd7e1c532c7260dd90ed8135778038e13c5d48aa81", - "sha256:b555a93c15bd2c71081922be746291d776d47521a00703163e5fbe6d2a402399", - "sha256:bc338ce9f8846543d428260fa0f9a716626963148edc937d71055d01d81e1525", - "sha256:bedf84835069f51c7b026b3ca04e2e747ea8ed0a77c72006172c72d28c9f69fc", - "sha256:c3d258d78341d5d54c0c804a5b7faa66cd30ba50b2756a7161db07ce15363b8d", - "sha256:c83a6d33a9eda0af6a7470240d1af487807adc269704fe76a4972dd982d16236", - "sha256:c9a13ac46b545a7d0d50f7641eefe47d1597e7d1783a5d89e09d080e6dff44b0", - "sha256:cf517701a4a872417f4e02a136e929537743461f9ec6cdb8184d9a04f4843545", - "sha256:d2b39aa8edd9e5f56f99a2a2740a251dc58515398e9ed5a4b3e5ff2827060755", - "sha256:d3572d4c34c4e9c33d25b3da47d9570d5122f8433b9ac6519dca49c2740d23cd", - "sha256:d562a6114ddafb09c33246c6ace7effa71ca4b6a2324a47f4b09b6445ea78941", - "sha256:e1ed613ee107269f66c2df631ec0fc8efddacface85314d392a4131abe299f00", - "sha256:e3750434c83b61abb3163b49c64b04180b85b4dabb29a294513faec57f2ffdb7", - "sha256:eba98901a2eab909dbd79681190b9049acc650f6111fde1845484a4450761e98", - "sha256:f159ac795785cde4899e0afa539f4c723fb5dd336ce5605bc909d34edd00b79b", - "sha256:f8c4f3a1210ed099a99e6a710df4ff2f8069411059ffe30fa5f9467ebed1256b", - "sha256:fa13d604fcb9417ae5f2e3de676e66aa97427d888e83662ad205bed35a313176", - "sha256:fbd0ab7a9943bbddb87cbc2bf2f09317e74c77dc55b1f5657f81d04666c25269", - "sha256:ffd98a299b0a74d1b704ef0ed959efb753e656a4e0425c14e46ae4c3cbdd2919" + "sha256:0179252846be03fa97d4d5f8233d1c620ef004855f0717712ae1c558f1974a16", + "sha256:06ce08549e49ba69ccc36fc5659a3d0ff4e3a07d542b895b8a9013fcab46c2dc", + "sha256:0b90651b4cf9e158d01faa0833b073e2e37719264bcee3eac49fc3c74e7d304b", + "sha256:0d1ec043f02ca04bf21b1b32cab155ce90c651aaf5540db8eb8ad7f7e645cba8", + "sha256:0fe4e740ea94978b2b2ab308cbf9270a246bcbb44401f77cc8740348cbaeac3d", + "sha256:127de3883bdb29dbd3b21f63126bb8fa6e773b74eaef46521025a9ce390e1073", + "sha256:1550be1a5cb3be08a3fb84636eaafa9b7119b70c71b0bed48726fd1d5aa9b868", + "sha256:160eff7d1267d7b025e983ca8460e8cc67b328284967cbe29c05f3c3163711a3", + "sha256:16db2d7e12f94818cbf16d4c8938e4d8aaecee23826344addfaaa671a1527b07", + "sha256:1c6cf7709ed3e55704cc06f6e835bf43c03bc8e3cb8ff946bf69a2e0a78d9d77", + "sha256:1da46bb1eefb5a37a8fb6fd52ad5d14822d67c498d99bda8754222396164ae42", + "sha256:1df924ba82ae9e77340101c28d56cbaff2c991bd6fe8444a545d24075abb0a87", + "sha256:1e263cc718545b7f897baeac1f00299ab6fabe3e18caaacacb0edf6d5f35513c", + "sha256:228e2247de583475d4cebf6b9af5dc9918abb99d1ef5ee737155bb39fb33f3c0", + "sha256:275c1b0e942d335fccb6014d79267d1b9fa45b5ac0639c297f1e856f2f532552", + "sha256:29b9cb35b7f290db1c31fb2fdf8fc6d3730cfa4bca4b49761083307f441cac5a", + "sha256:2b4691234d31686dca133c920f94e478b548a8e7c750f28dbbc2e4333e0d3da9", + "sha256:2b961b86cd3973f5822826017cad7f5a75795168cb645c3a6b30c349094e02e3", + "sha256:2dcc3f60c445f8ce14156854a072ceb36b83807ed803d37fdea2a50e898635d6", + "sha256:2f492d2907263d6d0d52f897a68647195bc093dafed14508a8d6817973586b6b", + "sha256:310505ad305e30cb6c5f55945858cdbe0eb297fc57378f29bacceb534ac34199", + "sha256:34e87c7b3464d02af87f1059fedda5484e43b153ef519e4085fe1a03dd94801e", + "sha256:418c5ce332f74939ff60691e5293e27c206c8164ce2b8ce0d9abf013003fb7fe", + "sha256:46e86ed457c3486080a72bc837300dd200e18d08183f12b6ca63475ab64ed651", + "sha256:48681c86f2cb08348631fed788a116c89c787fdf1e6381c5febafd782f6c3b44", + "sha256:489b80812f52a8d8c7b0d10f0d956db0efed25df2821c7a934f6143f76938bd6", + "sha256:48c9f3bc90c556a854f4cab6a79c16974099ccfa3e3e150673d82d47a4bc92c9", + "sha256:49bc1bc26abf4f32e132652f4b3bfeec77d8f8f62f57652703ef127e85a3e38d", + "sha256:52bb50a4c4ca2a689fdba84ba8ecc6a4e6210f03b6af93181bb61c4ec3abaf86", + "sha256:5691340f259b8f76b45fb31b98e594d46c36d1dc8285efa7975f7f50230c9093", + "sha256:62691f1c0894b001c7cde1195c03b7801aaa794a837bd6eef24da87d1542838d", + "sha256:632a52dcaee44792d0965c17bdfe5dc0edad5b86d6a29e53d6ad4bf92dc0ff49", + "sha256:65ab1fb635476f6170b07e8e21db0424de94877e4b76b7feabfe11f9a5fc12b5", + "sha256:6a5bc3ca468bb58a2ef50441f953e1f77b9a61bd1b8c347c8223403dc9b4ac9a", + "sha256:6a76494d2c5311584f22416c5a87c1e2cb954ff9b5f0988027bc4ef2a8a67181", + "sha256:6f8dc09ae69af50bead60783180f656ad96bd33ffbf6e7a6fce900f6d53b08f1", + "sha256:703aa5e50e465be901e0e0f9d5739add15e696d8c26c53bc6fc00eb65d7b9469", + "sha256:713f67132346bdcb4c12df185c30cf04bdf4bf6ea3acbc3ace0912cab6b7cb8c", + "sha256:75d3bcfa90454dba8df12adc86b13b6d85fda97d90e708efc036c2760cc6ba44", + "sha256:7ca05cacf2e5c4a97d02a2878a24020daca21dbb8823b023b978210a75c79098", + "sha256:80bf4b459d94a0387617a1b499f314aa04d8a64b7a0747d15d425b8c8b151da0", + "sha256:84fac88278f42d61c519a6c75fb5296fd56710b05bbdcc74bdf85db409a03780", + "sha256:889a37e2acf43c377b5124166bece139b4c731b61492ab22e64d371cce0e6e80", + "sha256:8af4b582d5fc1b8465d1d2483e5e7b880cc1a4e99f6ff65c23d64d070867ac58", + "sha256:90b0fe1fcea9bd6e3084b44875e179b4adcc4057a3b81402658d0eb58c98edf8", + "sha256:93436ed550e429da007fbafb723e0769f25bae178fbb287a94cb4ccdf42d3af3", + "sha256:995c374e86fa82126c03c5b4630c4e312327ecfe27761accb25b5e1d7ab50ec8", + "sha256:9af037d3df7188ae21dc1c7624501f2f90d81be6550904e07869d8d0e6766655", + "sha256:9e080cf917b35b20c889225a13f290f2716748362f6071b859b60b8847a6aa43", + "sha256:a2ec98e31e1844eac860e70d9247db9d75440fc8f5f679c37d01914568d18721", + "sha256:abd85de513eb83f5ec153a802348e7a5baa4588b818043848247e3e8986094e8", + "sha256:ac1be85fe43b4bf9a251978ce5c3bb30e1ada9784290441f5423a28633a958a7", + "sha256:be37f9b1f8934cd9e7eccfcb5612af9fb728fecbe16248b082b709a9d1b348bf", + "sha256:bfcae6aecd9e0cb425f5145afee871465b98b75862e038d42fe91fd753ddd780", + "sha256:c05b021f7b5aa333124f2a64d56e4cb9963b6efdf44e8d819152237bbd93ba15", + "sha256:c14a07bdb475eb696f85c715dbd0f037918ccbb5248290448488a0b4ef201aad", + "sha256:c18f3502ad0737813c7dad70e3e1cc966cc147fbaeef47a09463bbffe70b0a00", + "sha256:c2e9fe695ff151b42ab06501820f40d01310fbd58ba24da8923ace79cf6d702d", + "sha256:c68be72b1666d93b266714f2d4092d78dc53bd11cf91ed5a3c16527587a52e29", + "sha256:ca94c85911601b097d53caeeec30201736ad69a93f30d15672b967558df02885", + "sha256:cf745cbfad6389c0e331786e5fe9ae3f06e9d9c2ce2432378e1267954793975c", + "sha256:d9dd2b89a16cf7ab9c1170b5863e68de6bf83db51544875b25a5f05a7269e678", + "sha256:ddff3f8b9fa24a60527c137c852d0d9a7da2a02cf2151650029fdc97c852c974", + "sha256:e153a690b7255c5ced17895394b4f109d5dcc2a4f35cb809374da50f0e5c456a", + "sha256:ea2b51c5f38bad812da2ec0cd7eec09d25f521a8b6b6843cbccedd9a1d8a5c15", + "sha256:ef9ec8068cf23458dbf36a08e0c16f0a2df04b42a8827619646637be1769300a", + "sha256:f280b02827adc9d87f764972fbeb701cf5611f80b619c20568e1982a277d6146", + "sha256:f3ff7da165c99a5412fe5dd2304dd2dbaaaa5da718aad942dcb3a178eaa70c56", + "sha256:f58d3bfafecf3d81c15d99fc0ecf4319e80ac712c77cf0ce2661c8cf8bf84066", + "sha256:f79fe7993e230a12172ce7d7c7db061f046f672f2b946431c81aff8f60b2758b", + "sha256:ffe709b1d0bc2e9921257569675674cafb3a5f8af689ab9f3f2b3f88775b960f" ], - "version": "==1.0.0" + "markers": "python_version >= '3.9'", + "version": "==1.0.3" }, "websockets": { "hashes": [ @@ -2572,6 +2580,7 @@ "sha256:f6cf0ad281c979306a6a34242b371e90e891bce504509fb6bb5246bbbf31e7b6", "sha256:f95ba34d71e2fa0c5d225bde3b3bdb152e957150100e75c86bc7f3964c450d89" ], + "markers": "python_version >= '3.9'", "version": "==14.1" }, "wrapt": { @@ -2652,7 +2661,6 @@ ], "markers": "python_version >= '3.6'", "version": "==0.14.2" - }, "yarl": { "hashes": [ @@ -2948,72 +2956,71 @@ "toml" ], "hashes": [ - "sha256:093896e530c38c8e9c996901858ac63f3d4171268db2c9c8b373a228f459bbc5", - "sha256:09b9f848b28081e7b975a3626e9081574a7b9196cde26604540582da60235fdf", - "sha256:0b0c69f4f724c64dfbfe79f5dfb503b42fe6127b8d479b2677f2b227478db2eb", - "sha256:13618bed0c38acc418896005732e565b317aa9e98d855a0e9f211a7ffc2d6638", - "sha256:13690e923a3932e4fad4c0ebfb9cb5988e03d9dcb4c5150b5fcbf58fd8bddfc4", - "sha256:177f01eeaa3aee4a5ffb0d1439c5952b53d5010f86e9d2667963e632e30082cc", - "sha256:193e3bffca48ad74b8c764fb4492dd875038a2f9925530cb094db92bb5e47bed", - "sha256:1defe91d41ce1bd44b40fabf071e6a01a5aa14de4a31b986aa9dfd1b3e3e414a", - "sha256:1f188a2402f8359cf0c4b1fe89eea40dc13b52e7b4fd4812450da9fcd210181d", - "sha256:202a2d645c5a46b84992f55b0a3affe4f0ba6b4c611abec32ee88358db4bb649", - "sha256:24eda3a24a38157eee639ca9afe45eefa8d2420d49468819ac5f88b10de84f4c", - "sha256:2e4e0f60cb4bd7396108823548e82fdab72d4d8a65e58e2c19bbbc2f1e2bfa4b", - "sha256:379c111d3558272a2cae3d8e57e6b6e6f4fe652905692d54bad5ea0ca37c5ad4", - "sha256:37cda8712145917105e07aab96388ae76e787270ec04bcb9d5cc786d7cbb8443", - "sha256:38c51297b35b3ed91670e1e4efb702b790002e3245a28c76e627478aa3c10d83", - "sha256:3985b9be361d8fb6b2d1adc9924d01dec575a1d7453a14cccd73225cb79243ee", - "sha256:3988665ee376abce49613701336544041f2117de7b7fbfe91b93d8ff8b151c8e", - "sha256:3ac47fa29d8d41059ea3df65bd3ade92f97ee4910ed638e87075b8e8ce69599e", - "sha256:3b4b4299dd0d2c67caaaf286d58aef5e75b125b95615dda4542561a5a566a1e3", - "sha256:3ea8bb1ab9558374c0ab591783808511d135a833c3ca64a18ec927f20c4030f0", - "sha256:3fe47da3e4fda5f1abb5709c156eca207eacf8007304ce3019eb001e7a7204cb", - "sha256:428ac484592f780e8cd7b6b14eb568f7c85460c92e2a37cb0c0e5186e1a0d076", - "sha256:44e6c85bbdc809383b509d732b06419fb4544dca29ebe18480379633623baafb", - "sha256:4674f0daa1823c295845b6a740d98a840d7a1c11df00d1fd62614545c1583787", - "sha256:4be32da0c3827ac9132bb488d331cb32e8d9638dd41a0557c5569d57cf22c9c1", - "sha256:4db3ed6a907b555e57cc2e6f14dc3a4c2458cdad8919e40b5357ab9b6db6c43e", - "sha256:5c52a036535d12590c32c49209e79cabaad9f9ad8aa4cbd875b68c4d67a9cbce", - "sha256:629a1ba2115dce8bf75a5cce9f2486ae483cb89c0145795603d6554bdc83e801", - "sha256:62a66ff235e4c2e37ed3b6104d8b478d767ff73838d1222132a7a026aa548764", - "sha256:63068a11171e4276f6ece913bde059e77c713b48c3a848814a6537f35afb8365", - "sha256:63c19702db10ad79151a059d2d6336fe0c470f2e18d0d4d1a57f7f9713875dcf", - "sha256:644ec81edec0f4ad17d51c838a7d01e42811054543b76d4ba2c5d6af741ce2a6", - "sha256:6535d996f6537ecb298b4e287a855f37deaf64ff007162ec0afb9ab8ba3b8b71", - "sha256:6f4548c5ead23ad13fb7a2c8ea541357474ec13c2b736feb02e19a3085fac002", - "sha256:716a78a342679cd1177bc8c2fe957e0ab91405bd43a17094324845200b2fddf4", - "sha256:74610105ebd6f33d7c10f8907afed696e79c59e3043c5f20eaa3a46fddf33b4c", - "sha256:768939f7c4353c0fac2f7c37897e10b1414b571fd85dd9fc49e6a87e37a2e0d8", - "sha256:86cffe9c6dfcfe22e28027069725c7f57f4b868a3f86e81d1c62462764dc46d4", - "sha256:8aae5aea53cbfe024919715eca696b1a3201886ce83790537d1c3668459c7146", - "sha256:8b2b8503edb06822c86d82fa64a4a5cb0760bb8f31f26e138ec743f422f37cfc", - "sha256:912e95017ff51dc3d7b6e2be158dedc889d9a5cc3382445589ce554f1a34c0ea", - "sha256:9a7b8ac36fd688c8361cbc7bf1cb5866977ece6e0b17c34aa0df58bda4fa18a4", - "sha256:9e89d5c8509fbd6c03d0dd1972925b22f50db0792ce06324ba069f10787429ad", - "sha256:ae270e79f7e169ccfe23284ff5ea2d52a6f401dc01b337efb54b3783e2ce3f28", - "sha256:b07c25d52b1c16ce5de088046cd2432b30f9ad5e224ff17c8f496d9cb7d1d451", - "sha256:b39e6011cd06822eb964d038d5dff5da5d98652b81f5ecd439277b32361a3a50", - "sha256:bd55f8fc8fa494958772a2a7302b0354ab16e0b9272b3c3d83cdb5bec5bd1779", - "sha256:c15b32a7aca8038ed7644f854bf17b663bc38e1671b5d6f43f9a2b2bd0c46f63", - "sha256:c1b4474beee02ede1eef86c25ad4600a424fe36cff01a6103cb4533c6bf0169e", - "sha256:c79c0685f142ca53256722a384540832420dff4ab15fec1863d7e5bc8691bdcc", - "sha256:c9ebfb2507751f7196995142f057d1324afdab56db1d9743aab7f50289abd022", - "sha256:d7ad66e8e50225ebf4236368cc43c37f59d5e6728f15f6e258c8639fa0dd8e6d", - "sha256:d82ab6816c3277dc962cfcdc85b1efa0e5f50fb2c449432deaf2398a2928ab94", - "sha256:d9fd2547e6decdbf985d579cf3fc78e4c1d662b9b0ff7cc7862baaab71c9cc5b", - "sha256:de38add67a0af869b0d79c525d3e4588ac1ffa92f39116dbe0ed9753f26eba7d", - "sha256:e19122296822deafce89a0c5e8685704c067ae65d45e79718c92df7b3ec3d331", - "sha256:e44961e36cb13c495806d4cac67640ac2866cb99044e210895b506c26ee63d3a", - "sha256:e4c81ed2820b9023a9a90717020315e63b17b18c274a332e3b6437d7ff70abe0", - "sha256:e683e6ecc587643f8cde8f5da6768e9d165cd31edf39ee90ed7034f9ca0eefee", - "sha256:f39e2f3530ed1626c66e7493be7a8423b023ca852aacdc91fb30162c350d2a92", - "sha256:f56f49b2553d7dd85fd86e029515a221e5c1f8cb3d9c38b470bc38bde7b8445a", - "sha256:fb9fc32399dca861584d96eccd6c980b69bbcd7c228d06fb74fe53e007aa8ef9" + "sha256:0824a28ec542a0be22f60c6ac36d679e0e262e5353203bea81d44ee81fe9c6d4", + "sha256:085161be5f3b30fd9b3e7b9a8c301f935c8313dcf928a07b116324abea2c1c2c", + "sha256:0ae1387db4aecb1f485fb70a6c0148c6cdaebb6038f1d40089b1fc84a5db556f", + "sha256:0d59fd927b1f04de57a2ba0137166d31c1a6dd9e764ad4af552912d70428c92b", + "sha256:0f957943bc718b87144ecaee70762bc2bc3f1a7a53c7b861103546d3a403f0a6", + "sha256:13a9e2d3ee855db3dd6ea1ba5203316a1b1fd8eaeffc37c5b54987e61e4194ae", + "sha256:1a330812d9cc7ac2182586f6d41b4d0fadf9be9049f350e0efb275c8ee8eb692", + "sha256:22be16571504c9ccea919fcedb459d5ab20d41172056206eb2994e2ff06118a4", + "sha256:2d10e07aa2b91835d6abec555ec8b2733347956991901eea6ffac295f83a30e4", + "sha256:35371f8438028fdccfaf3570b31d98e8d9eda8bb1d6ab9473f5a390969e98717", + "sha256:3c026eb44f744acaa2bda7493dad903aa5bf5fc4f2554293a798d5606710055d", + "sha256:41ff7b0da5af71a51b53f501a3bac65fb0ec311ebed1632e58fc6107f03b9198", + "sha256:4401ae5fc52ad8d26d2a5d8a7428b0f0c72431683f8e63e42e70606374c311a1", + "sha256:44349150f6811b44b25574839b39ae35291f6496eb795b7366fef3bd3cf112d3", + "sha256:447af20e25fdbe16f26e84eb714ba21d98868705cb138252d28bc400381f6ffb", + "sha256:4a8d8977b0c6ef5aeadcb644da9e69ae0dcfe66ec7f368c89c72e058bd71164d", + "sha256:4e12ae8cc979cf83d258acb5e1f1cf2f3f83524d1564a49d20b8bec14b637f08", + "sha256:592ac539812e9b46046620341498caf09ca21023c41c893e1eb9dbda00a70cbf", + "sha256:5e6b86b5847a016d0fbd31ffe1001b63355ed309651851295315031ea7eb5a9b", + "sha256:608a7fd78c67bee8936378299a6cb9f5149bb80238c7a566fc3e6717a4e68710", + "sha256:61f70dc68bd36810972e55bbbe83674ea073dd1dcc121040a08cdf3416c5349c", + "sha256:65dad5a248823a4996724a88eb51d4b31587aa7aa428562dbe459c684e5787ae", + "sha256:777abfab476cf83b5177b84d7486497e034eb9eaea0d746ce0c1268c71652077", + "sha256:7e216d8044a356fc0337c7a2a0536d6de07888d7bcda76febcb8adc50bdbbd00", + "sha256:85d9636f72e8991a1706b2b55b06c27545448baf9f6dbf51c4004609aacd7dcb", + "sha256:899b8cd4781c400454f2f64f7776a5d87bbd7b3e7f7bda0cb18f857bb1334664", + "sha256:8a289d23d4c46f1a82d5db4abeb40b9b5be91731ee19a379d15790e53031c014", + "sha256:8d2dfa71665a29b153a9681edb1c8d9c1ea50dfc2375fb4dac99ea7e21a0bcd9", + "sha256:8e3c3e38930cfb729cb8137d7f055e5a473ddaf1217966aa6238c88bd9fd50e6", + "sha256:8f8770dfc6e2c6a2d4569f411015c8d751c980d17a14b0530da2d7f27ffdd88e", + "sha256:932fc826442132dde42ee52cf66d941f581c685a6313feebed358411238f60f9", + "sha256:96d636c77af18b5cb664ddf12dab9b15a0cfe9c0bde715da38698c8cea748bfa", + "sha256:97ddc94d46088304772d21b060041c97fc16bdda13c6c7f9d8fcd8d5ae0d8611", + "sha256:98caba4476a6c8d59ec1eb00c7dd862ba9beca34085642d46ed503cc2d440d4b", + "sha256:9901d36492009a0a9b94b20e52ebfc8453bf49bb2b27bca2c9706f8b4f5a554a", + "sha256:99e266ae0b5d15f1ca8d278a668df6f51cc4b854513daab5cae695ed7b721cf8", + "sha256:9c38bf15a40ccf5619fa2fe8f26106c7e8e080d7760aeccb3722664c8656b030", + "sha256:a27801adef24cc30871da98a105f77995e13a25a505a0161911f6aafbd66e678", + "sha256:abd3e72dd5b97e3af4246cdada7738ef0e608168de952b837b8dd7e90341f015", + "sha256:adb697c0bd35100dc690de83154627fbab1f4f3c0386df266dded865fc50a902", + "sha256:b12c6b18269ca471eedd41c1b6a1065b2f7827508edb9a7ed5555e9a56dcfc97", + "sha256:b9389a429e0e5142e69d5bf4a435dd688c14478a19bb901735cdf75e57b13845", + "sha256:ba9e7484d286cd5a43744e5f47b0b3fb457865baf07bafc6bee91896364e1419", + "sha256:bb5555cff66c4d3d6213a296b360f9e1a8e323e74e0426b6c10ed7f4d021e464", + "sha256:be57b6d56e49c2739cdf776839a92330e933dd5e5d929966fbbd380c77f060be", + "sha256:c69e42c892c018cd3c8d90da61d845f50a8243062b19d228189b0224150018a9", + "sha256:ccc660a77e1c2bf24ddbce969af9447a9474790160cfb23de6be4fa88e3951c7", + "sha256:d5275455b3e4627c8e7154feaf7ee0743c2e7af82f6e3b561967b1cca755a0be", + "sha256:d75cded8a3cff93da9edc31446872d2997e327921d8eed86641efafd350e1df1", + "sha256:d872ec5aeb086cbea771c573600d47944eea2dcba8be5f3ee649bfe3cb8dc9ba", + "sha256:d891c136b5b310d0e702e186d70cd16d1119ea8927347045124cb286b29297e5", + "sha256:db1dab894cc139f67822a92910466531de5ea6034ddfd2b11c0d4c6257168073", + "sha256:e28bf44afa2b187cc9f41749138a64435bf340adfcacb5b2290c070ce99839d4", + "sha256:e5ea1cf0872ee455c03e5674b5bca5e3e68e159379c1af0903e89f5eba9ccc3a", + "sha256:e77363e8425325384f9d49272c54045bbed2f478e9dd698dbc65dbc37860eb0a", + "sha256:ee5defd1733fd6ec08b168bd4f5387d5b322f45ca9e0e6c817ea6c4cd36313e3", + "sha256:f1592791f8204ae9166de22ba7e6705fa4ebd02936c09436a1bb85aabca3e599", + "sha256:f2d1ec60d6d256bdf298cb86b78dd715980828f50c46701abc3b0a2b3f8a0dc0", + "sha256:f3ca78518bc6bc92828cd11867b121891d75cae4ea9e908d72030609b996db1b", + "sha256:f7b15f589593110ae767ce997775d645b47e5cbbf54fd322f8ebea6277466cec", + "sha256:fd1213c86e48dfdc5a0cc676551db467495a95a662d2396ecd58e719191446e1", + "sha256:ff74026a461eb0660366fb01c650c1d00f833a086b336bdad7ab00cc952072b3" ], "markers": "python_version >= '3.9'", - "version": "==7.6.8" - + "version": "==7.6.9" }, "decorator": { "hashes": [ @@ -3238,6 +3245,7 @@ "sha256:1f519121bc366af3e485310dc8041d2e86e5173c1a320fac3dc9d2604069b83e", "sha256:ace9b420ce52995bb4f05e7425eedf19e433c981dfe7a831ab391e2fa2e1a195" ], + "markers": "python_version >= '3.8'", "version": "==1.2.1" }, "identify": { @@ -3286,9 +3294,7 @@ "sha256:85ec56a7e20f6c38fce7727dcca699ae4ffc85985aa7b23635a8008f918ae321", "sha256:cb0a405a306d2995a5cbb9901894d240784a9f341394c6ba3f4fe8c6eb89ff6e" ], - - "markers": "python_version >= '3.11'", - + "markers": "python_version >= '3.10'", "version": "==8.30.0" }, "jedi": { @@ -3577,7 +3583,7 @@ "sha256:77ca0ad1c435b6e363d7e8623d7cc4fcf2cf15513bf77a1c1b2e814930ac57cc", "sha256:f04b3e1ba35747ac86e96ec33e3bb9748ce08e254dc2a1c6253945901beec804" ], - "markers": "python_version >= '3.8' and python_version < '3.12'", + "markers": "python_version >= '3.9'", "version": "==3.12.0" }, "prompt-toolkit": { @@ -3936,12 +3942,12 @@ }, "types-python-dateutil": { "hashes": [ - "sha256:250e1d8e80e7bbc3a6c99b907762711d1a1cdd00e978ad39cb5940f6f0a87f3d", - "sha256:58cb85449b2a56d6684e41aeefb4c4280631246a0da1a719bdbe6f3fb0317446" + "sha256:18f493414c26ffba692a72369fea7a154c502646301ebfe3d56a04b3767284cb", + "sha256:e248a4bc70a486d3e3ec84d0dc30eec3a5f979d6e7ee4123ae043eedbb987f53" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==2.9.0.20241003" + "version": "==2.9.0.20241206" }, "types-pytz": { "hashes": [ From b91030bdafe067a14df16a16e1d811cf44af286d Mon Sep 17 00:00:00 2001 From: Andrew Weiland Date: Wed, 11 Dec 2024 09:57:03 -0500 Subject: [PATCH 07/10] Datadog startup fix --- compose/fastapi/start-datadog | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compose/fastapi/start-datadog b/compose/fastapi/start-datadog index 77f82aad692..f3673040111 100644 --- a/compose/fastapi/start-datadog +++ b/compose/fastapi/start-datadog @@ -9,7 +9,8 @@ export UVICORN_HOST="0.0.0.0" export UVICORN_PORT=80 -LOG_JSON_FORMAT=true DD_TRACE_ENABLED=true uvicorn main:app \ +export DD_AGENT_HOST=$(curl http://169.254.169.254/latest/meta-data/local-ipv4); \ + LOG_JSON_FORMAT=true DD_TRACE_ENABLED=true uvicorn main:app \ --host ${UVICORN_HOST} --port ${UVICORN_PORT} \ --reload --proxy-headers \ --log-config uvicorn_disable_logging.json From 8d3e7fd84abce45cb299e287e25343b5cbf6d7f8 Mon Sep 17 00:00:00 2001 From: Andrew Weiland Date: Wed, 11 Dec 2024 10:08:08 -0500 Subject: [PATCH 08/10] Fixed metadata endpoint --- compose/fastapi/start-datadog | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/compose/fastapi/start-datadog b/compose/fastapi/start-datadog index f3673040111..9123960cf59 100644 --- a/compose/fastapi/start-datadog +++ b/compose/fastapi/start-datadog @@ -8,9 +8,12 @@ set -o nounset export UVICORN_HOST="0.0.0.0" export UVICORN_PORT=80 +TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600") +export DD_AGENT_HOST=$(curl http://169.254.169.254/latest/meta-data/local-ipv4 -H "X-aws-ec2-metadata-token: $TOKEN") +export LOG_JSON_FORMAT=true +export DD_TRACE_ENABLED=true -export DD_AGENT_HOST=$(curl http://169.254.169.254/latest/meta-data/local-ipv4); \ - LOG_JSON_FORMAT=true DD_TRACE_ENABLED=true uvicorn main:app \ +uvicorn main:app \ --host ${UVICORN_HOST} --port ${UVICORN_PORT} \ --reload --proxy-headers \ --log-config uvicorn_disable_logging.json From f172f7cc7ebd4e5ba34e921b3441bee9889a781e Mon Sep 17 00:00:00 2001 From: Carlos Chacon Date: Thu, 12 Dec 2024 15:55:57 -0600 Subject: [PATCH 09/10] Reapply "feat: Report answer export updates (M2-7255) (#1670)" (#1685) This reverts commit 2cd996767c10f0c81e9ef10be33f1ad25f97243c. --- src/apps/answers/crud/answers.py | 1 + src/apps/answers/domain/answers.py | 13 +++-- src/apps/answers/service.py | 47 +++++++++++++------ src/apps/answers/tests/test_answers.py | 11 +++-- .../answers/tests/test_answers_arbitrary.py | 8 ++-- src/apps/workspaces/crud/applet_access.py | 2 + .../workspaces/domain/user_applet_access.py | 2 + 7 files changed, 60 insertions(+), 24 deletions(-) diff --git a/src/apps/answers/crud/answers.py b/src/apps/answers/crud/answers.py index 2d35ca8bb6b..38f439e3a10 100644 --- a/src/apps/answers/crud/answers.py +++ b/src/apps/answers/crud/answers.py @@ -325,6 +325,7 @@ async def get_applet_answers( AnswerItemSchema.respondent_id, self._exclude_assessment_val(AnswerSchema.target_subject_id).label("target_subject_id"), self._exclude_assessment_val(AnswerSchema.source_subject_id).label("source_subject_id"), + self._exclude_assessment_val(AnswerSchema.input_subject_id).label("input_subject_id"), self._exclude_assessment_val(AnswerSchema.relation).label("relation"), AnswerItemSchema.answer, AnswerItemSchema.events, diff --git a/src/apps/answers/domain/answers.py b/src/apps/answers/domain/answers.py index 9d5f3af7ddd..2072a991f71 100644 --- a/src/apps/answers/domain/answers.py +++ b/src/apps/answers/domain/answers.py @@ -526,12 +526,19 @@ class UserAnswerDataBase(BaseModel): submit_id: uuid.UUID version: str respondent_id: uuid.UUID | str | None = None - target_subject_id: uuid.UUID | str | None = None - target_secret_id: uuid.UUID | str | None = None + respondent_secret_id: str | None = None source_subject_id: uuid.UUID | str | None = None source_secret_id: uuid.UUID | str | None = None + source_user_nickname: str | None = None + source_user_tag: str | None = None + target_subject_id: uuid.UUID | str | None = None + target_secret_id: uuid.UUID | str | None = None + target_user_nickname: str | None = None + target_user_tag: str | None = None + input_subject_id: uuid.UUID | str | None = None + input_secret_id: uuid.UUID | str | None = None + input_user_nickname: str | None = None relation: str | None = None - respondent_secret_id: str | None = None legacy_profile_id: str | None = None user_public_key: str | None answer: str | None = None diff --git a/src/apps/answers/service.py b/src/apps/answers/service.py index 0eff0dabd49..6c6bb2adf2a 100644 --- a/src/apps/answers/service.py +++ b/src/apps/answers/service.py @@ -1215,15 +1215,16 @@ async def get_export_data( # noqa: C901 applet_assessment_ids = set() activity_hist_ids = set() flow_hist_ids = set() + + # collect ids to resolve data for answer in answers: - # collect id to resolve data - if answer.reviewed_answer_id: - # collect reviewer ids to fetch the data - respondent_ids.add(answer.respondent_id) # type: ignore[arg-type] # noqa: E501 - if answer.target_subject_id: - subject_ids.add(answer.target_subject_id) # type: ignore[arg-type] # noqa: E501 + respondent_ids.add(answer.respondent_id) # type: ignore[arg-type] # noqa: E501 if answer.source_subject_id: subject_ids.add(answer.source_subject_id) # type: ignore[arg-type] # noqa: E501 + if answer.target_subject_id: + subject_ids.add(answer.target_subject_id) # type: ignore[arg-type] # noqa: E501 + if answer.input_subject_id: + subject_ids.add(answer.input_subject_id) # type: ignore[arg-type] # noqa: E501 if answer.reviewed_answer_id: applet_assessment_ids.add(answer.applet_history_id) if answer.flow_history_id: @@ -1234,35 +1235,53 @@ async def get_export_data( # noqa: C901 flows_coro = FlowsHistoryCRUD(self.session).get_by_id_versions(list(flow_hist_ids)) user_map_coro = AppletAccessCRUD(self.session).get_respondent_export_data(applet_id, list(respondent_ids)) subject_map_coro = AppletAccessCRUD(self.session).get_subject_export_data(applet_id, list(subject_ids)) + current_user_subject_coro = SubjectsCrud(self.session).get_user_subject(self.user_id, applet_id) # type: ignore[arg-type] coros_result = await asyncio.gather( flows_coro, user_map_coro, subject_map_coro, + current_user_subject_coro, return_exceptions=True, ) for res in coros_result: if isinstance(res, BaseException): raise res - flows, user_map, subject_map = coros_result + flows, user_map, subject_map, current_user = coros_result flow_map = {flow.id_version: flow for flow in flows} # type: ignore for answer in answers: - # respondent data - if answer.reviewed_answer_id: - # assessment - respondent = user_map[answer.respondent_id] # type: ignore - else: - respondent = subject_map[answer.target_subject_id] # type: ignore + respondent = user_map[answer.respondent_id] # type: ignore + answer.respondent_secret_id = current_user.secret_user_id # type: ignore - answer.respondent_secret_id = respondent.secret_id answer.source_secret_id = ( subject_map.get(answer.source_subject_id).secret_id if answer.source_subject_id else None # type: ignore ) + answer.source_user_nickname = ( + subject_map.get(answer.source_subject_id).nickname if answer.source_subject_id else None # type: ignore + ) + answer.source_user_tag = ( + subject_map.get(answer.source_subject_id).tag if answer.source_subject_id else None # type: ignore + ) + answer.target_secret_id = ( subject_map.get(answer.target_subject_id).secret_id if answer.target_subject_id else None # type: ignore ) + answer.target_user_nickname = ( + subject_map.get(answer.target_subject_id).nickname if answer.target_subject_id else None # type: ignore + ) + answer.target_user_tag = ( + subject_map.get(answer.target_subject_id).tag if answer.target_subject_id else None # type: ignore + ) + + answer.input_secret_id = ( + subject_map.get(answer.input_subject_id).secret_id if answer.input_subject_id else None # type: ignore + ) + answer.input_user_nickname = ( + subject_map.get(answer.input_subject_id).nickname if answer.input_subject_id else None # type: ignore + ) + answer.respondent_email = respondent.email answer.is_manager = respondent.is_manager answer.legacy_profile_id = respondent.legacy_profile_id diff --git a/src/apps/answers/tests/test_answers.py b/src/apps/answers/tests/test_answers.py index 2958929f790..58ce8b0c571 100644 --- a/src/apps/answers/tests/test_answers.py +++ b/src/apps/answers/tests/test_answers.py @@ -1840,9 +1840,11 @@ async def test_answers_export( "flowName", "id", "itemIds", "migratedData", "respondentId", "respondentSecretId", "reviewedAnswerId", "userPublicKey", "version", "submitId", "scheduledDatetime", "startDatetime", - "endDatetime", "legacyProfileId", "migratedDate", - "relation", "sourceSubjectId", "sourceSecretId", "targetSubjectId", - "targetSecretId", "client", "tzOffset", "scheduledEventId", "reviewedFlowSubmitId" + "endDatetime", "legacyProfileId", "migratedDate", "relation", + "sourceSubjectId", "sourceSecretId", "sourceUserNickname", "sourceUserTag", + "targetSubjectId", "targetSecretId", "targetUserNickname", "targetUserTag", + "inputSubjectId", "inputSecretId", "inputUserNickname", + "client", "tzOffset", "scheduledEventId", "reviewedFlowSubmitId" } # Comment for now, wtf is it # assert int(answer['startDatetime'] * 1000) == answer_item_create.start_time @@ -1874,7 +1876,8 @@ async def test_get_applet_answers_without_assessment( assert len(data["answers"]) == 1 assert resp_data["count"] == 1 assert data["answers"][0]["respondentId"] == str(tom.id) - assert data["answers"][0]["respondentSecretId"] == answer_shell_account_target["target_secret_user_id"] + respondent_secret_id = data["answers"][0]["respondentSecretId"].split(" ")[-1].strip("()") + assert respondent_secret_id == answer_shell_account_target["respondent_secret_user_id"] @pytest.mark.parametrize( "user_fixture, exp_cnt", diff --git a/src/apps/answers/tests/test_answers_arbitrary.py b/src/apps/answers/tests/test_answers_arbitrary.py index e305266cb93..623aa6b4e7e 100644 --- a/src/apps/answers/tests/test_answers_arbitrary.py +++ b/src/apps/answers/tests/test_answers_arbitrary.py @@ -619,9 +619,11 @@ async def test_answers_export( "flowName", "id", "itemIds", "migratedData", "respondentId", "respondentSecretId", "reviewedAnswerId", "userPublicKey", "version", "submitId", "scheduledDatetime", "startDatetime", - "endDatetime", "legacyProfileId", "migratedDate", - "relation", "sourceSubjectId", "sourceSecretId", "targetSubjectId", - "targetSecretId", "client", "tzOffset", "scheduledEventId", "reviewedFlowSubmitId" + "endDatetime", "legacyProfileId", "migratedDate", "relation", + "sourceSubjectId", "sourceSecretId", "sourceUserNickname", "sourceUserTag", + "targetSubjectId", "targetSecretId", "targetUserNickname", "targetUserTag", + "inputSubjectId", "inputSecretId", "inputUserNickname", + "client", "tzOffset", "scheduledEventId", "reviewedFlowSubmitId" } assert set(assessment.keys()) == expected_keys diff --git a/src/apps/workspaces/crud/applet_access.py b/src/apps/workspaces/crud/applet_access.py index 5f88ad1e3fb..7521b18969b 100644 --- a/src/apps/workspaces/crud/applet_access.py +++ b/src/apps/workspaces/crud/applet_access.py @@ -278,6 +278,8 @@ async def get_subject_export_data( SubjectSchema.id, SubjectSchema.user_id, SubjectSchema.email, + SubjectSchema.nickname, + SubjectSchema.tag, SubjectSchema.secret_user_id.label("secret_id"), UserAppletAccessSchema.legacy_profile_id, has_manager_role.label("is_manager"), diff --git a/src/apps/workspaces/domain/user_applet_access.py b/src/apps/workspaces/domain/user_applet_access.py index 7d2d8b6efaa..702b03be499 100644 --- a/src/apps/workspaces/domain/user_applet_access.py +++ b/src/apps/workspaces/domain/user_applet_access.py @@ -137,6 +137,8 @@ class RespondentExportData(InternalModel): class SubjectExportData(RespondentExportData): user_id: uuid.UUID | None + nickname: str | None + tag: str | None class RespondentInfoPublic(PublicModel): From f0d6c07a4fb69812aac074eafc8da99a7285c4ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Vital?= Date: Thu, 19 Dec 2024 10:49:07 +0900 Subject: [PATCH 10/10] fix: Point secret user id to logged in user (input user) (M2-7255) (#1691) --- src/apps/answers/service.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/apps/answers/service.py b/src/apps/answers/service.py index 6c6bb2adf2a..13883493721 100644 --- a/src/apps/answers/service.py +++ b/src/apps/answers/service.py @@ -1235,25 +1235,25 @@ async def get_export_data( # noqa: C901 flows_coro = FlowsHistoryCRUD(self.session).get_by_id_versions(list(flow_hist_ids)) user_map_coro = AppletAccessCRUD(self.session).get_respondent_export_data(applet_id, list(respondent_ids)) subject_map_coro = AppletAccessCRUD(self.session).get_subject_export_data(applet_id, list(subject_ids)) - current_user_subject_coro = SubjectsCrud(self.session).get_user_subject(self.user_id, applet_id) # type: ignore[arg-type] coros_result = await asyncio.gather( flows_coro, user_map_coro, subject_map_coro, - current_user_subject_coro, return_exceptions=True, ) for res in coros_result: if isinstance(res, BaseException): raise res - flows, user_map, subject_map, current_user = coros_result + flows, user_map, subject_map = coros_result flow_map = {flow.id_version: flow for flow in flows} # type: ignore for answer in answers: respondent = user_map[answer.respondent_id] # type: ignore - answer.respondent_secret_id = current_user.secret_user_id # type: ignore + answer.respondent_secret_id = ( + subject_map.get(answer.input_subject_id).secret_id if answer.input_subject_id else None # type: ignore + ) answer.source_secret_id = ( subject_map.get(answer.source_subject_id).secret_id if answer.source_subject_id else None # type: ignore