From a4da23e8a194088a43cd4530677a672c1999df8b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 14:35:57 -0500 Subject: [PATCH 01/13] build(deps): bump protobuf from 4.24.4 to 4.25.0 (#952) Bumps [protobuf](https://github.com/protocolbuffers/protobuf) from 4.24.4 to 4.25.0. - [Release notes](https://github.com/protocolbuffers/protobuf/releases) - [Changelog](https://github.com/protocolbuffers/protobuf/blob/main/protobuf_release.bzl) - [Commits](https://github.com/protocolbuffers/protobuf/compare/v4.24.4...v4.25.0) --- updated-dependencies: - dependency-name: protobuf dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/requirements.txt b/requirements.txt index 191815f58..27ad167fb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -558,20 +558,18 @@ prettyconf==2.2.1 \ promise==2.3 \ --hash=sha256:dfd18337c523ba4b6a58801c164c1904a9d4d1b1747c7d5dbf45b693a49d93d0 # via graphene-django -protobuf==4.24.4 \ - --hash=sha256:02212557a76cd99574775a81fefeba8738d0f668d6abd0c6b1d3adcc75503dbe \ - --hash=sha256:1badab72aa8a3a2b812eacfede5020472e16c6b2212d737cefd685884c191085 \ - --hash=sha256:2fa3886dfaae6b4c5ed2730d3bf47c7a38a72b3a1f0acb4d4caf68e6874b947b \ - --hash=sha256:5a70731910cd9104762161719c3d883c960151eea077134458503723b60e3667 \ - --hash=sha256:6b7d2e1c753715dcfe9d284a25a52d67818dd43c4932574307daf836f0071e37 \ - --hash=sha256:80797ce7424f8c8d2f2547e2d42bfbb6c08230ce5832d6c099a37335c9c90a92 \ - --hash=sha256:8e61a27f362369c2f33248a0ff6896c20dcd47b5d48239cb9720134bef6082e4 \ - --hash=sha256:9fee5e8aa20ef1b84123bb9232b3f4a5114d9897ed89b4b8142d81924e05d79b \ - --hash=sha256:b493cb590960ff863743b9ff1452c413c2ee12b782f48beca77c8da3e2ffe9d9 \ - --hash=sha256:b77272f3e28bb416e2071186cb39efd4abbf696d682cbb5dc731308ad37fa6dd \ - --hash=sha256:bffa46ad9612e6779d0e51ae586fde768339b791a50610d85eb162daeb23661e \ - --hash=sha256:dbbed8a56e56cee8d9d522ce844a1379a72a70f453bde6243e3c86c30c2a3d46 \ - --hash=sha256:ec9912d5cb6714a5710e28e592ee1093d68c5ebfeda61983b3f40331da0b1ebb +protobuf==4.25.0 \ + --hash=sha256:1a3ba712877e6d37013cdc3476040ea1e313a6c2e1580836a94f76b3c176d575 \ + --hash=sha256:1a53d6f64b00eecf53b65ff4a8c23dc95df1fa1e97bb06b8122e5a64f49fc90a \ + --hash=sha256:32ac2100b0e23412413d948c03060184d34a7c50b3e5d7524ee96ac2b10acf51 \ + --hash=sha256:5c1203ac9f50e4853b0a0bfffd32c67118ef552a33942982eeab543f5c634395 \ + --hash=sha256:63714e79b761a37048c9701a37438aa29945cd2417a97076048232c1df07b701 \ + --hash=sha256:683dc44c61f2620b32ce4927de2108f3ebe8ccf2fd716e1e684e5a50da154054 \ + --hash=sha256:68f7caf0d4f012fd194a301420cf6aa258366144d814f358c5b32558228afa7c \ + --hash=sha256:b2cf8b5d381f9378afe84618288b239e75665fe58d0f3fd5db400959274296e9 \ + --hash=sha256:c40ff8f00aa737938c5378d461637d15c442a12275a81019cc2fef06d81c9419 \ + --hash=sha256:cf21faba64cd2c9a3ed92b7a67f226296b10159dbb8fbc5e854fc90657d908e4 \ + --hash=sha256:d94a33db8b7ddbd0af7c467475fb9fde0c705fb315a8433c0e2020942b863a1f # via # ddsketch # ddtrace From 54ad918875be60ff96fc952208a8efaa2e09b588 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 15:49:11 -0500 Subject: [PATCH 02/13] build(deps): bump ddtrace from 2.1.4 to 2.1.5 (#951) Bumps [ddtrace](https://github.com/DataDog/dd-trace-py) from 2.1.4 to 2.1.5. - [Release notes](https://github.com/DataDog/dd-trace-py/releases) - [Changelog](https://github.com/DataDog/dd-trace-py/blob/2.x/CHANGELOG.md) - [Commits](https://github.com/DataDog/dd-trace-py/compare/v2.1.4...v2.1.5) --- updated-dependencies: - dependency-name: ddtrace dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 122 +++++++++++++++++++++++------------------------ 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/requirements.txt b/requirements.txt index 27ad167fb..786edb393 100644 --- a/requirements.txt +++ b/requirements.txt @@ -246,67 +246,67 @@ ddsketch==2.0.4 \ --hash=sha256:3227a270fd686a29d3a7128f9352ccf852314410380fc11384356f1ae2a75938 \ --hash=sha256:32f7314077fec8747d4faebaec2c854b5ffc399c5f552f73fa94024f48d74d64 # via ddtrace -ddtrace==2.1.4 \ - --hash=sha256:02e14ae706a70236ed08ef1fd9a93ef3664bcc5a1d09f19e4db40de443c61d6e \ - --hash=sha256:048ef63d4cc4da65a82382c6ec24dde316746c2b0e500148232f91d8bf0222d3 \ - --hash=sha256:049befcc02514feef8480675ad0c4433962de2f191debd038c12a6d2a9a53e5e \ - --hash=sha256:05849fd41aa983a9901c0a8ea00d8e96fb9eac1e390c651101c54542a939e2f7 \ - --hash=sha256:0743d7fdf566916eeffb050428dfd0d4a787892e5a691a4fe871fef943226db4 \ - --hash=sha256:0bfb5519ed5f594c098185eee01015692c10c7b7fe4bb54af8bed21055ae2587 \ - --hash=sha256:271fde3363c1096e1951206902e2e8cd9632689c70114dd3695dae009583ac42 \ - --hash=sha256:2f2762c3072c25674674b6484ba6516a8d9faabace6cea9afaf3f1e306bd1691 \ - --hash=sha256:324587da64dd5a0eae9eb18f5a80a8a6d979527c23e020ee3885916cee763e55 \ - --hash=sha256:345efbb9ca299d80725039cbf0b47e4beb9a1b32ea01eac1d070602f48ce7d5b \ - --hash=sha256:34b1c6cdd48b309942e485a6cf6ce27c13ff7d8a584a84cf357c08696d5aa554 \ - --hash=sha256:37a29ebb12e16d1db3bf1b48c2449c490947df6cd147eed67ac77886c5945b09 \ - --hash=sha256:3998014378d8aba6910711bb5af545ac4947334b020430ec255d0b74debe5fed \ - --hash=sha256:3d40e11d8bcf30e4ed870cd1ce95383f6aa34ddea45a73317b787e1ae3c6caf7 \ - --hash=sha256:431dbc6678e2a03bd67429d6ce050dff87e06697132b45d652e6d1bd2b8479bd \ - --hash=sha256:48dd6028f8f23bb48bf4afac3d9a465ea44db2abdcb1d4b7636b328e7903e8d8 \ - --hash=sha256:4d36b26c979fac69d6418e91cea8e47f06df549ac77608b904e81dc3ec9d68f6 \ - --hash=sha256:52ff7626bb896ec25b3594aaca91487fecd3b3ca4150c764f7c44caf87972e33 \ - --hash=sha256:53b0120efc1ca96af7d65d28f0f2598fbd31953d04778ee1a3c54e4de59c94b0 \ - --hash=sha256:5589927879a9654116d9a7a48244912df858c1854794161d017c2b573e7101ce \ - --hash=sha256:571e77462729ad83747d26217d6791aa7fdcb57e7cc72127b512fc7f2b75f46a \ - --hash=sha256:57505c711bf70f7f2a86ec7af2d4d1d099201b7782ab1c7f6d9d4d30454fd478 \ - --hash=sha256:5a5eeb61ecbec1ca87e6859a10921bde6d2dfe54a5f7e75fc64df1163cc1ee65 \ - --hash=sha256:5dec4e896261ab7e9cb1971ed1dc3bd4def96c1d2c3c73e2a4b9ebfa6f75c0d3 \ - --hash=sha256:5e8e7255a16669b3250d717d7711e20fbf8c257f3eb2c2aa304c7b5db18a2956 \ - --hash=sha256:675acd5297548ce65bd44fd642dcbe9014d9cb69f3d57b020b38392cdd74bb7b \ - --hash=sha256:707dc8e3372b406438fee95204676a5e7beec640a3fad2cacebceee1a5f95e3e \ - --hash=sha256:77dffac5459e44eb1accdb3f518520128dec2ba335dad6deb800331dee9a5e7f \ - --hash=sha256:7815876b4d12112a77edf9fc5c5492626ccbf75f0aed005d747c1343a0d82860 \ - --hash=sha256:7bcac3e2f16e7a24eebe48d31b9dc995476c20747ec6f8b76cd0412580ab1914 \ - --hash=sha256:7d0e50d11d60a58e8e53e08fadb4acde7d07da5f5b68221b97f9265be22e8a38 \ - --hash=sha256:7e1bcc6acd0fa444ff73c06c6572008e89fccbfa5d7a09daf45137f2455d2280 \ - --hash=sha256:80da7f78f695e7b158ef0ad6de4d12a14ba1817c8862fa433c4df77814c593aa \ - --hash=sha256:81cea6d1182a17ab9b60120c66a5515aaa78e780abc09d1ace40dc76656167e7 \ - --hash=sha256:888f877d8705d331ec8022bc77cebdbfdddf0322840bc365290c0b27963f20d7 \ - --hash=sha256:8b9b18f4ecc95dbb05f701d9225c8b4a6fc03768589f8182444ef073bfdf1a8c \ - --hash=sha256:8f6f7b9cf96da548104e6e4f12566e5cba6a60158d33c47e6532efca91a5b113 \ - --hash=sha256:921d3acf2bca44a5fddbca5ca72ad5e5885b14b3e1bca5629b8fc76107139005 \ - --hash=sha256:924160e52356ec61cf6f5ad1348c39d9e687365f77a01b23ef64e2e556dbb7e1 \ - --hash=sha256:936d70b61bc773519e01a6c84fcfc2ae90e60e0f962a3678e1b201d0c1e7297f \ - --hash=sha256:a39fa5cb483de64a3336d506956d4ce57f7653adb9823f9797bc1eb96e2d77c2 \ - --hash=sha256:ab24da58c4b3f004e49a5f417b6c68f4dc2523deccf7f13ae7e31f64fc5b5ed6 \ - --hash=sha256:ac35ca3bb4c3d916a6bee628ddbf674499a6dff16632f8a1909d2534e262a87c \ - --hash=sha256:af3bc75fa519d4e669ae8e38ceeb9aea41b9ebe6459d02c2af67259790ea291d \ - --hash=sha256:b7f897d7ce74a0df5886c3700ab5f56a0c78d7fccb055ed6602600d59d072843 \ - --hash=sha256:bba269fb62a6fa21b5e81deec79f3c4cd2ba151d1661896c63840c39dff10677 \ - --hash=sha256:bd684f99177bb96b6ac3ace58ed638818a278532ccad8b149767b00ee26dba62 \ - --hash=sha256:bfa60950a43a771199fe0592558e5c8cdc205fca199402996f0a8f5588c9b54c \ - --hash=sha256:bfc22383d8ed80936cb6160928fbe77d39e235cd7fc7d80a15866e158f8a863a \ - --hash=sha256:bffdaa8f2162bff5f8c0f1e67a5776de31255f5637b21cc43b70f594a3f35fde \ - --hash=sha256:c69178d4b4740a118ad712eeec90196650138207635713d770925789f5cbd03d \ - --hash=sha256:cebd556e0416ffda97ae616078c6716509124b3f608880897620fdaf0ace063c \ - --hash=sha256:d6a0de562708ea6173cf4de13a46ec65a4b32322844672880ead395303c4217a \ - --hash=sha256:dddf1f89295510b7417ae885be98d763bb0fda5eae0dbb4674196abd7b04f270 \ - --hash=sha256:e125a6c520f7e0bb9c0ce06dc4b37e12b81c756608520daeda30aeb5dd31e2ce \ - --hash=sha256:e754fd49b7a5a1ec9d5a963821411bffed928d21653ecdf078fdb06cbee0dd3d \ - --hash=sha256:e8c5917568a6fba0126e2dba8eda0dd417788a25e5b2427b7741db8b5afeeab5 \ - --hash=sha256:f53148d936d674e5f1ff7b9c72cbdc7bd344948e774c4d03ad78f3a58c4f27b4 \ - --hash=sha256:f851fbc092827d203e0c46897e1925024ea2d21bcb6e706de90e18873941865c \ - --hash=sha256:ffabf31b700b48a63506ff988dcdaf156e19582749a403e33044c4fdd09a5993 +ddtrace==2.1.5 \ + --hash=sha256:03d89ad3f549562a43527b4078f08fe88e6ac09931664c82a443dde476dc12bb \ + --hash=sha256:0a1e3b87798c575102536f2ef9c9f29d269eecfee550b71de2c6401af8c6fa5c \ + --hash=sha256:11032ec18f716bbefb54794cd86acb688c9868db113a8e99bedee1270cfadfeb \ + --hash=sha256:15d2d6a9e93bff2b7e158aeae374ba0e96b8b8dcde3358280f8565af135566ef \ + --hash=sha256:1799e7092f0d6b3da5711d16650286d5636837df9332945b9aa3763801ede459 \ + --hash=sha256:23d3aa2b4ea4c98724cf04bc891ac5098bcb2f2c7a6d5faf51ad5db851cd95de \ + --hash=sha256:27b8c7d593d6299d2b3dadc97375823ca3ed6e8a3facf25db64f6ded4166cdcc \ + --hash=sha256:280706d4c94f5fd5c4ab3d6266af4f378ccaba5aa3edc6fd3ae633b408fba538 \ + --hash=sha256:37285fe66fa5df6f9b496d7c13bcd1cda44ff98ecdda37b8daeeded5799ca583 \ + --hash=sha256:3abad52d6827fd1011489ac08d9a630d95423067fe5b1c59b7f063532acc6f1f \ + --hash=sha256:3c4f184dee11ceb4549b018ceedd48c987cf38e868e0f2738f577d58f731cb8e \ + --hash=sha256:3d222bb16f5f59d7eec1b483930d471ff5b742a6d470fde4be9e49382e358e7b \ + --hash=sha256:3e72a758fab4922db1d1c0e81763350d1c58f8fddc201bbd50b3a53ab2775559 \ + --hash=sha256:3f2a6919c58363f4223d321ba742a8de861551ca8374a10ca4356f9ee48e8abf \ + --hash=sha256:450b714923a37aaf8895ccd667f389c1858e0aa6251da88e32e542f0e9eb43bc \ + --hash=sha256:4b79457d2453cab5ed92d33f4dbc5bcb6f1547970ff42a98df564a18b63b341e \ + --hash=sha256:66868d3f82d9a4c558aeefc765ecef6997186ed50c064ced502367999da804ef \ + --hash=sha256:66df78679765c249089f188ef538fc5e6ec9041ec807fce9de6eb522817283db \ + --hash=sha256:673da78d0486c73ba7ffedb4a18c6355fa5833d8a21c7d34be148011cd50ba0e \ + --hash=sha256:675f8496de767504a9898f7c4a829b11f20bdc06f3a73048e53491230eb3f98b \ + --hash=sha256:6766082753899827d82248d299d5c8c92374fd7402152eddc57115a356252966 \ + --hash=sha256:6b84f254b7bcfe3ceb332969283f4f8c8b1445143eafcc411ca6cb270a954897 \ + --hash=sha256:6c9624f379f0866ad4967bfc3075f91bd8d2763d5875c1775ab4e2444224e7c3 \ + --hash=sha256:700fdc39e991ffd110f6eda37a7ff05e28853d6426d72e8acdeca8656fb11e3a \ + --hash=sha256:794388b37d2f11f653c0c1510b5d1902560acb010fc1ec9201795adc8e8ef834 \ + --hash=sha256:801bc761d26446691b39c626400dc5259ea35ef4a3a6f274d238e3453d3e9d01 \ + --hash=sha256:807e8a7c48a23bc1963cebcbd3c8a71f1fc551cfcde65a3ce88e896d90951ccd \ + --hash=sha256:81f3bac029633357fb7dd942a9f34dc324961e54ce6dd4d13bff56a50971d7da \ + --hash=sha256:84688c50b2f6df28a8c31a2ed05144b4f9153372a6b8aef9329ab611aa6b19d8 \ + --hash=sha256:8685116c099da004faa06c67e8375a45240995031abdb39df77a0f1d6a6321e6 \ + --hash=sha256:87b3babd2918951fcc463fe366615124da942d8e399f27ed05cccd991355376e \ + --hash=sha256:8a0d33c4bd194274625200549c76674e6fed54d0836b24ead8fa4e7bc30bb3a6 \ + --hash=sha256:8d2fd2631a17b7f1c750cafd20952f059d47fa55be7b58e43cd863c9bae4ddfb \ + --hash=sha256:93e22be88b8bdb9f2aa8915b3806797f1a1203a323e1bf86db14eefff1b6281e \ + --hash=sha256:94b6ab3889d8e537b02fb72f71f08bb19110275c8b2a92c1b1c219fed90babf1 \ + --hash=sha256:98ecf4c2d899a0fe54bc71777f7e8c4ba2bc553664626a4b142c07c0e3d0265f \ + --hash=sha256:a650ad7d3e5c8e051be18e6dafd4fd12aee8bbe48893d64adc9c147fc9b6eb0a \ + --hash=sha256:a6851187cb4893df3b7abdfc8af197a53dfc043f5bc30a0c3c99a414e452d337 \ + --hash=sha256:a89b504f0d9c036fd927f005651e242ea0695a12d6c795921aefea35f1ca1388 \ + --hash=sha256:b317d40fb380eb2f8e228f309a56c3dc5fdef796c247f5585602ac5bedca2635 \ + --hash=sha256:b489c475034cfa33a9221609fd0582fe398d766c193d630a476fa114a6e086e9 \ + --hash=sha256:b5dc5c7798fed05ee1018307fd822552d5a1a4e526c76d72855cc5beff81a816 \ + --hash=sha256:b7dbdb8f7c5fa00a7fb8b4caef9d87070a5271fd8e34959772b7b6565ee216e2 \ + --hash=sha256:b91728c63827cdb53e1b1158233678cd2224bd7840ea2bbf89a3b7d4eddaa288 \ + --hash=sha256:bb5729e40cfafdb75fa24f7eea4bd57a0f25cfa7c640601d3815a0d4e85cd485 \ + --hash=sha256:bcb3bf61df12586816955ffb5614c7410ffd97867fe368a91b926ebcc5054c7e \ + --hash=sha256:c2bd90233b5234ebc77889ae37104d86a0cbac04e56458f8ad3c3f5338d37ef7 \ + --hash=sha256:c7570c289eeaa3a7d397f73f6988f4efa9dd69699e6ca4b9830c68c9aac30a52 \ + --hash=sha256:d4e2c6c03fe833f3207f26ea72a86852864933069138dbc0591dc1a6354cdf2b \ + --hash=sha256:d5fafd3f699590031a4470f9e3e346ec86b35b445dedd0d80f2d9af3701cf16f \ + --hash=sha256:e4eda64a156ce9f626874ed535cf2e79c78b63b4e982fc2daf4d92b0b9d033f5 \ + --hash=sha256:e72c387dc779611bafa29495cfd1244e6967df90ae273420a3752a9152ff9369 \ + --hash=sha256:e8766f16e5e342b9c861b2083dda25b108584de000e010f550eacc679ed7e581 \ + --hash=sha256:ebfa05b3595250fbe8304bcf35baa60fa413f8d828b63f6cf92d5ae64cd2a9e7 \ + --hash=sha256:eca2fa2e1ff123761a34fecad78f345fa4d0cbd9024890132ad68749deed3737 \ + --hash=sha256:f55cc4f99e1fb53e3040640ec4dbee4601a9d3656fd210260a2d775d7cbc4753 \ + --hash=sha256:f86e4e9df32b3adb5e8f17b873795589301b1ea04b38a90fe18981aa0c2ffc82 \ + --hash=sha256:fbe0f510c088b41a87d09816b83f15d70c086bc62aba70dc9c166844bbc6622a \ + --hash=sha256:fd5a1c17e7e12f68a219db99c89f88dde59b2dfac623adea5bd1ed164bae8228 \ + --hash=sha256:fdbff8b41eaf84b5f409ff602ba59feae609b238ebbcafd3ce72dfe9665c3326 # via -r requirements/deploy.in deprecated==1.2.14 \ --hash=sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c \ From 3c8bf5a600e22e3980da1e4c96dffe82e0745150 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 15:49:28 -0500 Subject: [PATCH 03/13] build(deps): bump charset-normalizer from 3.3.1 to 3.3.2 (#955) Bumps [charset-normalizer](https://github.com/Ousret/charset_normalizer) from 3.3.1 to 3.3.2. - [Release notes](https://github.com/Ousret/charset_normalizer/releases) - [Changelog](https://github.com/Ousret/charset_normalizer/blob/master/CHANGELOG.md) - [Commits](https://github.com/Ousret/charset_normalizer/compare/3.3.1...3.3.2) --- updated-dependencies: - dependency-name: charset-normalizer dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements-dev.txt | 182 +++++++++++++++++++++---------------------- requirements.txt | 182 +++++++++++++++++++++---------------------- 2 files changed, 182 insertions(+), 182 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 66345fec8..f2cf93769 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -108,97 +108,97 @@ cffi==1.16.0 \ --hash=sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956 \ --hash=sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357 # via cryptography -charset-normalizer==3.3.1 \ - --hash=sha256:06cf46bdff72f58645434d467bf5228080801298fbba19fe268a01b4534467f5 \ - --hash=sha256:0c8c61fb505c7dad1d251c284e712d4e0372cef3b067f7ddf82a7fa82e1e9a93 \ - --hash=sha256:10b8dd31e10f32410751b3430996f9807fc4d1587ca69772e2aa940a82ab571a \ - --hash=sha256:1171ef1fc5ab4693c5d151ae0fdad7f7349920eabbaca6271f95969fa0756c2d \ - --hash=sha256:17a866d61259c7de1bdadef418a37755050ddb4b922df8b356503234fff7932c \ - --hash=sha256:1d6bfc32a68bc0933819cfdfe45f9abc3cae3877e1d90aac7259d57e6e0f85b1 \ - --hash=sha256:1ec937546cad86d0dce5396748bf392bb7b62a9eeb8c66efac60e947697f0e58 \ - --hash=sha256:223b4d54561c01048f657fa6ce41461d5ad8ff128b9678cfe8b2ecd951e3f8a2 \ - --hash=sha256:2465aa50c9299d615d757c1c888bc6fef384b7c4aec81c05a0172b4400f98557 \ - --hash=sha256:28f512b9a33235545fbbdac6a330a510b63be278a50071a336afc1b78781b147 \ - --hash=sha256:2c092be3885a1b7899cd85ce24acedc1034199d6fca1483fa2c3a35c86e43041 \ - --hash=sha256:2c4c99f98fc3a1835af8179dcc9013f93594d0670e2fa80c83aa36346ee763d2 \ - --hash=sha256:31445f38053476a0c4e6d12b047b08ced81e2c7c712e5a1ad97bc913256f91b2 \ - --hash=sha256:31bbaba7218904d2eabecf4feec0d07469284e952a27400f23b6628439439fa7 \ - --hash=sha256:34d95638ff3613849f473afc33f65c401a89f3b9528d0d213c7037c398a51296 \ - --hash=sha256:352a88c3df0d1fa886562384b86f9a9e27563d4704ee0e9d56ec6fcd270ea690 \ - --hash=sha256:39b70a6f88eebe239fa775190796d55a33cfb6d36b9ffdd37843f7c4c1b5dc67 \ - --hash=sha256:3c66df3f41abee950d6638adc7eac4730a306b022570f71dd0bd6ba53503ab57 \ - --hash=sha256:3f70fd716855cd3b855316b226a1ac8bdb3caf4f7ea96edcccc6f484217c9597 \ - --hash=sha256:3f9bc2ce123637a60ebe819f9fccc614da1bcc05798bbbaf2dd4ec91f3e08846 \ - --hash=sha256:3fb765362688821404ad6cf86772fc54993ec11577cd5a92ac44b4c2ba52155b \ - --hash=sha256:45f053a0ece92c734d874861ffe6e3cc92150e32136dd59ab1fb070575189c97 \ - --hash=sha256:46fb9970aa5eeca547d7aa0de5d4b124a288b42eaefac677bde805013c95725c \ - --hash=sha256:4cb50a0335382aac15c31b61d8531bc9bb657cfd848b1d7158009472189f3d62 \ - --hash=sha256:4e12f8ee80aa35e746230a2af83e81bd6b52daa92a8afaef4fea4a2ce9b9f4fa \ - --hash=sha256:4f3100d86dcd03c03f7e9c3fdb23d92e32abbca07e7c13ebd7ddfbcb06f5991f \ - --hash=sha256:4f6e2a839f83a6a76854d12dbebde50e4b1afa63e27761549d006fa53e9aa80e \ - --hash=sha256:4f861d94c2a450b974b86093c6c027888627b8082f1299dfd5a4bae8e2292821 \ - --hash=sha256:501adc5eb6cd5f40a6f77fbd90e5ab915c8fd6e8c614af2db5561e16c600d6f3 \ - --hash=sha256:520b7a142d2524f999447b3a0cf95115df81c4f33003c51a6ab637cbda9d0bf4 \ - --hash=sha256:548eefad783ed787b38cb6f9a574bd8664468cc76d1538215d510a3cd41406cb \ - --hash=sha256:555fe186da0068d3354cdf4bbcbc609b0ecae4d04c921cc13e209eece7720727 \ - --hash=sha256:55602981b2dbf8184c098bc10287e8c245e351cd4fdcad050bd7199d5a8bf514 \ - --hash=sha256:58e875eb7016fd014c0eea46c6fa92b87b62c0cb31b9feae25cbbe62c919f54d \ - --hash=sha256:5a3580a4fdc4ac05f9e53c57f965e3594b2f99796231380adb2baaab96e22761 \ - --hash=sha256:5b70bab78accbc672f50e878a5b73ca692f45f5b5e25c8066d748c09405e6a55 \ - --hash=sha256:5ceca5876032362ae73b83347be8b5dbd2d1faf3358deb38c9c88776779b2e2f \ - --hash=sha256:61f1e3fb621f5420523abb71f5771a204b33c21d31e7d9d86881b2cffe92c47c \ - --hash=sha256:633968254f8d421e70f91c6ebe71ed0ab140220469cf87a9857e21c16687c034 \ - --hash=sha256:63a6f59e2d01310f754c270e4a257426fe5a591dc487f1983b3bbe793cf6bac6 \ - --hash=sha256:63accd11149c0f9a99e3bc095bbdb5a464862d77a7e309ad5938fbc8721235ae \ - --hash=sha256:6db3cfb9b4fcecb4390db154e75b49578c87a3b9979b40cdf90d7e4b945656e1 \ - --hash=sha256:71ef3b9be10070360f289aea4838c784f8b851be3ba58cf796262b57775c2f14 \ - --hash=sha256:7ae8e5142dcc7a49168f4055255dbcced01dc1714a90a21f87448dc8d90617d1 \ - --hash=sha256:7b6cefa579e1237ce198619b76eaa148b71894fb0d6bcf9024460f9bf30fd228 \ - --hash=sha256:800561453acdecedaac137bf09cd719c7a440b6800ec182f077bb8e7025fb708 \ - --hash=sha256:82ca51ff0fc5b641a2d4e1cc8c5ff108699b7a56d7f3ad6f6da9dbb6f0145b48 \ - --hash=sha256:851cf693fb3aaef71031237cd68699dded198657ec1e76a76eb8be58c03a5d1f \ - --hash=sha256:854cc74367180beb327ab9d00f964f6d91da06450b0855cbbb09187bcdb02de5 \ - --hash=sha256:87071618d3d8ec8b186d53cb6e66955ef2a0e4fa63ccd3709c0c90ac5a43520f \ - --hash=sha256:871d045d6ccc181fd863a3cd66ee8e395523ebfbc57f85f91f035f50cee8e3d4 \ - --hash=sha256:8aee051c89e13565c6bd366813c386939f8e928af93c29fda4af86d25b73d8f8 \ - --hash=sha256:8af5a8917b8af42295e86b64903156b4f110a30dca5f3b5aedea123fbd638bff \ - --hash=sha256:8ec8ef42c6cd5856a7613dcd1eaf21e5573b2185263d87d27c8edcae33b62a61 \ - --hash=sha256:91e43805ccafa0a91831f9cd5443aa34528c0c3f2cc48c4cb3d9a7721053874b \ - --hash=sha256:9505dc359edb6a330efcd2be825fdb73ee3e628d9010597aa1aee5aa63442e97 \ - --hash=sha256:985c7965f62f6f32bf432e2681173db41336a9c2611693247069288bcb0c7f8b \ - --hash=sha256:9a74041ba0bfa9bc9b9bb2cd3238a6ab3b7618e759b41bd15b5f6ad958d17605 \ - --hash=sha256:9edbe6a5bf8b56a4a84533ba2b2f489d0046e755c29616ef8830f9e7d9cf5728 \ - --hash=sha256:a15c1fe6d26e83fd2e5972425a772cca158eae58b05d4a25a4e474c221053e2d \ - --hash=sha256:a66bcdf19c1a523e41b8e9d53d0cedbfbac2e93c649a2e9502cb26c014d0980c \ - --hash=sha256:ae4070f741f8d809075ef697877fd350ecf0b7c5837ed68738607ee0a2c572cf \ - --hash=sha256:ae55d592b02c4349525b6ed8f74c692509e5adffa842e582c0f861751701a673 \ - --hash=sha256:b578cbe580e3b41ad17b1c428f382c814b32a6ce90f2d8e39e2e635d49e498d1 \ - --hash=sha256:b891a2f68e09c5ef989007fac11476ed33c5c9994449a4e2c3386529d703dc8b \ - --hash=sha256:baec8148d6b8bd5cee1ae138ba658c71f5b03e0d69d5907703e3e1df96db5e41 \ - --hash=sha256:bb06098d019766ca16fc915ecaa455c1f1cd594204e7f840cd6258237b5079a8 \ - --hash=sha256:bc791ec3fd0c4309a753f95bb6c749ef0d8ea3aea91f07ee1cf06b7b02118f2f \ - --hash=sha256:bd28b31730f0e982ace8663d108e01199098432a30a4c410d06fe08fdb9e93f4 \ - --hash=sha256:be4d9c2770044a59715eb57c1144dedea7c5d5ae80c68fb9959515037cde2008 \ - --hash=sha256:c0c72d34e7de5604df0fde3644cc079feee5e55464967d10b24b1de268deceb9 \ - --hash=sha256:c0e842112fe3f1a4ffcf64b06dc4c61a88441c2f02f373367f7b4c1aa9be2ad5 \ - --hash=sha256:c15070ebf11b8b7fd1bfff7217e9324963c82dbdf6182ff7050519e350e7ad9f \ - --hash=sha256:c2000c54c395d9e5e44c99dc7c20a64dc371f777faf8bae4919ad3e99ce5253e \ - --hash=sha256:c30187840d36d0ba2893bc3271a36a517a717f9fd383a98e2697ee890a37c273 \ - --hash=sha256:cb7cd68814308aade9d0c93c5bd2ade9f9441666f8ba5aa9c2d4b389cb5e2a45 \ - --hash=sha256:cd805513198304026bd379d1d516afbf6c3c13f4382134a2c526b8b854da1c2e \ - --hash=sha256:d0bf89afcbcf4d1bb2652f6580e5e55a840fdf87384f6063c4a4f0c95e378656 \ - --hash=sha256:d9137a876020661972ca6eec0766d81aef8a5627df628b664b234b73396e727e \ - --hash=sha256:dbd95e300367aa0827496fe75a1766d198d34385a58f97683fe6e07f89ca3e3c \ - --hash=sha256:dced27917823df984fe0c80a5c4ad75cf58df0fbfae890bc08004cd3888922a2 \ - --hash=sha256:de0b4caa1c8a21394e8ce971997614a17648f94e1cd0640fbd6b4d14cab13a72 \ - --hash=sha256:debb633f3f7856f95ad957d9b9c781f8e2c6303ef21724ec94bea2ce2fcbd056 \ - --hash=sha256:e372d7dfd154009142631de2d316adad3cc1c36c32a38b16a4751ba78da2a397 \ - --hash=sha256:ecd26be9f112c4f96718290c10f4caea6cc798459a3a76636b817a0ed7874e42 \ - --hash=sha256:edc0202099ea1d82844316604e17d2b175044f9bcb6b398aab781eba957224bd \ - --hash=sha256:f194cce575e59ffe442c10a360182a986535fd90b57f7debfaa5c845c409ecc3 \ - --hash=sha256:f5fb672c396d826ca16a022ac04c9dce74e00a1c344f6ad1a0fdc1ba1f332213 \ - --hash=sha256:f6a02a3c7950cafaadcd46a226ad9e12fc9744652cc69f9e5534f98b47f3bbcf \ - --hash=sha256:fe81b35c33772e56f4b6cf62cf4aedc1762ef7162a31e6ac7fe5e40d0149eb67 +charset-normalizer==3.3.2 \ + --hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \ + --hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \ + --hash=sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786 \ + --hash=sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8 \ + --hash=sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09 \ + --hash=sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185 \ + --hash=sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574 \ + --hash=sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e \ + --hash=sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519 \ + --hash=sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898 \ + --hash=sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269 \ + --hash=sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3 \ + --hash=sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f \ + --hash=sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6 \ + --hash=sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8 \ + --hash=sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a \ + --hash=sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73 \ + --hash=sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc \ + --hash=sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714 \ + --hash=sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2 \ + --hash=sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc \ + --hash=sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce \ + --hash=sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d \ + --hash=sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e \ + --hash=sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6 \ + --hash=sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269 \ + --hash=sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96 \ + --hash=sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d \ + --hash=sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a \ + --hash=sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4 \ + --hash=sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77 \ + --hash=sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d \ + --hash=sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0 \ + --hash=sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed \ + --hash=sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068 \ + --hash=sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac \ + --hash=sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25 \ + --hash=sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8 \ + --hash=sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab \ + --hash=sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26 \ + --hash=sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2 \ + --hash=sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db \ + --hash=sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f \ + --hash=sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5 \ + --hash=sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99 \ + --hash=sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c \ + --hash=sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d \ + --hash=sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811 \ + --hash=sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa \ + --hash=sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a \ + --hash=sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03 \ + --hash=sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b \ + --hash=sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04 \ + --hash=sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c \ + --hash=sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001 \ + --hash=sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458 \ + --hash=sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389 \ + --hash=sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99 \ + --hash=sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985 \ + --hash=sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537 \ + --hash=sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238 \ + --hash=sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f \ + --hash=sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d \ + --hash=sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796 \ + --hash=sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a \ + --hash=sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143 \ + --hash=sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8 \ + --hash=sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c \ + --hash=sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5 \ + --hash=sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5 \ + --hash=sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711 \ + --hash=sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4 \ + --hash=sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6 \ + --hash=sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c \ + --hash=sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7 \ + --hash=sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4 \ + --hash=sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b \ + --hash=sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae \ + --hash=sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12 \ + --hash=sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c \ + --hash=sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae \ + --hash=sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8 \ + --hash=sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887 \ + --hash=sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b \ + --hash=sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4 \ + --hash=sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f \ + --hash=sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5 \ + --hash=sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33 \ + --hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \ + --hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561 # via requests click==8.1.7 \ --hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \ diff --git a/requirements.txt b/requirements.txt index 786edb393..b51d33b8d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -108,97 +108,97 @@ cffi==1.16.0 \ --hash=sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956 \ --hash=sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357 # via cryptography -charset-normalizer==3.3.1 \ - --hash=sha256:06cf46bdff72f58645434d467bf5228080801298fbba19fe268a01b4534467f5 \ - --hash=sha256:0c8c61fb505c7dad1d251c284e712d4e0372cef3b067f7ddf82a7fa82e1e9a93 \ - --hash=sha256:10b8dd31e10f32410751b3430996f9807fc4d1587ca69772e2aa940a82ab571a \ - --hash=sha256:1171ef1fc5ab4693c5d151ae0fdad7f7349920eabbaca6271f95969fa0756c2d \ - --hash=sha256:17a866d61259c7de1bdadef418a37755050ddb4b922df8b356503234fff7932c \ - --hash=sha256:1d6bfc32a68bc0933819cfdfe45f9abc3cae3877e1d90aac7259d57e6e0f85b1 \ - --hash=sha256:1ec937546cad86d0dce5396748bf392bb7b62a9eeb8c66efac60e947697f0e58 \ - --hash=sha256:223b4d54561c01048f657fa6ce41461d5ad8ff128b9678cfe8b2ecd951e3f8a2 \ - --hash=sha256:2465aa50c9299d615d757c1c888bc6fef384b7c4aec81c05a0172b4400f98557 \ - --hash=sha256:28f512b9a33235545fbbdac6a330a510b63be278a50071a336afc1b78781b147 \ - --hash=sha256:2c092be3885a1b7899cd85ce24acedc1034199d6fca1483fa2c3a35c86e43041 \ - --hash=sha256:2c4c99f98fc3a1835af8179dcc9013f93594d0670e2fa80c83aa36346ee763d2 \ - --hash=sha256:31445f38053476a0c4e6d12b047b08ced81e2c7c712e5a1ad97bc913256f91b2 \ - --hash=sha256:31bbaba7218904d2eabecf4feec0d07469284e952a27400f23b6628439439fa7 \ - --hash=sha256:34d95638ff3613849f473afc33f65c401a89f3b9528d0d213c7037c398a51296 \ - --hash=sha256:352a88c3df0d1fa886562384b86f9a9e27563d4704ee0e9d56ec6fcd270ea690 \ - --hash=sha256:39b70a6f88eebe239fa775190796d55a33cfb6d36b9ffdd37843f7c4c1b5dc67 \ - --hash=sha256:3c66df3f41abee950d6638adc7eac4730a306b022570f71dd0bd6ba53503ab57 \ - --hash=sha256:3f70fd716855cd3b855316b226a1ac8bdb3caf4f7ea96edcccc6f484217c9597 \ - --hash=sha256:3f9bc2ce123637a60ebe819f9fccc614da1bcc05798bbbaf2dd4ec91f3e08846 \ - --hash=sha256:3fb765362688821404ad6cf86772fc54993ec11577cd5a92ac44b4c2ba52155b \ - --hash=sha256:45f053a0ece92c734d874861ffe6e3cc92150e32136dd59ab1fb070575189c97 \ - --hash=sha256:46fb9970aa5eeca547d7aa0de5d4b124a288b42eaefac677bde805013c95725c \ - --hash=sha256:4cb50a0335382aac15c31b61d8531bc9bb657cfd848b1d7158009472189f3d62 \ - --hash=sha256:4e12f8ee80aa35e746230a2af83e81bd6b52daa92a8afaef4fea4a2ce9b9f4fa \ - --hash=sha256:4f3100d86dcd03c03f7e9c3fdb23d92e32abbca07e7c13ebd7ddfbcb06f5991f \ - --hash=sha256:4f6e2a839f83a6a76854d12dbebde50e4b1afa63e27761549d006fa53e9aa80e \ - --hash=sha256:4f861d94c2a450b974b86093c6c027888627b8082f1299dfd5a4bae8e2292821 \ - --hash=sha256:501adc5eb6cd5f40a6f77fbd90e5ab915c8fd6e8c614af2db5561e16c600d6f3 \ - --hash=sha256:520b7a142d2524f999447b3a0cf95115df81c4f33003c51a6ab637cbda9d0bf4 \ - --hash=sha256:548eefad783ed787b38cb6f9a574bd8664468cc76d1538215d510a3cd41406cb \ - --hash=sha256:555fe186da0068d3354cdf4bbcbc609b0ecae4d04c921cc13e209eece7720727 \ - --hash=sha256:55602981b2dbf8184c098bc10287e8c245e351cd4fdcad050bd7199d5a8bf514 \ - --hash=sha256:58e875eb7016fd014c0eea46c6fa92b87b62c0cb31b9feae25cbbe62c919f54d \ - --hash=sha256:5a3580a4fdc4ac05f9e53c57f965e3594b2f99796231380adb2baaab96e22761 \ - --hash=sha256:5b70bab78accbc672f50e878a5b73ca692f45f5b5e25c8066d748c09405e6a55 \ - --hash=sha256:5ceca5876032362ae73b83347be8b5dbd2d1faf3358deb38c9c88776779b2e2f \ - --hash=sha256:61f1e3fb621f5420523abb71f5771a204b33c21d31e7d9d86881b2cffe92c47c \ - --hash=sha256:633968254f8d421e70f91c6ebe71ed0ab140220469cf87a9857e21c16687c034 \ - --hash=sha256:63a6f59e2d01310f754c270e4a257426fe5a591dc487f1983b3bbe793cf6bac6 \ - --hash=sha256:63accd11149c0f9a99e3bc095bbdb5a464862d77a7e309ad5938fbc8721235ae \ - --hash=sha256:6db3cfb9b4fcecb4390db154e75b49578c87a3b9979b40cdf90d7e4b945656e1 \ - --hash=sha256:71ef3b9be10070360f289aea4838c784f8b851be3ba58cf796262b57775c2f14 \ - --hash=sha256:7ae8e5142dcc7a49168f4055255dbcced01dc1714a90a21f87448dc8d90617d1 \ - --hash=sha256:7b6cefa579e1237ce198619b76eaa148b71894fb0d6bcf9024460f9bf30fd228 \ - --hash=sha256:800561453acdecedaac137bf09cd719c7a440b6800ec182f077bb8e7025fb708 \ - --hash=sha256:82ca51ff0fc5b641a2d4e1cc8c5ff108699b7a56d7f3ad6f6da9dbb6f0145b48 \ - --hash=sha256:851cf693fb3aaef71031237cd68699dded198657ec1e76a76eb8be58c03a5d1f \ - --hash=sha256:854cc74367180beb327ab9d00f964f6d91da06450b0855cbbb09187bcdb02de5 \ - --hash=sha256:87071618d3d8ec8b186d53cb6e66955ef2a0e4fa63ccd3709c0c90ac5a43520f \ - --hash=sha256:871d045d6ccc181fd863a3cd66ee8e395523ebfbc57f85f91f035f50cee8e3d4 \ - --hash=sha256:8aee051c89e13565c6bd366813c386939f8e928af93c29fda4af86d25b73d8f8 \ - --hash=sha256:8af5a8917b8af42295e86b64903156b4f110a30dca5f3b5aedea123fbd638bff \ - --hash=sha256:8ec8ef42c6cd5856a7613dcd1eaf21e5573b2185263d87d27c8edcae33b62a61 \ - --hash=sha256:91e43805ccafa0a91831f9cd5443aa34528c0c3f2cc48c4cb3d9a7721053874b \ - --hash=sha256:9505dc359edb6a330efcd2be825fdb73ee3e628d9010597aa1aee5aa63442e97 \ - --hash=sha256:985c7965f62f6f32bf432e2681173db41336a9c2611693247069288bcb0c7f8b \ - --hash=sha256:9a74041ba0bfa9bc9b9bb2cd3238a6ab3b7618e759b41bd15b5f6ad958d17605 \ - --hash=sha256:9edbe6a5bf8b56a4a84533ba2b2f489d0046e755c29616ef8830f9e7d9cf5728 \ - --hash=sha256:a15c1fe6d26e83fd2e5972425a772cca158eae58b05d4a25a4e474c221053e2d \ - --hash=sha256:a66bcdf19c1a523e41b8e9d53d0cedbfbac2e93c649a2e9502cb26c014d0980c \ - --hash=sha256:ae4070f741f8d809075ef697877fd350ecf0b7c5837ed68738607ee0a2c572cf \ - --hash=sha256:ae55d592b02c4349525b6ed8f74c692509e5adffa842e582c0f861751701a673 \ - --hash=sha256:b578cbe580e3b41ad17b1c428f382c814b32a6ce90f2d8e39e2e635d49e498d1 \ - --hash=sha256:b891a2f68e09c5ef989007fac11476ed33c5c9994449a4e2c3386529d703dc8b \ - --hash=sha256:baec8148d6b8bd5cee1ae138ba658c71f5b03e0d69d5907703e3e1df96db5e41 \ - --hash=sha256:bb06098d019766ca16fc915ecaa455c1f1cd594204e7f840cd6258237b5079a8 \ - --hash=sha256:bc791ec3fd0c4309a753f95bb6c749ef0d8ea3aea91f07ee1cf06b7b02118f2f \ - --hash=sha256:bd28b31730f0e982ace8663d108e01199098432a30a4c410d06fe08fdb9e93f4 \ - --hash=sha256:be4d9c2770044a59715eb57c1144dedea7c5d5ae80c68fb9959515037cde2008 \ - --hash=sha256:c0c72d34e7de5604df0fde3644cc079feee5e55464967d10b24b1de268deceb9 \ - --hash=sha256:c0e842112fe3f1a4ffcf64b06dc4c61a88441c2f02f373367f7b4c1aa9be2ad5 \ - --hash=sha256:c15070ebf11b8b7fd1bfff7217e9324963c82dbdf6182ff7050519e350e7ad9f \ - --hash=sha256:c2000c54c395d9e5e44c99dc7c20a64dc371f777faf8bae4919ad3e99ce5253e \ - --hash=sha256:c30187840d36d0ba2893bc3271a36a517a717f9fd383a98e2697ee890a37c273 \ - --hash=sha256:cb7cd68814308aade9d0c93c5bd2ade9f9441666f8ba5aa9c2d4b389cb5e2a45 \ - --hash=sha256:cd805513198304026bd379d1d516afbf6c3c13f4382134a2c526b8b854da1c2e \ - --hash=sha256:d0bf89afcbcf4d1bb2652f6580e5e55a840fdf87384f6063c4a4f0c95e378656 \ - --hash=sha256:d9137a876020661972ca6eec0766d81aef8a5627df628b664b234b73396e727e \ - --hash=sha256:dbd95e300367aa0827496fe75a1766d198d34385a58f97683fe6e07f89ca3e3c \ - --hash=sha256:dced27917823df984fe0c80a5c4ad75cf58df0fbfae890bc08004cd3888922a2 \ - --hash=sha256:de0b4caa1c8a21394e8ce971997614a17648f94e1cd0640fbd6b4d14cab13a72 \ - --hash=sha256:debb633f3f7856f95ad957d9b9c781f8e2c6303ef21724ec94bea2ce2fcbd056 \ - --hash=sha256:e372d7dfd154009142631de2d316adad3cc1c36c32a38b16a4751ba78da2a397 \ - --hash=sha256:ecd26be9f112c4f96718290c10f4caea6cc798459a3a76636b817a0ed7874e42 \ - --hash=sha256:edc0202099ea1d82844316604e17d2b175044f9bcb6b398aab781eba957224bd \ - --hash=sha256:f194cce575e59ffe442c10a360182a986535fd90b57f7debfaa5c845c409ecc3 \ - --hash=sha256:f5fb672c396d826ca16a022ac04c9dce74e00a1c344f6ad1a0fdc1ba1f332213 \ - --hash=sha256:f6a02a3c7950cafaadcd46a226ad9e12fc9744652cc69f9e5534f98b47f3bbcf \ - --hash=sha256:fe81b35c33772e56f4b6cf62cf4aedc1762ef7162a31e6ac7fe5e40d0149eb67 +charset-normalizer==3.3.2 \ + --hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \ + --hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \ + --hash=sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786 \ + --hash=sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8 \ + --hash=sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09 \ + --hash=sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185 \ + --hash=sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574 \ + --hash=sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e \ + --hash=sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519 \ + --hash=sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898 \ + --hash=sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269 \ + --hash=sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3 \ + --hash=sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f \ + --hash=sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6 \ + --hash=sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8 \ + --hash=sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a \ + --hash=sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73 \ + --hash=sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc \ + --hash=sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714 \ + --hash=sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2 \ + --hash=sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc \ + --hash=sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce \ + --hash=sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d \ + --hash=sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e \ + --hash=sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6 \ + --hash=sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269 \ + --hash=sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96 \ + --hash=sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d \ + --hash=sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a \ + --hash=sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4 \ + --hash=sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77 \ + --hash=sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d \ + --hash=sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0 \ + --hash=sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed \ + --hash=sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068 \ + --hash=sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac \ + --hash=sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25 \ + --hash=sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8 \ + --hash=sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab \ + --hash=sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26 \ + --hash=sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2 \ + --hash=sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db \ + --hash=sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f \ + --hash=sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5 \ + --hash=sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99 \ + --hash=sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c \ + --hash=sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d \ + --hash=sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811 \ + --hash=sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa \ + --hash=sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a \ + --hash=sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03 \ + --hash=sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b \ + --hash=sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04 \ + --hash=sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c \ + --hash=sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001 \ + --hash=sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458 \ + --hash=sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389 \ + --hash=sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99 \ + --hash=sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985 \ + --hash=sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537 \ + --hash=sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238 \ + --hash=sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f \ + --hash=sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d \ + --hash=sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796 \ + --hash=sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a \ + --hash=sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143 \ + --hash=sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8 \ + --hash=sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c \ + --hash=sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5 \ + --hash=sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5 \ + --hash=sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711 \ + --hash=sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4 \ + --hash=sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6 \ + --hash=sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c \ + --hash=sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7 \ + --hash=sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4 \ + --hash=sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b \ + --hash=sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae \ + --hash=sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12 \ + --hash=sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c \ + --hash=sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae \ + --hash=sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8 \ + --hash=sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887 \ + --hash=sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b \ + --hash=sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4 \ + --hash=sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f \ + --hash=sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5 \ + --hash=sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33 \ + --hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \ + --hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561 # via requests click==8.1.7 \ --hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \ From 90e41d6b7c5865d12cee3baeaa246093e42c87a3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 15:49:37 -0500 Subject: [PATCH 04/13] build(deps): bump botocore from 1.31.75 to 1.31.78 (#954) Bumps [botocore](https://github.com/boto/botocore) from 1.31.75 to 1.31.78. - [Changelog](https://github.com/boto/botocore/blob/develop/CHANGELOG.rst) - [Commits](https://github.com/boto/botocore/compare/1.31.75...1.31.78) --- updated-dependencies: - dependency-name: botocore dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements-dev.txt | 6 +++--- requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index f2cf93769..8117ab435 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -40,9 +40,9 @@ boto3==1.28.75 \ --hash=sha256:63d772a784e8e35ee51974eb1c20dff5faa51b007d22c5647783f18966bf4042 \ --hash=sha256:b959decd588982bc919bfcbebc7916926b05003a0093e7f2845362da4f5dd9fc # via moto -botocore==1.31.75 \ - --hash=sha256:d704ea9867b2227de0350bc2a5ca2543349e164ecb5d15edbfacbb05f2056482 \ - --hash=sha256:fa078c4aa9a5777b3ede756540e62fec551e13d39cf7abf9a37bb81981496d68 +botocore==1.31.78 \ + --hash=sha256:320c70bc412157813c2cf60217a592b4b345f8e97e4bf3b1ce49b6be69ed8965 \ + --hash=sha256:a9ca8deeb3f47a10a25637859fee8d81cac2db37ace819d24471279e44879547 # via # boto3 # moto diff --git a/requirements.txt b/requirements.txt index b51d33b8d..da2dfaa95 100644 --- a/requirements.txt +++ b/requirements.txt @@ -31,9 +31,9 @@ boto3==1.28.75 \ # via # -r requirements/base.in # django-ses -botocore==1.31.75 \ - --hash=sha256:d704ea9867b2227de0350bc2a5ca2543349e164ecb5d15edbfacbb05f2056482 \ - --hash=sha256:fa078c4aa9a5777b3ede756540e62fec551e13d39cf7abf9a37bb81981496d68 +botocore==1.31.78 \ + --hash=sha256:320c70bc412157813c2cf60217a592b4b345f8e97e4bf3b1ce49b6be69ed8965 \ + --hash=sha256:a9ca8deeb3f47a10a25637859fee8d81cac2db37ace819d24471279e44879547 # via # boto3 # s3transfer From 32191fe020860f78dfb2e89adf9c875e2b1cdaeb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 15:49:50 -0500 Subject: [PATCH 05/13] build(deps): bump httpx from 0.25.0 to 0.25.1 (#953) Bumps [httpx](https://github.com/encode/httpx) from 0.25.0 to 0.25.1. - [Release notes](https://github.com/encode/httpx/releases) - [Changelog](https://github.com/encode/httpx/blob/master/CHANGELOG.md) - [Commits](https://github.com/encode/httpx/compare/0.25.0...0.25.1) --- updated-dependencies: - dependency-name: httpx dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements-dev.txt | 6 +++--- requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 8117ab435..dbc455f4d 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -315,9 +315,9 @@ httpcore==0.18.0 \ --hash=sha256:13b5e5cd1dca1a6636a6aaea212b19f4f85cd88c366a2b82304181b769aab3c9 \ --hash=sha256:adc5398ee0a476567bf87467063ee63584a8bce86078bf748e48754f60202ced # via httpx -httpx==0.25.0 \ - --hash=sha256:181ea7f8ba3a82578be86ef4171554dd45fec26a02556a744db029a0a27b7100 \ - --hash=sha256:47ecda285389cb32bb2691cc6e069e3ab0205956f681c5b2ad2325719751d875 +httpx==0.25.1 \ + --hash=sha256:fec7d6cc5c27c578a391f7e87b9aa7d3d8fbcd034f6399f9f79b45bcc12a866a \ + --hash=sha256:ffd96d5cf901e63863d9f1b4b6807861dbea4d301613415d9e6e57ead15fc5d0 # via respx idna==3.4 \ --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ diff --git a/requirements.txt b/requirements.txt index da2dfaa95..61bdea424 100644 --- a/requirements.txt +++ b/requirements.txt @@ -445,9 +445,9 @@ httpcore==0.18.0 \ --hash=sha256:13b5e5cd1dca1a6636a6aaea212b19f4f85cd88c366a2b82304181b769aab3c9 \ --hash=sha256:adc5398ee0a476567bf87467063ee63584a8bce86078bf748e48754f60202ced # via httpx -httpx==0.25.0 \ - --hash=sha256:181ea7f8ba3a82578be86ef4171554dd45fec26a02556a744db029a0a27b7100 \ - --hash=sha256:47ecda285389cb32bb2691cc6e069e3ab0205956f681c5b2ad2325719751d875 +httpx==0.25.1 \ + --hash=sha256:fec7d6cc5c27c578a391f7e87b9aa7d3d8fbcd034f6399f9f79b45bcc12a866a \ + --hash=sha256:ffd96d5cf901e63863d9f1b4b6807861dbea4d301613415d9e6e57ead15fc5d0 # via -r requirements/base.in idna==3.4 \ --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ From 7cae8e05808ef530db01bb8cf7a0b6a7c82721a8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 15:50:12 -0500 Subject: [PATCH 06/13] build(deps-dev): bump responses from 0.23.3 to 0.24.0 (#958) Bumps [responses](https://github.com/getsentry/responses) from 0.23.3 to 0.24.0. - [Release notes](https://github.com/getsentry/responses/releases) - [Changelog](https://github.com/getsentry/responses/blob/master/CHANGES) - [Commits](https://github.com/getsentry/responses/compare/0.23.3...0.24.0) --- updated-dependencies: - dependency-name: responses dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements-dev.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index dbc455f4d..26ef20e5d 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -583,9 +583,9 @@ requests==2.31.0 \ # via # moto # responses -responses==0.23.3 \ - --hash=sha256:205029e1cb334c21cb4ec64fc7599be48b859a0fd381a42443cdd600bfe8b16a \ - --hash=sha256:e6fbcf5d82172fecc0aa1860fd91e58cbfd96cee5e96da5b63fa6eb3caa10dd3 +responses==0.24.0 \ + --hash=sha256:060be153c270c06fa4d22c1ef8865fdef43902eb595204deeef736cddb62d353 \ + --hash=sha256:3df82f7d4dcd3e5f61498181aadb4381f291da25c7506c47fe8cb68ce29203e7 # via moto respx==0.20.2 \ --hash=sha256:07cf4108b1c88b82010f67d3c831dae33a375c7b436e54d87737c7f9f99be643 \ From 89774a8d81fd5a9caea9a4dc1e5eac7f4e9b222a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 15:57:47 -0500 Subject: [PATCH 07/13] build(deps): bump httpcore from 0.18.0 to 1.0.1 (#957) Bumps [httpcore](https://github.com/encode/httpcore) from 0.18.0 to 1.0.1. - [Release notes](https://github.com/encode/httpcore/releases) - [Changelog](https://github.com/encode/httpcore/blob/master/CHANGELOG.md) - [Commits](https://github.com/encode/httpcore/compare/0.18.0...1.0.1) --- updated-dependencies: - dependency-name: httpcore dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements-dev.txt | 6 +++--- requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 26ef20e5d..acb0053e1 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -311,9 +311,9 @@ h11==0.14.0 \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 # via httpcore -httpcore==0.18.0 \ - --hash=sha256:13b5e5cd1dca1a6636a6aaea212b19f4f85cd88c366a2b82304181b769aab3c9 \ - --hash=sha256:adc5398ee0a476567bf87467063ee63584a8bce86078bf748e48754f60202ced +httpcore==1.0.1 \ + --hash=sha256:c5e97ef177dca2023d0b9aad98e49507ef5423e9f1d94ffe2cfe250aa28e63b0 \ + --hash=sha256:fce1ddf9b606cfb98132ab58865c3728c52c8e4c3c46e2aabb3674464a186e92 # via httpx httpx==0.25.1 \ --hash=sha256:fec7d6cc5c27c578a391f7e87b9aa7d3d8fbcd034f6399f9f79b45bcc12a866a \ diff --git a/requirements.txt b/requirements.txt index 61bdea424..59a96ee7f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -441,9 +441,9 @@ h11==0.14.0 \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 # via httpcore -httpcore==0.18.0 \ - --hash=sha256:13b5e5cd1dca1a6636a6aaea212b19f4f85cd88c366a2b82304181b769aab3c9 \ - --hash=sha256:adc5398ee0a476567bf87467063ee63584a8bce86078bf748e48754f60202ced +httpcore==1.0.1 \ + --hash=sha256:c5e97ef177dca2023d0b9aad98e49507ef5423e9f1d94ffe2cfe250aa28e63b0 \ + --hash=sha256:fce1ddf9b606cfb98132ab58865c3728c52c8e4c3c46e2aabb3674464a186e92 # via httpx httpx==0.25.1 \ --hash=sha256:fec7d6cc5c27c578a391f7e87b9aa7d3d8fbcd034f6399f9f79b45bcc12a866a \ From 543edfee244ac0eb96f63a011443e44fb628d3e9 Mon Sep 17 00:00:00 2001 From: Paul Schreiber Date: Mon, 6 Nov 2023 16:44:29 -0500 Subject: [PATCH 08/13] chore: update dependencies (#961) --- requirements-dev.txt | 19 +++++++------------ requirements.txt | 37 ++++++++----------------------------- 2 files changed, 15 insertions(+), 41 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index acb0053e1..c027f8a45 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -7,7 +7,7 @@ anyio==4.0.0 \ --hash=sha256:cfdb2b588b9fc25ede96d8db56ed50848b0b649dca3dd1df0b11f683bb9e0b5f \ --hash=sha256:f7ed51751b2c2add651e5747c891b47e26d2a21be5d32d9311dfe9692f3e5d7a - # via httpcore + # via httpx appnope==0.1.3 \ --hash=sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24 \ --hash=sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e @@ -36,13 +36,13 @@ black==23.10.1 \ --hash=sha256:e293e4c2f4a992b980032bbd62df07c1bcff82d6964d6c9496f2cd726e246ace \ --hash=sha256:ec3f8e6234c4e46ff9e16d9ae96f4ef69fa328bb4ad08198c8cee45bb1f08c69 # via -r requirements/dev.in -boto3==1.28.75 \ - --hash=sha256:63d772a784e8e35ee51974eb1c20dff5faa51b007d22c5647783f18966bf4042 \ - --hash=sha256:b959decd588982bc919bfcbebc7916926b05003a0093e7f2845362da4f5dd9fc +boto3==1.28.79 \ + --hash=sha256:02ce7dcad2d3b054cd99e7ca6df7a708e016a31b1c98b46d8df3b3891070c121 \ + --hash=sha256:b8acb57a124434284d6ab69c61d32d70e84e13e2c27c33b4ad3c32f15ad407d3 # via moto -botocore==1.31.78 \ - --hash=sha256:320c70bc412157813c2cf60217a592b4b345f8e97e4bf3b1ce49b6be69ed8965 \ - --hash=sha256:a9ca8deeb3f47a10a25637859fee8d81cac2db37ace819d24471279e44879547 +botocore==1.31.79 \ + --hash=sha256:07ecb93833475dde68e5c0e02a7ccf8ca22caf68cdc892651c300529894133e1 \ + --hash=sha256:6f1fc49e9e12f9772b4fef577837670bc84d772a7c946b4d08fe2890e34a4305 # via # boto3 # moto @@ -606,7 +606,6 @@ sniffio==1.3.0 \ --hash=sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384 # via # anyio - # httpcore # httpx stack-data==0.6.3 \ --hash=sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9 \ @@ -618,10 +617,6 @@ traitlets==5.13.0 \ # via # ipython # matplotlib-inline -types-pyyaml==6.0.12.12 \ - --hash=sha256:334373d392fde0fdf95af5c3f1661885fa10c52167b14593eb856289e1855062 \ - --hash=sha256:c05bc6c158facb0676674b7f11fe3960db4f389718e19e62bd2b84d6205cfd24 - # via responses urllib3==2.0.7 \ --hash=sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84 \ --hash=sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e diff --git a/requirements.txt b/requirements.txt index 59a96ee7f..6d5adde06 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,7 @@ aniso8601==9.0.1 \ anyio==4.0.0 \ --hash=sha256:cfdb2b588b9fc25ede96d8db56ed50848b0b649dca3dd1df0b11f683bb9e0b5f \ --hash=sha256:f7ed51751b2c2add651e5747c891b47e26d2a21be5d32d9311dfe9692f3e5d7a - # via httpcore + # via httpx asgiref==3.7.2 \ --hash=sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e \ --hash=sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed @@ -25,15 +25,15 @@ attrs==23.1.0 \ # cattrs # ddtrace # fiona -boto3==1.28.75 \ - --hash=sha256:63d772a784e8e35ee51974eb1c20dff5faa51b007d22c5647783f18966bf4042 \ - --hash=sha256:b959decd588982bc919bfcbebc7916926b05003a0093e7f2845362da4f5dd9fc +boto3==1.28.79 \ + --hash=sha256:02ce7dcad2d3b054cd99e7ca6df7a708e016a31b1c98b46d8df3b3891070c121 \ + --hash=sha256:b8acb57a124434284d6ab69c61d32d70e84e13e2c27c33b4ad3c32f15ad407d3 # via # -r requirements/base.in # django-ses -botocore==1.31.78 \ - --hash=sha256:320c70bc412157813c2cf60217a592b4b345f8e97e4bf3b1ce49b6be69ed8965 \ - --hash=sha256:a9ca8deeb3f47a10a25637859fee8d81cac2db37ace819d24471279e44879547 +botocore==1.31.79 \ + --hash=sha256:07ecb93833475dde68e5c0e02a7ccf8ca22caf68cdc892651c300529894133e1 \ + --hash=sha256:6f1fc49e9e12f9772b4fef577837670bc84d772a7c946b4d08fe2890e34a4305 # via # boto3 # s3transfer @@ -573,24 +573,6 @@ protobuf==4.25.0 \ # via # ddsketch # ddtrace -psutil==5.9.6 \ - --hash=sha256:10e8c17b4f898d64b121149afb136c53ea8b68c7531155147867b7b1ac9e7e28 \ - --hash=sha256:18cd22c5db486f33998f37e2bb054cc62fd06646995285e02a51b1e08da97017 \ - --hash=sha256:3ebf2158c16cc69db777e3c7decb3c0f43a7af94a60d72e87b2823aebac3d602 \ - --hash=sha256:51dc3d54607c73148f63732c727856f5febec1c7c336f8f41fcbd6315cce76ac \ - --hash=sha256:6e5fb8dc711a514da83098bc5234264e551ad980cec5f85dabf4d38ed6f15e9a \ - --hash=sha256:70cb3beb98bc3fd5ac9ac617a327af7e7f826373ee64c80efd4eb2856e5051e9 \ - --hash=sha256:748c9dd2583ed86347ed65d0035f45fa8c851e8d90354c122ab72319b5f366f4 \ - --hash=sha256:91ecd2d9c00db9817a4b4192107cf6954addb5d9d67a969a4f436dbc9200f88c \ - --hash=sha256:92e0cc43c524834af53e9d3369245e6cc3b130e78e26100d1f63cdb0abeb3d3c \ - --hash=sha256:a6f01f03bf1843280f4ad16f4bde26b817847b4c1a0db59bf6419807bc5ce05c \ - --hash=sha256:c69596f9fc2f8acd574a12d5f8b7b1ba3765a641ea5d60fb4736bf3c08a8214a \ - --hash=sha256:ca2780f5e038379e520281e4c032dddd086906ddff9ef0d1b9dcf00710e5071c \ - --hash=sha256:daecbcbd29b289aac14ece28eca6a3e60aa361754cf6da3dfb20d4d32b6c7f57 \ - --hash=sha256:e4b92ddcd7dd4cdd3f900180ea1e104932c7bce234fb88976e2a3b296441225a \ - --hash=sha256:fb8a697f11b0f5994550555fcfe3e69799e5b060c8ecf9e2f75c69302cc35c0d \ - --hash=sha256:ff18b8d1a784b810df0b0fff3bcb50ab941c3b8e2c8de5726f9c71c601c611aa - # via ddtrace psycopg2==2.9.9 \ --hash=sha256:121081ea2e76729acfb0673ff33755e8703d45e926e416cb59bae3a86c6a4981 \ --hash=sha256:38a8dcc6856f569068b47de286b472b7c473ac7977243593a288ebce0dc89516 \ @@ -732,7 +714,6 @@ sniffio==1.3.0 \ --hash=sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384 # via # anyio - # httpcore # httpx sqlparse==0.4.4 \ --hash=sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3 \ @@ -838,9 +819,7 @@ wrapt==1.15.0 \ --hash=sha256:f87ec75864c37c4c6cb908d282e1969e79763e0d9becdfe9fe5473b7bb1e5f09 \ --hash=sha256:fbec11614dba0424ca72f4e8ba3c420dba07b4a7c206c8c8e4e73f2e98f4c559 \ --hash=sha256:fd69666217b62fa5d7c6aa88e507493a34dec4fa20c5bd925e4bc12fce586639 - # via - # ddtrace - # deprecated + # via deprecated xmltodict==0.13.0 \ --hash=sha256:341595a488e3e01a85a9d8911d8912fd922ede5fecc4dce437eb4b6c8d037e56 \ --hash=sha256:aa89e8fd76320154a40d19a0df04a4695fb9dc5ba977cbb68ab3e4eb225e7852 From 2162f0e6d8eaf1e8b02ad50df24e350eb19db0c8 Mon Sep 17 00:00:00 2001 From: Jose Buitron Date: Wed, 8 Nov 2023 15:07:43 -0500 Subject: [PATCH 09/13] feat: Visualization (data map) GIS formats support (#917) --- terraso_backend/apps/core/gis/mapbox.py | 8 +- terraso_backend/apps/core/gis/parsers.py | 37 ++++ terraso_backend/apps/core/views.py | 44 +--- .../apps/graphql/schema/data_entries.py | 14 ++ .../apps/graphql/schema/schema.graphql | 3 + .../graphql/schema/visualization_config.py | 2 + .../0017_visualizationconfig_description.py | 35 +++ .../models/visualization_config.py | 1 + .../visualization_tileset_tasks.py | 145 ++++++------ .../tests/core/gis/test_parsers.py | 206 +++++++++--------- terraso_backend/tests/graphql/conftest.py | 30 +++ .../tests/graphql/test_shared_data.py | 120 ++++++++++ .../graphql/test_visualization_config.py | 4 + terraso_backend/tests/shared_data/conftest.py | 16 ++ .../test_visualization_tileset_tasks.py | 71 +++++- 15 files changed, 527 insertions(+), 209 deletions(-) create mode 100644 terraso_backend/apps/shared_data/migrations/0017_visualizationconfig_description.py diff --git a/terraso_backend/apps/core/gis/mapbox.py b/terraso_backend/apps/core/gis/mapbox.py index 9457aa6f4..db3066844 100644 --- a/terraso_backend/apps/core/gis/mapbox.py +++ b/terraso_backend/apps/core/gis/mapbox.py @@ -84,11 +84,15 @@ def get_publish_status(id): return len(response_json) > 0 +def get_line_delimited_geojson(geojson): + return "\n".join([json.dumps(feature) for feature in geojson["features"]]) + + def _post_tileset_source(geojson, id): - line_delimited_geojson = "\n".join([json.dumps(feature) for feature in geojson["features"]]) + line_delimited_geojson = get_line_delimited_geojson(geojson) url = f"{API_URL}/tilesets/v1/sources/{USERNAME}/{id}?access_token={TOKEN}" - multipart_data = [("file", ("test.ndjson", line_delimited_geojson, "text/plain"))] + multipart_data = [("file", ("input.ndjson", line_delimited_geojson, "text/plain"))] response = requests.post(url, files=multipart_data) response_json = response.json() diff --git a/terraso_backend/apps/core/gis/parsers.py b/terraso_backend/apps/core/gis/parsers.py index 5d2d7b429..17e90f5c9 100644 --- a/terraso_backend/apps/core/gis/parsers.py +++ b/terraso_backend/apps/core/gis/parsers.py @@ -19,13 +19,21 @@ import zipfile import geopandas as gpd +import structlog +from django.core.exceptions import ValidationError from fiona.drvsupport import supported_drivers from apps.core.gis.utils import DEFAULT_CRS +logger = structlog.get_logger(__name__) + supported_drivers["KML"] = "rw" +def is_geojson_file_extension(file): + return file.name.endswith((".geojson", ".json")) + + def is_shape_file_extension(file): return file.name.endswith(".zip") @@ -96,3 +104,32 @@ def parse_shapefile(file): os.rmdir(tmp_folder) return json.loads(gdf_transformed.to_json()) + + +def parse_file_to_geojson(file): + if is_shape_file_extension(file): + try: + return parse_shapefile(file) + except Exception as e: + logger.error("Error parsing shapefile", error=e) + raise ValidationError("invalid_shapefile") + elif is_kml_file_extension(file): + try: + return parse_kml_file(file) + except Exception as e: + logger.error("Error parsing kml file", error=e) + raise ValidationError("invalid_kml_file") + elif is_kmz_file_extension(file): + try: + return parse_kmz_file(file) + except Exception as e: + logger.error("Error parsing kmz file", error=e) + raise ValidationError("invalid_kmz_file") + elif is_geojson_file_extension(file): + try: + return json.load(file) + except Exception as e: + logger.error("Error parsing geojson file", error=e) + raise ValidationError("invalid_geojson_file") + else: + raise ValidationError("invalid_file_type") diff --git a/terraso_backend/apps/core/views.py b/terraso_backend/apps/core/views.py index 7a682a339..bbe10a0e1 100644 --- a/terraso_backend/apps/core/views.py +++ b/terraso_backend/apps/core/views.py @@ -25,6 +25,7 @@ from django.contrib.admin.views.decorators import staff_member_required from django.contrib.sessions.models import Session from django.core import management +from django.core.exceptions import ValidationError from django.db import DatabaseError, transaction from django.db.transaction import get_connection from django.http import ( @@ -37,14 +38,7 @@ from django.views.generic.edit import FormView from apps.auth.mixins import AuthenticationRequiredMixin -from apps.core.gis.parsers import ( - is_kml_file_extension, - is_kmz_file_extension, - is_shape_file_extension, - parse_kml_file, - parse_kmz_file, - parse_shapefile, -) +from apps.core.gis.parsers import parse_file_to_geojson from apps.core.models import BackgroundTask, Group, Landscape, User logger = structlog.get_logger(__name__) @@ -56,37 +50,11 @@ class ParseGeoFileView(AuthenticationRequiredMixin, FormView): def post(self, request, **kwargs): file = request.FILES.get("file") - geojson = None - if is_shape_file_extension(file): - try: - geojson = parse_shapefile(file) - except Exception as e: - logger.exception(f"Error when parsing shapefile. File name: {file.name}", error=e) - return JsonResponse( - {"errors": [{"message": json.dumps([{"code": "invalid_shapefile"}])}]}, - status=400, - ) - elif is_kml_file_extension(file): - try: - geojson = parse_kml_file(file) - except Exception as e: - logger.exception(f"Error when parsing KML file. File name: {file.name}", error=e) - return JsonResponse( - {"errors": [{"message": json.dumps([{"code": "invalid_kml_file"}])}]}, - status=400, - ) - elif is_kmz_file_extension(file): - try: - geojson = parse_kmz_file(file) - except Exception as e: - logger.exception(f"Error when parsing KMZ file. File name: {file.name}", error=e) - return JsonResponse( - {"errors": [{"message": json.dumps([{"code": "invalid_kmz_file"}])}]}, - status=400, - ) - else: + try: + geojson = parse_file_to_geojson(file) + except ValidationError as error: return JsonResponse( - {"error": f"File type not supported. File type: {file.content_type}"}, status=400 + {"errors": [{"message": json.dumps([{"code": error.message}])}]}, status=400 ) return JsonResponse({"geojson": geojson}) diff --git a/terraso_backend/apps/graphql/schema/data_entries.py b/terraso_backend/apps/graphql/schema/data_entries.py index 5ba5689d2..783fbf599 100644 --- a/terraso_backend/apps/graphql/schema/data_entries.py +++ b/terraso_backend/apps/graphql/schema/data_entries.py @@ -17,16 +17,20 @@ import graphene import rules import structlog +from django.conf import settings from django.contrib.contenttypes.models import ContentType +from django.core.exceptions import ValidationError from django.db import transaction from django.db.models import Q from graphene import relay from graphene_django import DjangoObjectType +from apps.core.gis.parsers import parse_file_to_geojson from apps.core.models import Group, Landscape, Membership from apps.graphql.exceptions import GraphQLNotAllowedException, GraphQLNotFoundException from apps.shared_data.models import DataEntry from apps.shared_data.models.data_entries import VALID_TARGET_TYPES +from apps.shared_data.services import data_entry_upload_service from .commons import BaseDeleteMutation, BaseWriteMutation, TerrasoConnection from .constants import MutationTypes @@ -70,6 +74,7 @@ def filter_shared_resources_target_content_type(self, queryset, name, value): class DataEntryNode(DjangoObjectType, SharedResourcesMixin): id = graphene.ID(source="pk", required=True) + geojson = graphene.JSONString() class Meta: model = DataEntry @@ -117,6 +122,15 @@ def resolve_url(self, info): return self.signed_url return self.url + def resolve_geojson(self, info): + if f".{self.resource_type}" not in settings.DATA_ENTRY_GIS_TYPES.keys(): + return None + file = data_entry_upload_service.get_file(self.s3_object_name, "rb") + try: + return parse_file_to_geojson(file) + except ValidationError: + return None + class DataEntryAddMutation(BaseWriteMutation): data_entry = graphene.Field(DataEntryNode) diff --git a/terraso_backend/apps/graphql/schema/schema.graphql b/terraso_backend/apps/graphql/schema/schema.graphql index 6cb5bd914..5402a63f8 100644 --- a/terraso_backend/apps/graphql/schema/schema.graphql +++ b/terraso_backend/apps/graphql/schema/schema.graphql @@ -436,6 +436,7 @@ type VisualizationConfigNode implements Node { createdAt: DateTime! slug: String! title: String! + description: String configuration: JSONString createdBy: UserNode mapboxTilesetId: String @@ -464,6 +465,7 @@ type DataEntryNode implements Node { visualizations(offset: Int, before: String, after: String, first: Int, last: Int, slug: String, slug_Icontains: String, dataEntry_SharedResources_TargetObjectId: UUID, dataEntry_SharedResources_Target_Slug: String, dataEntry_SharedResources_TargetContentType: String): VisualizationConfigNodeConnection! id: ID! sharedResources(offset: Int, before: String, after: String, first: Int, last: Int, source_DataEntry_ResourceType_In: [String]): SharedResourceNodeConnection + geojson: JSONString } """An enumeration.""" @@ -1997,6 +1999,7 @@ type VisualizationConfigAddMutationPayload { input VisualizationConfigAddMutationInput { title: String! + description: String configuration: JSONString dataEntryId: ID! ownerId: ID! diff --git a/terraso_backend/apps/graphql/schema/visualization_config.py b/terraso_backend/apps/graphql/schema/visualization_config.py index bfa82a8d8..6dd0fc0a9 100644 --- a/terraso_backend/apps/graphql/schema/visualization_config.py +++ b/terraso_backend/apps/graphql/schema/visualization_config.py @@ -88,6 +88,7 @@ class Meta: "id", "slug", "title", + "description", "configuration", "created_by", "created_at", @@ -133,6 +134,7 @@ class VisualizationConfigAddMutation(BaseWriteMutation): class Input: title = graphene.String(required=True) + description = graphene.String() configuration = graphene.JSONString() data_entry_id = graphene.ID(required=True) ownerId = graphene.ID(required=True) diff --git a/terraso_backend/apps/shared_data/migrations/0017_visualizationconfig_description.py b/terraso_backend/apps/shared_data/migrations/0017_visualizationconfig_description.py new file mode 100644 index 000000000..9d30301db --- /dev/null +++ b/terraso_backend/apps/shared_data/migrations/0017_visualizationconfig_description.py @@ -0,0 +1,35 @@ +# Copyright © 2023 Technology Matters +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see https://www.gnu.org/licenses/. + +# Generated by Django 4.2.6 on 2023-10-20 22:14 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("shared_data", "0016_remove_dataentry_groups_and_more"), + ] + + operations = [ + migrations.AddField( + model_name="visualizationconfig", + name="description", + field=models.TextField(blank=True, null=True), + ), + ] diff --git a/terraso_backend/apps/shared_data/models/visualization_config.py b/terraso_backend/apps/shared_data/models/visualization_config.py index 1b2d1b354..c49062690 100644 --- a/terraso_backend/apps/shared_data/models/visualization_config.py +++ b/terraso_backend/apps/shared_data/models/visualization_config.py @@ -35,6 +35,7 @@ class VisualizationConfig(SlugModel): ) title = models.CharField(max_length=128, validators=[validate_name]) + description = models.TextField(blank=True, null=True) configuration = models.JSONField(blank=True, null=True) created_by = models.ForeignKey( User, diff --git a/terraso_backend/apps/shared_data/visualization_tileset_tasks.py b/terraso_backend/apps/shared_data/visualization_tileset_tasks.py index a3d0b55a4..b5bba752f 100644 --- a/terraso_backend/apps/shared_data/visualization_tileset_tasks.py +++ b/terraso_backend/apps/shared_data/visualization_tileset_tasks.py @@ -7,6 +7,7 @@ from django.conf import settings from apps.core.gis.mapbox import create_tileset, remove_tileset +from apps.core.gis.parsers import parse_file_to_geojson from apps.shared_data.services import data_entry_upload_service from .models import VisualizationConfig @@ -62,85 +63,105 @@ def get_owner_name(visualization): return visualization.owner.name if visualization.owner else "Unknown" -def create_mapbox_tileset(visualization_id): - logger.info("Creating mapbox tileset", visualization_id=visualization_id) - visualization = VisualizationConfig.objects.get(pk=visualization_id) - data_entry = visualization.data_entry - owner_name = get_owner_name(visualization) +def _get_geojson_from_dataset(data_entry, visualization): + rows = get_rows_from_file(data_entry) - # You cannot update a Mapbox tileset. We have to delete it and create a new one. - remove_mapbox_tileset(visualization.mapbox_tileset_id) + first_row = rows[0] - try: - rows = get_rows_from_file(data_entry) + dataset_config = visualization.configuration["datasetConfig"] + annotate_config = visualization.configuration["annotateConfig"] - first_row = rows[0] + longitude_column = dataset_config["longitude"] + longitude_index = first_row.index(longitude_column) - dataset_config = visualization.configuration["datasetConfig"] - annotate_config = visualization.configuration["annotateConfig"] + latitude_column = dataset_config["latitude"] + latitude_index = first_row.index(latitude_column) - longitude_column = dataset_config["longitude"] - longitude_index = first_row.index(longitude_column) + data_points = annotate_config["dataPoints"] + data_points_indexes = [ + { + "label": data_point.get("label", data_point["column"]), + "index": first_row.index(data_point["column"]), + } + for data_point in data_points + ] - latitude_column = dataset_config["latitude"] - latitude_index = first_row.index(latitude_column) + annotation_title = annotate_config.get("annotationTitle") - data_points = annotate_config["dataPoints"] - data_points_indexes = [ + title_index = ( + first_row.index(annotation_title) + if annotation_title and annotation_title in first_row + else None + ) + + features = [] + for row in rows: + fields = [ { - "label": data_point.get("label", data_point["column"]), - "index": first_row.index(data_point["column"]), + "label": data_point["label"], + "value": row[data_point["index"]], } - for data_point in data_points + for data_point in data_points_indexes ] - annotation_title = annotate_config.get("annotationTitle") - - title_index = ( - first_row.index(annotation_title) - if annotation_title and annotation_title in first_row - else None - ) + properties = { + "title": row[title_index] if title_index else None, + "fields": json.dumps(fields), + } - features = [] - for row in rows: - fields = [ - { - "label": data_point["label"], - "value": row[data_point["index"]], - } - for data_point in data_points_indexes - ] - - properties = { - "title": row[title_index] if title_index else None, - "fields": json.dumps(fields), + try: + longitude = float(row[longitude_index]) + latitude = float(row[latitude_index]) + feature = { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [longitude, latitude], + }, + "properties": properties, } - try: - longitude = float(row[longitude_index]) - latitude = float(row[latitude_index]) - feature = { - "type": "Feature", - "geometry": { - "type": "Point", - "coordinates": [longitude, latitude], - }, - "properties": properties, - } - - features.append(feature) - except ValueError: - continue - - geojson = { - "type": "FeatureCollection", - "features": features, - } + features.append(feature) + except ValueError: + continue + + return { + "type": "FeatureCollection", + "features": features, + } + + +def _get_geojson_from_gis(data_entry): + file = data_entry_upload_service.get_file(data_entry.s3_object_name, "rb") + return parse_file_to_geojson(file) + + +def _get_geojson_from_data_entry(data_entry, visualization): + is_dataset = f".{data_entry.resource_type}" in settings.DATA_ENTRY_SPREADSHEET_TYPES.keys() + is_gis = f".{data_entry.resource_type}" in settings.DATA_ENTRY_GIS_TYPES.keys() + + if is_dataset: + return _get_geojson_from_dataset(data_entry, visualization) + + if is_gis: + return _get_geojson_from_gis(data_entry) + + +def create_mapbox_tileset(visualization_id): + logger.info("Creating mapbox tileset", visualization_id=visualization_id) + visualization = VisualizationConfig.objects.get(pk=visualization_id) + data_entry = visualization.data_entry + owner_name = get_owner_name(visualization) + + # You cannot update a Mapbox tileset. We have to delete it and create a new one. + remove_mapbox_tileset(visualization.mapbox_tileset_id) + + try: + geojson = _get_geojson_from_data_entry(data_entry, visualization) logger.info( "Geojson generated for mapbox tileset", visualization_id=visualization_id, - rows=len(rows), + features=len(geojson["features"]), ) # Include the environment in the title and description when calling the Mapbox API. diff --git a/terraso_backend/tests/core/gis/test_parsers.py b/terraso_backend/tests/core/gis/test_parsers.py index 94ec1c906..1e54e1f83 100644 --- a/terraso_backend/tests/core/gis/test_parsers.py +++ b/terraso_backend/tests/core/gis/test_parsers.py @@ -21,20 +21,105 @@ import geopandas as gpd import pytest -from apps.core.gis.parsers import parse_kml_file, parse_shapefile +from apps.core.gis.parsers import parse_file_to_geojson from apps.core.gis.utils import DEFAULT_CRS +KML_CONTENT = """ + + + + Portland + + -122.681944,45.52,0 + + + + Rio de Janeiro + + -43.196389,-22.908333,0 + + + + Istanbul + + 28.976018,41.01224,0 + + + + Reykjavik + + -21.933333,64.133333,0 + + + + Simple Polygon + + + + -122.681944,45.52,0 + -43.196389,-22.908333,0 + 28.976018,41.01224,0 + -21.933333,64.133333,0 + -122.681944,45.52,0 + + + + + + """ + +KML_GEOJSON = { + "type": "FeatureCollection", + "features": [ + { + "id": "0", + "type": "Feature", + "properties": {"Name": "Portland", "Description": ""}, + "geometry": {"type": "Point", "coordinates": [-122.681944, 45.52, 0.0]}, + }, + { + "id": "1", + "type": "Feature", + "properties": {"Name": "Rio de Janeiro", "Description": ""}, + "geometry": {"type": "Point", "coordinates": [-43.196389, -22.908333, 0.0]}, + }, + { + "id": "2", + "type": "Feature", + "properties": {"Name": "Istanbul", "Description": ""}, + "geometry": {"type": "Point", "coordinates": [28.976018, 41.01224, 0.0]}, + }, + { + "id": "3", + "type": "Feature", + "properties": {"Name": "Reykjavik", "Description": ""}, + "geometry": {"type": "Point", "coordinates": [-21.933333, 64.133333, 0.0]}, + }, + { + "id": "4", + "type": "Feature", + "properties": {"Name": "Simple Polygon", "Description": ""}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-122.681944, 45.52, 0.0], + [-43.196389, -22.908333, 0.0], + [28.976018, 41.01224, 0.0], + [-21.933333, 64.133333, 0.0], + [-122.681944, 45.52, 0.0], + ] + ], + }, + }, + ], +} + @pytest.fixture def shapefile_zip(request): shp, shx, prj = request.param zip_file = tempfile.NamedTemporaryFile(suffix=".zip") - - with zipfile.ZipFile(zip_file.name, "w") as zf: - zf.writestr("test.shp", shp) - zf.writestr("test.shx", shx) - zf.writestr("test.prj", prj) - return zip_file @@ -60,11 +145,12 @@ def test_parse_shapefile(shapefile_zip): for component in ["shp", "shx", "prj"]: zf.write(os.path.join(tmpdir, f"test.{component}"), f"test.{component}") - # Parse the Shapefile - shapefile_json = parse_shapefile(shapefile_zip.name) + with open(shapefile_zip.name, "rb") as file: + shapefile_json = parse_file_to_geojson(file) - # Verify that the parsed Shapefile is equivalent to the original GeoDataFrame - assert shapefile_json == json.loads(gdf.to_json()) + # Verify that the parsed Shapefile is equivalent to the original GeoDataFrame + gdf_json = json.loads(gdf.to_json()) + assert shapefile_json == gdf_json @pytest.fixture @@ -85,103 +171,13 @@ def kml_file(request): @pytest.mark.parametrize( "kml_file", [ - ( - """ - - - - Portland - - -122.681944,45.52,0 - - - - Rio de Janeiro - - -43.196389,-22.908333,0 - - - - Istanbul - - 28.976018,41.01224,0 - - - - Reykjavik - - -21.933333,64.133333,0 - - - - Simple Polygon - - - - -122.681944,45.52,0 - -43.196389,-22.908333,0 - 28.976018,41.01224,0 - -21.933333,64.133333,0 - -122.681944,45.52,0 - - - - - - """, - "kml", - ), + (KML_CONTENT, "kml"), ], indirect=True, ) def test_parse_kml_file(kml_file): - # Call the parse_kml_file function with the file path - kml_json = parse_kml_file(kml_file) + with open(kml_file, "rb") as file: + kml_json = parse_file_to_geojson(file) # Assert that the output of the parse_kml_file function is as expected - assert kml_json == { - "type": "FeatureCollection", - "features": [ - { - "id": "0", - "type": "Feature", - "properties": {"Name": "Portland", "Description": ""}, - "geometry": {"type": "Point", "coordinates": [-122.681944, 45.52, 0.0]}, - }, - { - "id": "1", - "type": "Feature", - "properties": {"Name": "Rio de Janeiro", "Description": ""}, - "geometry": {"type": "Point", "coordinates": [-43.196389, -22.908333, 0.0]}, - }, - { - "id": "2", - "type": "Feature", - "properties": {"Name": "Istanbul", "Description": ""}, - "geometry": {"type": "Point", "coordinates": [28.976018, 41.01224, 0.0]}, - }, - { - "id": "3", - "type": "Feature", - "properties": {"Name": "Reykjavik", "Description": ""}, - "geometry": {"type": "Point", "coordinates": [-21.933333, 64.133333, 0.0]}, - }, - { - "id": "4", - "type": "Feature", - "properties": {"Name": "Simple Polygon", "Description": ""}, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [-122.681944, 45.52, 0.0], - [-43.196389, -22.908333, 0.0], - [28.976018, 41.01224, 0.0], - [-21.933333, 64.133333, 0.0], - [-122.681944, 45.52, 0.0], - ] - ], - }, - }, - ], - } + assert kml_json == KML_GEOJSON diff --git a/terraso_backend/tests/graphql/conftest.py b/terraso_backend/tests/graphql/conftest.py index e6db1caf2..02478a8a5 100644 --- a/terraso_backend/tests/graphql/conftest.py +++ b/terraso_backend/tests/graphql/conftest.py @@ -318,6 +318,36 @@ def data_entries(group_data_entries, landscape_data_entries): return group_data_entries + landscape_data_entries +@pytest.fixture +def data_entry_kml(users, groups): + creator = users[0] + creator_group = groups[0] + creator_group.members.add(creator) + return mixer.blend( + DataEntry, + created_by=creator, + size=100, + groups=creator_group, + entry_type=DataEntry.ENTRY_TYPE_FILE, + resource_type="kml", + ) + + +@pytest.fixture +def data_entry_shapefile(users, groups): + creator = users[0] + creator_group = groups[0] + creator_group.members.add(creator) + return mixer.blend( + DataEntry, + created_by=creator, + size=100, + groups=creator_group, + entry_type=DataEntry.ENTRY_TYPE_FILE, + resource_type="zip", + ) + + @pytest.fixture def visualization_config_current_user(users, data_entry_current_user_file, groups): creator = users[0] diff --git a/terraso_backend/tests/graphql/test_shared_data.py b/terraso_backend/tests/graphql/test_shared_data.py index 75e5b42e8..73223ec5b 100644 --- a/terraso_backend/tests/graphql/test_shared_data.py +++ b/terraso_backend/tests/graphql/test_shared_data.py @@ -13,8 +13,19 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see https://www.gnu.org/licenses/. +import json +import os +import tempfile +import zipfile +from unittest import mock + +import geopandas as gpd import pytest +from apps.core.gis.utils import DEFAULT_CRS + +from ..core.gis.test_parsers import KML_CONTENT, KML_GEOJSON + pytestmark = pytest.mark.django_db @@ -289,3 +300,112 @@ def test_data_entries_from_parent_query_by_resource_field(client_query, data_ent for data_entry in data_entries: assert data_entry.name in entries_result + + +@pytest.fixture +def kml_file(request): + kml_contents, file_extension = request.param + # Create a temporary file + with tempfile.NamedTemporaryFile(mode="w", suffix=f".{file_extension}", delete=False) as f: + # Write the KML content to the file + f.write(kml_contents) + + # Return the file path + yield f.name + + # Clean up: delete the temporary file + os.unlink(f.name) + + +@pytest.mark.parametrize( + "kml_file", + [ + ( + KML_CONTENT, + "kml", + ), + ], + indirect=True, +) +@mock.patch("apps.shared_data.services.data_entry_upload_service.get_file") +def test_data_entry_kml_to_geojson(get_file_mock, client_query, data_entry_kml, kml_file): + with open(kml_file, "rb") as file: + get_file_mock.return_value = file + response = client_query( + """ + {dataEntry(id: "%s") { + id + name + geojson + }} + """ + % data_entry_kml.id + ) + json_response = response.json() + data_entry_result = json_response["data"]["dataEntry"] + + assert data_entry_result["id"] == str(data_entry_kml.id) + assert data_entry_result["name"] == data_entry_kml.name + assert data_entry_result["geojson"] == json.dumps(KML_GEOJSON) + + +@mock.patch("apps.shared_data.services.data_entry_upload_service.get_file") +def test_data_entry_shapefil_to_geojson(get_file_mock, client_query, data_entry_shapefile): + gdf = gpd.GeoDataFrame({"geometry": gpd.points_from_xy([0], [0])}, crs=DEFAULT_CRS) + with tempfile.TemporaryDirectory() as tmpdir: + shapefile_zip = tempfile.NamedTemporaryFile(suffix=".zip") + shapefile_path = os.path.join(tmpdir, "test.shp") + gdf.to_file(shapefile_path) + + with zipfile.ZipFile(shapefile_zip.name, "w") as zf: + for component in ["shp", "shx", "prj"]: + zf.write(os.path.join(tmpdir, f"test.{component}"), f"test.{component}") + + with open(shapefile_zip.name, "rb") as file: + get_file_mock.return_value = file + response = client_query( + """ + {dataEntry(id: "%s") { + id + name + geojson + }} + """ + % data_entry_shapefile.id + ) + json_response = response.json() + data_entry_result = json_response["data"]["dataEntry"] + + assert data_entry_result["id"] == str(data_entry_shapefile.id) + assert data_entry_result["name"] == data_entry_shapefile.name + assert json.loads(data_entry_result["geojson"]) == { + "type": "FeatureCollection", + "features": [ + { + "id": "0", + "type": "Feature", + "properties": {}, + "geometry": {"type": "Point", "coordinates": [0.0, 0.0]}, + } + ], + "crs": {"type": "name", "properties": {"name": "urn:ogc:def:crs:OGC::CRS84"}}, + } + + +@mock.patch("apps.shared_data.services.data_entry_upload_service.get_file") +def test_data_entry_avoid_fetching_file_for_not_gis_file(get_file_mock, client_query, data_entries): + response = client_query( + """ + {dataEntry(id: "%s") { + id + name + geojson + }} + """ + % data_entries[0].id + ) + json_response = response.json() + data_entry_result = json_response["data"]["dataEntry"] + + get_file_mock.assert_not_called() + assert data_entry_result["geojson"] is None diff --git a/terraso_backend/tests/graphql/test_visualization_config.py b/terraso_backend/tests/graphql/test_visualization_config.py index 8612223e3..d03cbc317 100644 --- a/terraso_backend/tests/graphql/test_visualization_config.py +++ b/terraso_backend/tests/graphql/test_visualization_config.py @@ -170,6 +170,8 @@ def test_visualization_configs_returns_only_for_users_groups( edges { node { id + title + description } } }} @@ -181,3 +183,5 @@ def test_visualization_configs_returns_only_for_users_groups( assert len(entries_result) == 1 assert entries_result[0] == str(visualization_config_current_user.id) + assert edges[0]["node"]["title"] == visualization_config_current_user.title + assert edges[0]["node"]["description"] == visualization_config_current_user.description diff --git a/terraso_backend/tests/shared_data/conftest.py b/terraso_backend/tests/shared_data/conftest.py index 407daf294..910409234 100644 --- a/terraso_backend/tests/shared_data/conftest.py +++ b/terraso_backend/tests/shared_data/conftest.py @@ -85,3 +85,19 @@ def visualization_config_b(user_b, data_entry): data_entry=data_entry, created_by=user_b, ) + + +@pytest.fixture +def visualization_config_kml(user): + return mixer.blend( + VisualizationConfig, + size=1, + data_entry=mixer.blend( + DataEntry, + size=1, + url=f"{settings.DATA_ENTRY_FILE_BASE_URL}/{user.id}/test_data.kml", + created_by=user, + resource_type="kml", + ), + created_by=user, + ) diff --git a/terraso_backend/tests/shared_data/test_visualization_tileset_tasks.py b/terraso_backend/tests/shared_data/test_visualization_tileset_tasks.py index d5fca3c25..299350be4 100644 --- a/terraso_backend/tests/shared_data/test_visualization_tileset_tasks.py +++ b/terraso_backend/tests/shared_data/test_visualization_tileset_tasks.py @@ -14,17 +14,23 @@ # along with this program. If not, see https://www.gnu.org/licenses/. import io +import json +import os +import tempfile from unittest.mock import patch import pytest import requests +from apps.core.gis.mapbox import get_line_delimited_geojson from apps.shared_data.models import VisualizationConfig from apps.shared_data.visualization_tileset_tasks import ( create_mapbox_tileset, remove_mapbox_tileset, ) +from ..core.gis.test_parsers import KML_CONTENT, KML_GEOJSON + pytestmark = pytest.mark.django_db @@ -37,7 +43,9 @@ def create_mock_response(response): @patch("apps.shared_data.visualization_tileset_tasks.data_entry_upload_service.get_file") @patch("apps.core.gis.mapbox.requests.post") -def test_create_mapbox_tileset_success(mock_request_post, mock_get_file, visualization_config): +def test_create_mapbox_tileset_dataset_success( + mock_request_post, mock_get_file, visualization_config +): visualization_config.configuration = { "datasetConfig": { "longitude": "lng", @@ -53,7 +61,9 @@ def test_create_mapbox_tileset_success(mock_request_post, mock_get_file, visuali }, } visualization_config.save() - mock_get_file.return_value = io.StringIO("lat,lng,col1\nval1,val2,val3") + mock_get_file.return_value = io.StringIO( + "lat,lng,col1\n-78.48306234911033,-0.1805502450716432,val3" + ) mock_responses = [ {"status_code": 200, "json_data": {"id": "tileset-id-1"}}, {"status_code": 200, "json_data": {}}, @@ -65,6 +75,63 @@ def test_create_mapbox_tileset_success(mock_request_post, mock_get_file, visuali assert updated_visualization_config.mapbox_tileset_id is not None assert mock_request_post.call_count == 3 + assert json.loads(mock_request_post.call_args_list[0][1]["files"][0][1][1]) == { + "type": "Feature", + "geometry": {"type": "Point", "coordinates": [-0.1805502450716432, -78.48306234911033]}, + "properties": { + "title": None, + "fields": '[{"label": "label", "value": "val3"}]', + }, + } + + assert ( + mock_request_post.call_args_list[1][1]["json"]["name"] + == f"development - {visualization_config.title}"[:64] + ) + + +@pytest.fixture +def kml_file(): + kml_contents = KML_CONTENT + file_extension = "kml" + with tempfile.NamedTemporaryFile(mode="w", suffix=f".{file_extension}", delete=False) as f: + f.write(kml_contents) + + yield f.name + + os.unlink(f.name) + + +@patch("apps.shared_data.services.data_entry_upload_service.get_file") +@patch("apps.core.gis.mapbox.requests.post") +def test_create_mapbox_tileset_gis_dataentry_success( + mock_request_post, mock_get_file, visualization_config_kml, kml_file +): + with open(kml_file, "rb") as file: + mock_get_file.return_value = file + mock_responses = [ + {"status_code": 200, "json_data": {"id": "tileset-id-1"}}, + {"status_code": 200, "json_data": {}}, + {"status_code": 200, "json_data": {}}, + ] + mock_request_post.side_effect = [ + create_mock_response(response) for response in mock_responses + ] + create_mapbox_tileset(visualization_config_kml.id) + + updated_visualization_config = VisualizationConfig.objects.get(id=visualization_config_kml.id) + assert updated_visualization_config.mapbox_tileset_id is not None + assert mock_request_post.call_count == 3 + + assert mock_request_post.call_args_list[0][1]["files"][0][1][1] == get_line_delimited_geojson( + KML_GEOJSON + ) + + assert ( + mock_request_post.call_args_list[1][1]["json"]["name"] + == f"development - {visualization_config_kml.title}"[:64] + ) + @patch("apps.shared_data.visualization_tileset_tasks.data_entry_upload_service.get_file") @patch("apps.core.gis.mapbox.requests.post") From 00f57d67680a17b3e08fad32b3ec065231d0b085 Mon Sep 17 00:00:00 2001 From: Jose Buitron Date: Wed, 8 Nov 2023 14:35:22 -0500 Subject: [PATCH 10/13] fix: Optimized data entries query --- .../apps/graphql/schema/__init__.py | 3 -- .../apps/graphql/schema/schema.graphql | 44 +++++++++---------- .../apps/graphql/schema/shared_resources.py | 4 +- .../graphql/schema/shared_resources_mixin.py | 21 ++++++++- .../graphql/schema/visualization_config.py | 16 +------ .../apps/shared_data/models/data_entries.py | 5 ++- .../tests/graphql/test_shared_data.py | 37 +++++++++++++++- .../tests/shared_data/test_views.py | 1 - 8 files changed, 83 insertions(+), 48 deletions(-) diff --git a/terraso_backend/apps/graphql/schema/__init__.py b/terraso_backend/apps/graphql/schema/__init__.py index 1186fc8ad..0dc2c1141 100644 --- a/terraso_backend/apps/graphql/schema/__init__.py +++ b/terraso_backend/apps/graphql/schema/__init__.py @@ -107,7 +107,6 @@ from .visualization_config import ( VisualizationConfigAddMutation, VisualizationConfigDeleteMutation, - VisualizationConfigNode, VisualizationConfigUpdateMutation, ) @@ -129,8 +128,6 @@ class Query(graphene.ObjectType): group_associations = DjangoFilterConnectionField(GroupAssociationNode) data_entry = TerrasoRelayNode.Field(DataEntryNode) data_entries = DjangoFilterConnectionField(DataEntryNode) - visualization_config = TerrasoRelayNode.Field(VisualizationConfigNode) - visualization_configs = DjangoFilterConnectionField(VisualizationConfigNode) taxonomy_term = TerrasoRelayNode.Field(TaxonomyTermNode) taxonomy_terms = DjangoFilterConnectionField(TaxonomyTermNode) story_map = TerrasoRelayNode.Field(StoryMapNode) diff --git a/terraso_backend/apps/graphql/schema/schema.graphql b/terraso_backend/apps/graphql/schema/schema.graphql index 5402a63f8..c45bd3b09 100644 --- a/terraso_backend/apps/graphql/schema/schema.graphql +++ b/terraso_backend/apps/graphql/schema/schema.graphql @@ -39,11 +39,6 @@ type Query { id: ID! ): DataEntryNode! dataEntries(offset: Int, before: String, after: String, first: Int, last: Int, name_Icontains: String, description_Icontains: String, url_Icontains: String, entryType_In: [SharedDataDataEntryEntryTypeChoices], resourceType_In: [String], sharedResources_TargetObjectId: UUID, sharedResources_Target_Slug: String, sharedResources_TargetContentType: String): DataEntryNodeConnection - visualizationConfig( - """The ID of the object""" - id: ID! - ): VisualizationConfigNode! - visualizationConfigs(offset: Int, before: String, after: String, first: Int, last: Int, slug: String, slug_Icontains: String, dataEntry_SharedResources_TargetObjectId: UUID, dataEntry_SharedResources_Target_Slug: String, dataEntry_SharedResources_TargetContentType: String): VisualizationConfigNodeConnection taxonomyTerm( """The ID of the object""" id: ID! @@ -110,6 +105,7 @@ type GroupNode implements Node { associatedLandscapes(offset: Int, before: String, after: String, first: Int, last: Int, landscape: ID, landscape_Slug_Icontains: String, group: ID, group_Slug_Icontains: String, isDefaultLandscapeGroup: Boolean, isPartnership: Boolean): LandscapeGroupNodeConnection! id: ID! sharedResources(offset: Int, before: String, after: String, first: Int, last: Int, source_DataEntry_ResourceType_In: [String]): SharedResourceNodeConnection + dataEntries(offset: Int, before: String, after: String, first: Int, last: Int, name_Icontains: String, description_Icontains: String, url_Icontains: String, entryType_In: [SharedDataDataEntryEntryTypeChoices], resourceType_In: [String], sharedResources_TargetObjectId: UUID, sharedResources_Target_Slug: String, sharedResources_TargetContentType: String): DataEntryNodeConnection accountMembership: MembershipNode membershipsCount: Int } @@ -296,6 +292,7 @@ type LandscapeNode implements Node { associatedGroups(offset: Int, before: String, after: String, first: Int, last: Int, landscape: ID, landscape_Slug_Icontains: String, group: ID, group_Slug_Icontains: String, isDefaultLandscapeGroup: Boolean, isPartnership: Boolean): LandscapeGroupNodeConnection! id: ID! sharedResources(offset: Int, before: String, after: String, first: Int, last: Int, source_DataEntry_ResourceType_In: [String]): SharedResourceNodeConnection + dataEntries(offset: Int, before: String, after: String, first: Int, last: Int, name_Icontains: String, description_Icontains: String, url_Icontains: String, entryType_In: [SharedDataDataEntryEntryTypeChoices], resourceType_In: [String], sharedResources_TargetObjectId: UUID, sharedResources_Target_Slug: String, sharedResources_TargetContentType: String): DataEntryNodeConnection areaTypes: [String] defaultGroup: GroupNode areaScalarHa: Float @@ -465,6 +462,7 @@ type DataEntryNode implements Node { visualizations(offset: Int, before: String, after: String, first: Int, last: Int, slug: String, slug_Icontains: String, dataEntry_SharedResources_TargetObjectId: UUID, dataEntry_SharedResources_Target_Slug: String, dataEntry_SharedResources_TargetContentType: String): VisualizationConfigNodeConnection! id: ID! sharedResources(offset: Int, before: String, after: String, first: Int, last: Int, source_DataEntry_ResourceType_In: [String]): SharedResourceNodeConnection + dataEntries(offset: Int, before: String, after: String, first: Int, last: Int, name_Icontains: String, description_Icontains: String, url_Icontains: String, entryType_In: [SharedDataDataEntryEntryTypeChoices], resourceType_In: [String], sharedResources_TargetObjectId: UUID, sharedResources_Target_Slug: String, sharedResources_TargetContentType: String): DataEntryNodeConnection geojson: JSONString } @@ -508,6 +506,24 @@ in fields, resolvers and input. """ scalar UUID +type DataEntryNodeConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [DataEntryNodeEdge!]! + totalCount: Int! +} + +"""A Relay edge containing a `DataEntryNode` and its cursor.""" +type DataEntryNodeEdge { + """The item at the end of the edge""" + node: DataEntryNode! + + """A cursor for use in pagination""" + cursor: String! +} + union OwnerNode = GroupNode | LandscapeNode union TargetNode = GroupNode | LandscapeNode @@ -566,24 +582,6 @@ type UserNodeEdge { cursor: String! } -type DataEntryNodeConnection { - """Pagination data for this connection.""" - pageInfo: PageInfo! - - """Contains the nodes in this connection.""" - edges: [DataEntryNodeEdge!]! - totalCount: Int! -} - -"""A Relay edge containing a `DataEntryNode` and its cursor.""" -type DataEntryNodeEdge { - """The item at the end of the edge""" - node: DataEntryNode! - - """A cursor for use in pagination""" - cursor: String! -} - type StoryMapNode implements Node { id: ID! createdAt: DateTime! diff --git a/terraso_backend/apps/graphql/schema/shared_resources.py b/terraso_backend/apps/graphql/schema/shared_resources.py index 844b41273..b13ecd65d 100644 --- a/terraso_backend/apps/graphql/schema/shared_resources.py +++ b/terraso_backend/apps/graphql/schema/shared_resources.py @@ -19,8 +19,10 @@ from apps.core.models import SharedResource -from . import DataEntryNode, GroupNode, LandscapeNode, VisualizationConfigNode +from . import GroupNode, LandscapeNode from .commons import TerrasoConnection +from .data_entries import DataEntryNode +from .visualization_config import VisualizationConfigNode class SourceNode(graphene.Union): diff --git a/terraso_backend/apps/graphql/schema/shared_resources_mixin.py b/terraso_backend/apps/graphql/schema/shared_resources_mixin.py index b989b5bed..d1d53c96a 100644 --- a/terraso_backend/apps/graphql/schema/shared_resources_mixin.py +++ b/terraso_backend/apps/graphql/schema/shared_resources_mixin.py @@ -14,10 +14,11 @@ # along with this program. If not, see https://www.gnu.org/licenses/. import django_filters +from django.db.models import Prefetch from graphene_django.filter import DjangoFilterConnectionField from apps.core.models import SharedResource -from apps.shared_data.models import DataEntry +from apps.shared_data.models import DataEntry, VisualizationConfig class MultipleChoiceField(django_filters.fields.MultipleChoiceField): @@ -49,6 +50,22 @@ class SharedResourcesMixin: "apps.graphql.schema.shared_resources.SharedResourceNode", filterset_class=SharedResourceFilterSet, ) + data_entries = DjangoFilterConnectionField( + "apps.graphql.schema.data_entries.DataEntryNode", + ) def resolve_shared_resources(self, info, **kwargs): - return self.shared_resources + return self.shared_resources.prefetch_related( + "source", + ) + + def resolve_data_entries(self, info, **kwargs): + return DataEntry.objects.prefetch_related( + Prefetch( + "visualizations", + queryset=VisualizationConfig.objects.defer("configuration") + .prefetch_related("created_by") + .filter(data_entry__shared_resources__target_object_id=self.pk), + ), + "created_by", + ).filter(shared_resources__target_object_id=self.pk) diff --git a/terraso_backend/apps/graphql/schema/visualization_config.py b/terraso_backend/apps/graphql/schema/visualization_config.py index 6dd0fc0a9..f06e37125 100644 --- a/terraso_backend/apps/graphql/schema/visualization_config.py +++ b/terraso_backend/apps/graphql/schema/visualization_config.py @@ -23,7 +23,7 @@ from graphene_django import DjangoObjectType from apps.core.gis.mapbox import get_publish_status -from apps.core.models import Group, Landscape, Membership +from apps.core.models import Group, Landscape from apps.graphql.exceptions import GraphQLNotAllowedException from apps.shared_data.models.data_entries import DataEntry from apps.shared_data.models.visualization_config import VisualizationConfig @@ -99,20 +99,6 @@ class Meta: filterset_class = VisualizationConfigFilterSet connection_class = TerrasoConnection - @classmethod - def get_queryset(cls, queryset, info): - user_pk = getattr(info.context.user, "pk", False) - user_groups_ids = Membership.objects.filter( - user__id=user_pk, membership_status=Membership.APPROVED - ).values_list("group", flat=True) - user_landscape_ids = Landscape.objects.filter( - associated_groups__group__memberships__user__id=user_pk, - associated_groups__group__memberships__membership_status=Membership.APPROVED, - associated_groups__is_default_landscape_group=True, - ).values_list("id", flat=True) - all_ids = list(user_groups_ids) + list(user_landscape_ids) - return queryset.filter(data_entry__shared_resources__target_object_id__in=all_ids) - def resolve_mapbox_tileset_id(self, info): if self.mapbox_tileset_id is None: return None diff --git a/terraso_backend/apps/shared_data/models/data_entries.py b/terraso_backend/apps/shared_data/models/data_entries.py index 91811755b..3d63660d1 100644 --- a/terraso_backend/apps/shared_data/models/data_entries.py +++ b/terraso_backend/apps/shared_data/models/data_entries.py @@ -25,6 +25,8 @@ VALID_TARGET_TYPES = ["group", "landscape"] +data_entry_file_storage = DataEntryFileStorage(custom_domain=None) + class DataEntry(BaseModel): """ @@ -98,8 +100,7 @@ def s3_object_name(self): @property def signed_url(self): - storage = DataEntryFileStorage(custom_domain=None) - return storage.url(self.s3_object_name) + return data_entry_file_storage.url(self.s3_object_name) def delete_file_on_storage(self): if not self.deleted_at: diff --git a/terraso_backend/tests/graphql/test_shared_data.py b/terraso_backend/tests/graphql/test_shared_data.py index 73223ec5b..d2586a3a4 100644 --- a/terraso_backend/tests/graphql/test_shared_data.py +++ b/terraso_backend/tests/graphql/test_shared_data.py @@ -268,7 +268,9 @@ def test_data_entries_from_parent_query(client_query, data_entries_by_parent): @pytest.mark.parametrize("data_entries_by_parent", ["groups", "landscapes"], indirect=True) -def test_data_entries_from_parent_query_by_resource_field(client_query, data_entries_by_parent): +def test_data_entries_from_parent_query_by_resource_field_trough_shared_resources( + client_query, data_entries_by_parent +): (parent, data_entries) = data_entries_by_parent response = client_query( """ @@ -302,6 +304,39 @@ def test_data_entries_from_parent_query_by_resource_field(client_query, data_ent assert data_entry.name in entries_result +@pytest.mark.parametrize("data_entries_by_parent", ["groups", "landscapes"], indirect=True) +def test_data_entries_from_parent_query_by_resource_field_trough_data_entries( + client_query, data_entries_by_parent +): + (parent, data_entries) = data_entries_by_parent + response = client_query( + """ + {%s { + edges { + node { + dataEntries(resourceType_In: ["csv", "xls"]) { + edges { + node { + name + } + } + } + } + } + }} + """ + % parent + ) + + json_response = response.json() + + resources = json_response["data"][parent]["edges"][0]["node"]["dataEntries"]["edges"] + entries_result = [resource["node"]["name"] for resource in resources] + + for data_entry in data_entries: + assert data_entry.name in entries_result + + @pytest.fixture def kml_file(request): kml_contents, file_extension = request.param diff --git a/terraso_backend/tests/shared_data/test_views.py b/terraso_backend/tests/shared_data/test_views.py index 779baf03c..b3f2f9b1d 100644 --- a/terraso_backend/tests/shared_data/test_views.py +++ b/terraso_backend/tests/shared_data/test_views.py @@ -76,7 +76,6 @@ def test_create_data_entry_successfully( response = logged_client.post(upload_url, data_entry_payload) response_data = response.json() - print(response_data) assert response.status_code == 201 mocked_upload_service.assert_called_once() From 4304444ce81c561ad1690c1681c43c2760dda060 Mon Sep 17 00:00:00 2001 From: Jose Buitron Date: Wed, 8 Nov 2023 16:46:38 -0500 Subject: [PATCH 11/13] fix: Removed not needed separate data entries field --- .../apps/graphql/schema/__init__.py | 3 ++ .../apps/graphql/schema/data_entries.py | 44 +++++++++++-------- .../apps/graphql/schema/schema.graphql | 44 ++++++++++--------- .../graphql/schema/shared_resources_mixin.py | 17 +------ .../graphql/schema/visualization_config.py | 28 +++++++++++- .../tests/graphql/test_shared_data.py | 37 +--------------- .../graphql/test_visualization_config.py | 5 ++- 7 files changed, 82 insertions(+), 96 deletions(-) diff --git a/terraso_backend/apps/graphql/schema/__init__.py b/terraso_backend/apps/graphql/schema/__init__.py index 0dc2c1141..1186fc8ad 100644 --- a/terraso_backend/apps/graphql/schema/__init__.py +++ b/terraso_backend/apps/graphql/schema/__init__.py @@ -107,6 +107,7 @@ from .visualization_config import ( VisualizationConfigAddMutation, VisualizationConfigDeleteMutation, + VisualizationConfigNode, VisualizationConfigUpdateMutation, ) @@ -128,6 +129,8 @@ class Query(graphene.ObjectType): group_associations = DjangoFilterConnectionField(GroupAssociationNode) data_entry = TerrasoRelayNode.Field(DataEntryNode) data_entries = DjangoFilterConnectionField(DataEntryNode) + visualization_config = TerrasoRelayNode.Field(VisualizationConfigNode) + visualization_configs = DjangoFilterConnectionField(VisualizationConfigNode) taxonomy_term = TerrasoRelayNode.Field(TaxonomyTermNode) taxonomy_terms = DjangoFilterConnectionField(TaxonomyTermNode) story_map = TerrasoRelayNode.Field(StoryMapNode) diff --git a/terraso_backend/apps/graphql/schema/data_entries.py b/terraso_backend/apps/graphql/schema/data_entries.py index 783fbf599..a4add33b3 100644 --- a/terraso_backend/apps/graphql/schema/data_entries.py +++ b/terraso_backend/apps/graphql/schema/data_entries.py @@ -21,14 +21,14 @@ from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError from django.db import transaction -from django.db.models import Q +from django.db.models import Prefetch, Q, Subquery from graphene import relay from graphene_django import DjangoObjectType from apps.core.gis.parsers import parse_file_to_geojson from apps.core.models import Group, Landscape, Membership from apps.graphql.exceptions import GraphQLNotAllowedException, GraphQLNotFoundException -from apps.shared_data.models import DataEntry +from apps.shared_data.models import DataEntry, VisualizationConfig from apps.shared_data.models.data_entries import VALID_TARGET_TYPES from apps.shared_data.services import data_entry_upload_service @@ -97,24 +97,30 @@ class Meta: @classmethod def get_queryset(cls, queryset, info): user_pk = getattr(info.context.user, "pk", False) - user_groups_ids = Membership.objects.filter( - user__id=user_pk, membership_status=Membership.APPROVED - ).values_list("group", flat=True) - user_landscape_ids = Landscape.objects.filter( - associated_groups__group__memberships__user__id=user_pk, - associated_groups__group__memberships__membership_status=Membership.APPROVED, - associated_groups__is_default_landscape_group=True, - ).values_list("id", flat=True) + user_groups_ids = Subquery( + Group.objects.filter( + memberships__user__id=user_pk, memberships__membership_status=Membership.APPROVED + ).values("id") + ) + user_landscape_ids = Subquery( + Landscape.objects.filter( + associated_groups__group__memberships__user__id=user_pk, + associated_groups__group__memberships__membership_status=Membership.APPROVED, + associated_groups__is_default_landscape_group=True, + ).values("id") + ) - return queryset.filter( - Q( - shared_resources__target_content_type=ContentType.objects.get_for_model(Group), - shared_resources__target_object_id__in=user_groups_ids, - ) - | Q( - shared_resources__target_content_type=ContentType.objects.get_for_model(Landscape), - shared_resources__target_object_id__in=user_landscape_ids, - ) + return queryset.prefetch_related( + Prefetch( + "visualizations", + queryset=VisualizationConfig.objects.defer("configuration").prefetch_related( + "created_by" + ), + ), + "created_by", + ).filter( + Q(shared_resources__target_object_id__in=user_groups_ids) + | Q(shared_resources__target_object_id__in=user_landscape_ids) ) def resolve_url(self, info): diff --git a/terraso_backend/apps/graphql/schema/schema.graphql b/terraso_backend/apps/graphql/schema/schema.graphql index c45bd3b09..5402a63f8 100644 --- a/terraso_backend/apps/graphql/schema/schema.graphql +++ b/terraso_backend/apps/graphql/schema/schema.graphql @@ -39,6 +39,11 @@ type Query { id: ID! ): DataEntryNode! dataEntries(offset: Int, before: String, after: String, first: Int, last: Int, name_Icontains: String, description_Icontains: String, url_Icontains: String, entryType_In: [SharedDataDataEntryEntryTypeChoices], resourceType_In: [String], sharedResources_TargetObjectId: UUID, sharedResources_Target_Slug: String, sharedResources_TargetContentType: String): DataEntryNodeConnection + visualizationConfig( + """The ID of the object""" + id: ID! + ): VisualizationConfigNode! + visualizationConfigs(offset: Int, before: String, after: String, first: Int, last: Int, slug: String, slug_Icontains: String, dataEntry_SharedResources_TargetObjectId: UUID, dataEntry_SharedResources_Target_Slug: String, dataEntry_SharedResources_TargetContentType: String): VisualizationConfigNodeConnection taxonomyTerm( """The ID of the object""" id: ID! @@ -105,7 +110,6 @@ type GroupNode implements Node { associatedLandscapes(offset: Int, before: String, after: String, first: Int, last: Int, landscape: ID, landscape_Slug_Icontains: String, group: ID, group_Slug_Icontains: String, isDefaultLandscapeGroup: Boolean, isPartnership: Boolean): LandscapeGroupNodeConnection! id: ID! sharedResources(offset: Int, before: String, after: String, first: Int, last: Int, source_DataEntry_ResourceType_In: [String]): SharedResourceNodeConnection - dataEntries(offset: Int, before: String, after: String, first: Int, last: Int, name_Icontains: String, description_Icontains: String, url_Icontains: String, entryType_In: [SharedDataDataEntryEntryTypeChoices], resourceType_In: [String], sharedResources_TargetObjectId: UUID, sharedResources_Target_Slug: String, sharedResources_TargetContentType: String): DataEntryNodeConnection accountMembership: MembershipNode membershipsCount: Int } @@ -292,7 +296,6 @@ type LandscapeNode implements Node { associatedGroups(offset: Int, before: String, after: String, first: Int, last: Int, landscape: ID, landscape_Slug_Icontains: String, group: ID, group_Slug_Icontains: String, isDefaultLandscapeGroup: Boolean, isPartnership: Boolean): LandscapeGroupNodeConnection! id: ID! sharedResources(offset: Int, before: String, after: String, first: Int, last: Int, source_DataEntry_ResourceType_In: [String]): SharedResourceNodeConnection - dataEntries(offset: Int, before: String, after: String, first: Int, last: Int, name_Icontains: String, description_Icontains: String, url_Icontains: String, entryType_In: [SharedDataDataEntryEntryTypeChoices], resourceType_In: [String], sharedResources_TargetObjectId: UUID, sharedResources_Target_Slug: String, sharedResources_TargetContentType: String): DataEntryNodeConnection areaTypes: [String] defaultGroup: GroupNode areaScalarHa: Float @@ -462,7 +465,6 @@ type DataEntryNode implements Node { visualizations(offset: Int, before: String, after: String, first: Int, last: Int, slug: String, slug_Icontains: String, dataEntry_SharedResources_TargetObjectId: UUID, dataEntry_SharedResources_Target_Slug: String, dataEntry_SharedResources_TargetContentType: String): VisualizationConfigNodeConnection! id: ID! sharedResources(offset: Int, before: String, after: String, first: Int, last: Int, source_DataEntry_ResourceType_In: [String]): SharedResourceNodeConnection - dataEntries(offset: Int, before: String, after: String, first: Int, last: Int, name_Icontains: String, description_Icontains: String, url_Icontains: String, entryType_In: [SharedDataDataEntryEntryTypeChoices], resourceType_In: [String], sharedResources_TargetObjectId: UUID, sharedResources_Target_Slug: String, sharedResources_TargetContentType: String): DataEntryNodeConnection geojson: JSONString } @@ -506,24 +508,6 @@ in fields, resolvers and input. """ scalar UUID -type DataEntryNodeConnection { - """Pagination data for this connection.""" - pageInfo: PageInfo! - - """Contains the nodes in this connection.""" - edges: [DataEntryNodeEdge!]! - totalCount: Int! -} - -"""A Relay edge containing a `DataEntryNode` and its cursor.""" -type DataEntryNodeEdge { - """The item at the end of the edge""" - node: DataEntryNode! - - """A cursor for use in pagination""" - cursor: String! -} - union OwnerNode = GroupNode | LandscapeNode union TargetNode = GroupNode | LandscapeNode @@ -582,6 +566,24 @@ type UserNodeEdge { cursor: String! } +type DataEntryNodeConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [DataEntryNodeEdge!]! + totalCount: Int! +} + +"""A Relay edge containing a `DataEntryNode` and its cursor.""" +type DataEntryNodeEdge { + """The item at the end of the edge""" + node: DataEntryNode! + + """A cursor for use in pagination""" + cursor: String! +} + type StoryMapNode implements Node { id: ID! createdAt: DateTime! diff --git a/terraso_backend/apps/graphql/schema/shared_resources_mixin.py b/terraso_backend/apps/graphql/schema/shared_resources_mixin.py index d1d53c96a..86dffe189 100644 --- a/terraso_backend/apps/graphql/schema/shared_resources_mixin.py +++ b/terraso_backend/apps/graphql/schema/shared_resources_mixin.py @@ -14,11 +14,10 @@ # along with this program. If not, see https://www.gnu.org/licenses/. import django_filters -from django.db.models import Prefetch from graphene_django.filter import DjangoFilterConnectionField from apps.core.models import SharedResource -from apps.shared_data.models import DataEntry, VisualizationConfig +from apps.shared_data.models import DataEntry class MultipleChoiceField(django_filters.fields.MultipleChoiceField): @@ -50,22 +49,8 @@ class SharedResourcesMixin: "apps.graphql.schema.shared_resources.SharedResourceNode", filterset_class=SharedResourceFilterSet, ) - data_entries = DjangoFilterConnectionField( - "apps.graphql.schema.data_entries.DataEntryNode", - ) def resolve_shared_resources(self, info, **kwargs): return self.shared_resources.prefetch_related( "source", ) - - def resolve_data_entries(self, info, **kwargs): - return DataEntry.objects.prefetch_related( - Prefetch( - "visualizations", - queryset=VisualizationConfig.objects.defer("configuration") - .prefetch_related("created_by") - .filter(data_entry__shared_resources__target_object_id=self.pk), - ), - "created_by", - ).filter(shared_resources__target_object_id=self.pk) diff --git a/terraso_backend/apps/graphql/schema/visualization_config.py b/terraso_backend/apps/graphql/schema/visualization_config.py index f06e37125..1635da93a 100644 --- a/terraso_backend/apps/graphql/schema/visualization_config.py +++ b/terraso_backend/apps/graphql/schema/visualization_config.py @@ -18,12 +18,12 @@ import structlog from django.contrib.contenttypes.models import ContentType from django.db import transaction -from django.db.models import Q +from django.db.models import Q, Subquery from graphene import relay from graphene_django import DjangoObjectType from apps.core.gis.mapbox import get_publish_status -from apps.core.models import Group, Landscape +from apps.core.models import Group, Landscape, Membership from apps.graphql.exceptions import GraphQLNotAllowedException from apps.shared_data.models.data_entries import DataEntry from apps.shared_data.models.visualization_config import VisualizationConfig @@ -112,6 +112,30 @@ def resolve_mapbox_tileset_id(self, info): self.save() return self.mapbox_tileset_id + @classmethod + def get_queryset(cls, queryset, info): + if info.field_name != "visualizationConfigs": + return queryset + + user_pk = getattr(info.context.user, "pk", False) + + user_groups_ids = Subquery( + Group.objects.filter( + memberships__user__id=user_pk, memberships__membership_status=Membership.APPROVED + ).values("id") + ) + user_landscape_ids = Subquery( + Landscape.objects.filter( + associated_groups__group__memberships__user__id=user_pk, + associated_groups__group__memberships__membership_status=Membership.APPROVED, + associated_groups__is_default_landscape_group=True, + ).values("id") + ) + return queryset.filter( + Q(data_entry__shared_resources__target_object_id__in=user_groups_ids) + | Q(data_entry__shared_resources__target_object_id__in=user_landscape_ids) + ) + class VisualizationConfigAddMutation(BaseWriteMutation): visualization_config = graphene.Field(VisualizationConfigNode) diff --git a/terraso_backend/tests/graphql/test_shared_data.py b/terraso_backend/tests/graphql/test_shared_data.py index d2586a3a4..73223ec5b 100644 --- a/terraso_backend/tests/graphql/test_shared_data.py +++ b/terraso_backend/tests/graphql/test_shared_data.py @@ -268,9 +268,7 @@ def test_data_entries_from_parent_query(client_query, data_entries_by_parent): @pytest.mark.parametrize("data_entries_by_parent", ["groups", "landscapes"], indirect=True) -def test_data_entries_from_parent_query_by_resource_field_trough_shared_resources( - client_query, data_entries_by_parent -): +def test_data_entries_from_parent_query_by_resource_field(client_query, data_entries_by_parent): (parent, data_entries) = data_entries_by_parent response = client_query( """ @@ -304,39 +302,6 @@ def test_data_entries_from_parent_query_by_resource_field_trough_shared_resource assert data_entry.name in entries_result -@pytest.mark.parametrize("data_entries_by_parent", ["groups", "landscapes"], indirect=True) -def test_data_entries_from_parent_query_by_resource_field_trough_data_entries( - client_query, data_entries_by_parent -): - (parent, data_entries) = data_entries_by_parent - response = client_query( - """ - {%s { - edges { - node { - dataEntries(resourceType_In: ["csv", "xls"]) { - edges { - node { - name - } - } - } - } - } - }} - """ - % parent - ) - - json_response = response.json() - - resources = json_response["data"][parent]["edges"][0]["node"]["dataEntries"]["edges"] - entries_result = [resource["node"]["name"] for resource in resources] - - for data_entry in data_entries: - assert data_entry.name in entries_result - - @pytest.fixture def kml_file(request): kml_contents, file_extension = request.param diff --git a/terraso_backend/tests/graphql/test_visualization_config.py b/terraso_backend/tests/graphql/test_visualization_config.py index d03cbc317..ebca9bd55 100644 --- a/terraso_backend/tests/graphql/test_visualization_config.py +++ b/terraso_backend/tests/graphql/test_visualization_config.py @@ -160,7 +160,7 @@ def test_visualization_configs_filter_by_group_id_filters_successfuly( def test_visualization_configs_returns_only_for_users_groups( - client_query, visualization_config_current_user + client_query, visualization_config_current_user, visualization_config_other_user ): # It's being done a request for all configurations, but only the configurations # from logged user's group is expected to return. @@ -178,7 +178,8 @@ def test_visualization_configs_returns_only_for_users_groups( """ ) - edges = response.json()["data"]["visualizationConfigs"]["edges"] + json_response = response.json() + edges = json_response["data"]["visualizationConfigs"]["edges"] entries_result = [edge["node"]["id"] for edge in edges] assert len(entries_result) == 1 From 1c8d33e77a79e4995e8524ca27d4e2ffc6260dfe Mon Sep 17 00:00:00 2001 From: Jose Buitron Date: Wed, 8 Nov 2023 16:49:56 -0500 Subject: [PATCH 12/13] fix: Moved queryset function --- .../graphql/schema/visualization_config.py | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/terraso_backend/apps/graphql/schema/visualization_config.py b/terraso_backend/apps/graphql/schema/visualization_config.py index 1635da93a..0aee523ff 100644 --- a/terraso_backend/apps/graphql/schema/visualization_config.py +++ b/terraso_backend/apps/graphql/schema/visualization_config.py @@ -99,19 +99,6 @@ class Meta: filterset_class = VisualizationConfigFilterSet connection_class = TerrasoConnection - def resolve_mapbox_tileset_id(self, info): - if self.mapbox_tileset_id is None: - return None - if self.mapbox_tileset_status == VisualizationConfig.MAPBOX_TILESET_READY: - return self.mapbox_tileset_id - - # Check if tileset ready to be published and update status - published = get_publish_status(self.mapbox_tileset_id) - if published: - self.mapbox_tileset_status = VisualizationConfig.MAPBOX_TILESET_READY - self.save() - return self.mapbox_tileset_id - @classmethod def get_queryset(cls, queryset, info): if info.field_name != "visualizationConfigs": @@ -136,6 +123,19 @@ def get_queryset(cls, queryset, info): | Q(data_entry__shared_resources__target_object_id__in=user_landscape_ids) ) + def resolve_mapbox_tileset_id(self, info): + if self.mapbox_tileset_id is None: + return None + if self.mapbox_tileset_status == VisualizationConfig.MAPBOX_TILESET_READY: + return self.mapbox_tileset_id + + # Check if tileset ready to be published and update status + published = get_publish_status(self.mapbox_tileset_id) + if published: + self.mapbox_tileset_status = VisualizationConfig.MAPBOX_TILESET_READY + self.save() + return self.mapbox_tileset_id + class VisualizationConfigAddMutation(BaseWriteMutation): visualization_config = graphene.Field(VisualizationConfigNode) From c0b4d9ba79fec9b94c553f53ad958dab453749f2 Mon Sep 17 00:00:00 2001 From: Jose Buitron Date: Thu, 9 Nov 2023 11:52:05 -0500 Subject: [PATCH 13/13] fix: Added comments explaining custom queryset --- terraso_backend/apps/graphql/schema/visualization_config.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/terraso_backend/apps/graphql/schema/visualization_config.py b/terraso_backend/apps/graphql/schema/visualization_config.py index 0aee523ff..d5d37d9d0 100644 --- a/terraso_backend/apps/graphql/schema/visualization_config.py +++ b/terraso_backend/apps/graphql/schema/visualization_config.py @@ -101,6 +101,9 @@ class Meta: @classmethod def get_queryset(cls, queryset, info): + # Only filter for user memberships if the field is not visualizationConfigs + # This is because the user can be requesting a visualizations from a parent + # node, that should be handling the filtering if info.field_name != "visualizationConfigs": return queryset