From fa35a5a379482cd2fda5c13e57f4204826644905 Mon Sep 17 00:00:00 2001 From: Emile Swarts Date: Mon, 1 Jul 2024 15:04:07 +0100 Subject: [PATCH 01/86] Update application for DBT Platform --- .InstallPackages | 12 ++ .copilot/config.yml | 6 + .copilot/image_build_run.sh | 6 + .copilot/phases/build.sh | 6 + .copilot/phases/install.sh | 6 + .copilot/phases/post_build.sh | 6 + .copilot/phases/pre_build.sh | 25 +++ Pipfile.lock | 229 +++++++++++++++++++++++ Procfile | 2 +- api/conf/gconfig.py | 4 +- api/conf/settings.py | 22 ++- api/documents/libraries/s3_operations.py | 4 +- 12 files changed, 317 insertions(+), 11 deletions(-) create mode 100644 .InstallPackages create mode 100644 .copilot/config.yml create mode 100755 .copilot/image_build_run.sh create mode 100644 .copilot/phases/build.sh create mode 100644 .copilot/phases/install.sh create mode 100644 .copilot/phases/post_build.sh create mode 100644 .copilot/phases/pre_build.sh diff --git a/.InstallPackages b/.InstallPackages new file mode 100644 index 0000000000..95263bb8af --- /dev/null +++ b/.InstallPackages @@ -0,0 +1,12 @@ +libpq-dev +build-essential +libcairo2 +libpango-1.0-0 +libpangocairo-1.0-0 +libgdk-pixbuf2.0-0 +libffi-dev +shared-mime-info +swig +imagemagick +poppler-utils +libsqlite3-dev \ No newline at end of file diff --git a/.copilot/config.yml b/.copilot/config.yml new file mode 100644 index 0000000000..6a6bbf3bb7 --- /dev/null +++ b/.copilot/config.yml @@ -0,0 +1,6 @@ +repository: lite/lite-backend +builder: + name: paketobuildpacks/builder-jammy-full + version: 0.3.339 +packs: + - acodeninja/install diff --git a/.copilot/image_build_run.sh b/.copilot/image_build_run.sh new file mode 100755 index 0000000000..8ac7a39065 --- /dev/null +++ b/.copilot/image_build_run.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +# Exit early if something goes wrong +set -e + +# Add commands below to run inside the container after all the other buildpacks have been applied diff --git a/.copilot/phases/build.sh b/.copilot/phases/build.sh new file mode 100644 index 0000000000..c1a73f284b --- /dev/null +++ b/.copilot/phases/build.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +# Exit early if something goes wrong +set -e + +# Add commands below to run as part of the build phase diff --git a/.copilot/phases/install.sh b/.copilot/phases/install.sh new file mode 100644 index 0000000000..17794e84a4 --- /dev/null +++ b/.copilot/phases/install.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +# Exit early if something goes wrong +set -e + +# Add commands below to run as part of the install phase diff --git a/.copilot/phases/post_build.sh b/.copilot/phases/post_build.sh new file mode 100644 index 0000000000..1676bb5b32 --- /dev/null +++ b/.copilot/phases/post_build.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +# Exit early if something goes wrong +set -e + +# Add commands below to run as part of the post_build phase diff --git a/.copilot/phases/pre_build.sh b/.copilot/phases/pre_build.sh new file mode 100644 index 0000000000..aa0c045dbd --- /dev/null +++ b/.copilot/phases/pre_build.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +# Exit early if something goes wrong +set -e + +git_clone_base_url="https://codestar-connections.eu-west-2.amazonaws.com/git-http/730335529260/eu-west-2/192881c6-e3f2-41a9-9dcb-fcc87d8b90be/uktrade" + +git config --global credential.helper '!aws codecommit credential-helper $@' +git config --global credential.UseHttpPath true + +cat < ./.gitmodules +[submodule "lite-content"] + path = lite_content + url = $git_clone_base_url/lite-content.git + branch = master +[submodule "lite_routing"] + path = lite_routing + url = $git_clone_base_url/lite-routing.git + branch = main +[submodule "django_db_anonymiser"] + path = django_db_anonymiser + url = $git_clone_base_url/django-db-anonymiser.git +EOF + +git submodule update --init --remote --recursive diff --git a/Pipfile.lock b/Pipfile.lock index 5920071ed3..1dc92ec976 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -25,6 +25,14 @@ "markers": "python_version >= '3.6'", "version": "==5.2.0" }, + "appnope": { + "hashes": [ + "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", + "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c" + ], + "markers": "sys_platform == 'darwin'", + "version": "==0.1.4" + }, "asgiref": { "hashes": [ "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47", @@ -33,6 +41,13 @@ "markers": "python_version >= '3.8'", "version": "==3.8.1" }, + "asn1crypto": { + "hashes": [ + "sha256:13ae38502be632115abf8a24cbe5f4da52e3b5231990aff31123c805306ccb9c", + "sha256:db4e40728b728508912cbb3d44f19ce188f218e9eba635821bb4b68564f8fd67" + ], + "version": "==1.5.1" + }, "async-timeout": { "hashes": [ "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", @@ -72,6 +87,39 @@ "markers": "python_version >= '3.7'", "version": "==2.2.1" }, + "bcrypt": { + "hashes": [ + "sha256:096a15d26ed6ce37a14c1ac1e48119660f21b24cba457f160a4b830f3fe6b5cb", + "sha256:0da52759f7f30e83f1e30a888d9163a81353ef224d82dc58eb5bb52efcabc399", + "sha256:1bb429fedbe0249465cdd85a58e8376f31bb315e484f16e68ca4c786dcc04291", + "sha256:1d84cf6d877918620b687b8fd1bf7781d11e8a0998f576c7aa939776b512b98d", + "sha256:1ee38e858bf5d0287c39b7a1fc59eec64bbf880c7d504d3a06a96c16e14058e7", + "sha256:1ff39b78a52cf03fdf902635e4c81e544714861ba3f0efc56558979dd4f09170", + "sha256:27fe0f57bb5573104b5a6de5e4153c60814c711b29364c10a75a54bb6d7ff48d", + "sha256:3413bd60460f76097ee2e0a493ccebe4a7601918219c02f503984f0a7ee0aebe", + "sha256:3698393a1b1f1fd5714524193849d0c6d524d33523acca37cd28f02899285060", + "sha256:373db9abe198e8e2c70d12b479464e0d5092cc122b20ec504097b5f2297ed184", + "sha256:39e1d30c7233cfc54f5c3f2c825156fe044efdd3e0b9d309512cc514a263ec2a", + "sha256:3bbbfb2734f0e4f37c5136130405332640a1e46e6b23e000eeff2ba8d005da68", + "sha256:3d3a6d28cb2305b43feac298774b997e372e56c7c7afd90a12b3dc49b189151c", + "sha256:5a1e8aa9b28ae28020a3ac4b053117fb51c57a010b9f969603ed885f23841458", + "sha256:61ed14326ee023917ecd093ee6ef422a72f3aec6f07e21ea5f10622b735538a9", + "sha256:655ea221910bcac76ea08aaa76df427ef8625f92e55a8ee44fbf7753dbabb328", + "sha256:762a2c5fb35f89606a9fde5e51392dad0cd1ab7ae64149a8b935fe8d79dd5ed7", + "sha256:77800b7147c9dc905db1cba26abe31e504d8247ac73580b4aa179f98e6608f34", + "sha256:8ac68872c82f1add6a20bd489870c71b00ebacd2e9134a8aa3f98a0052ab4b0e", + "sha256:8d7bb9c42801035e61c109c345a28ed7e84426ae4865511eb82e913df18f58c2", + "sha256:8f6ede91359e5df88d1f5c1ef47428a4420136f3ce97763e31b86dd8280fbdf5", + "sha256:9c1c4ad86351339c5f320ca372dfba6cb6beb25e8efc659bedd918d921956bae", + "sha256:c02d944ca89d9b1922ceb8a46460dd17df1ba37ab66feac4870f6862a1533c00", + "sha256:c52aac18ea1f4a4f65963ea4f9530c306b56ccd0c6f8c8da0c06976e34a6e841", + "sha256:cb2a8ec2bc07d3553ccebf0746bbf3d19426d1c6d1adbd4fa48925f66af7b9e8", + "sha256:cf69eaf5185fd58f268f805b505ce31f9b9fc2d64b376642164e9244540c1221", + "sha256:f4f4acf526fcd1c34e7ce851147deedd4e26e6402369304220250598b26448db" + ], + "markers": "python_version >= '3.7'", + "version": "==4.2.0" + }, "billiard": { "hashes": [ "sha256:12b641b0c539073fc8d3f5b8b7be998956665c4233c7c1fcd66a7e677c4fb36f", @@ -97,6 +145,13 @@ "markers": "python_version >= '3.7'", "version": "==1.29.165" }, + "cached-property": { + "hashes": [ + "sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130", + "sha256:df4f613cf7ad9a588cc381aaf4a512d26265ecebd5eb9e1ba12f1319eb85a6a0" + ], + "version": "==1.5.2" + }, "cairocffi": { "hashes": [ "sha256:2e48ee864884ec4a3a34bfa8c9ab9999f688286eb714a15a43ec9d068c36557b", @@ -718,6 +773,14 @@ "markers": "python_version >= '3.7'", "version": "==2.5.3" }, + "endesive": { + "hashes": [ + "sha256:20e279e1527e5259a0788285ac0397310ee1f3a51fc1b07d7a9261a4355e1cdb", + "sha256:e55fe62093be0f928d8513c821307d10749ecdf3712c7bb7db4e49916de6d466" + ], + "index": "pypi", + "version": "==1.5.12" + }, "et-xmlfile": { "hashes": [ "sha256:8eb9e2bc2f8c97e37a2dc85a09ecdcdec9d8a396530a6d5a33b30b9a92da0c5c", @@ -1076,6 +1139,150 @@ "markers": "python_version >= '3.6' and python_version < '4'", "version": "==0.1.2" }, + "lxml": { + "hashes": [ + "sha256:01220dca0d066d1349bd6a1726856a78f7929f3878f7e2ee83c296c69495309e", + "sha256:02ced472497b8362c8e902ade23e3300479f4f43e45f4105c85ef43b8db85229", + "sha256:052d99051e77a4f3e8482c65014cf6372e61b0a6f4fe9edb98503bb5364cfee3", + "sha256:07da23d7ee08577760f0a71d67a861019103e4812c87e2fab26b039054594cc5", + "sha256:094cb601ba9f55296774c2d57ad68730daa0b13dc260e1f941b4d13678239e70", + "sha256:0a7056921edbdd7560746f4221dca89bb7a3fe457d3d74267995253f46343f15", + "sha256:0c120f43553ec759f8de1fee2f4794452b0946773299d44c36bfe18e83caf002", + "sha256:0d7b36afa46c97875303a94e8f3ad932bf78bace9e18e603f2085b652422edcd", + "sha256:0fdf3a3059611f7585a78ee10399a15566356116a4288380921a4b598d807a22", + "sha256:109fa6fede314cc50eed29e6e56c540075e63d922455346f11e4d7a036d2b8cf", + "sha256:146173654d79eb1fc97498b4280c1d3e1e5d58c398fa530905c9ea50ea849b22", + "sha256:1473427aff3d66a3fa2199004c3e601e6c4500ab86696edffdbc84954c72d832", + "sha256:1483fd3358963cc5c1c9b122c80606a3a79ee0875bcac0204149fa09d6ff2727", + "sha256:168f2dfcfdedf611eb285efac1516c8454c8c99caf271dccda8943576b67552e", + "sha256:17e8d968d04a37c50ad9c456a286b525d78c4a1c15dd53aa46c1d8e06bf6fa30", + "sha256:18feb4b93302091b1541221196a2155aa296c363fd233814fa11e181adebc52f", + "sha256:1afe0a8c353746e610bd9031a630a95bcfb1a720684c3f2b36c4710a0a96528f", + "sha256:1d04f064bebdfef9240478f7a779e8c5dc32b8b7b0b2fc6a62e39b928d428e51", + "sha256:1fdc9fae8dd4c763e8a31e7630afef517eab9f5d5d31a278df087f307bf601f4", + "sha256:1ffc23010330c2ab67fac02781df60998ca8fe759e8efde6f8b756a20599c5de", + "sha256:20094fc3f21ea0a8669dc4c61ed7fa8263bd37d97d93b90f28fc613371e7a875", + "sha256:213261f168c5e1d9b7535a67e68b1f59f92398dd17a56d934550837143f79c42", + "sha256:218c1b2e17a710e363855594230f44060e2025b05c80d1f0661258142b2add2e", + "sha256:23e0553b8055600b3bf4a00b255ec5c92e1e4aebf8c2c09334f8368e8bd174d6", + "sha256:25f1b69d41656b05885aa185f5fdf822cb01a586d1b32739633679699f220391", + "sha256:2b3778cb38212f52fac9fe913017deea2fdf4eb1a4f8e4cfc6b009a13a6d3fcc", + "sha256:2bc9fd5ca4729af796f9f59cd8ff160fe06a474da40aca03fcc79655ddee1a8b", + "sha256:2c226a06ecb8cdef28845ae976da407917542c5e6e75dcac7cc33eb04aaeb237", + "sha256:2c3406b63232fc7e9b8783ab0b765d7c59e7c59ff96759d8ef9632fca27c7ee4", + "sha256:2c86bf781b12ba417f64f3422cfc302523ac9cd1d8ae8c0f92a1c66e56ef2e86", + "sha256:2d9b8d9177afaef80c53c0a9e30fa252ff3036fb1c6494d427c066a4ce6a282f", + "sha256:2dec2d1130a9cda5b904696cec33b2cfb451304ba9081eeda7f90f724097300a", + "sha256:2dfab5fa6a28a0b60a20638dc48e6343c02ea9933e3279ccb132f555a62323d8", + "sha256:2ecdd78ab768f844c7a1d4a03595038c166b609f6395e25af9b0f3f26ae1230f", + "sha256:315f9542011b2c4e1d280e4a20ddcca1761993dda3afc7a73b01235f8641e903", + "sha256:36aef61a1678cb778097b4a6eeae96a69875d51d1e8f4d4b491ab3cfb54b5a03", + "sha256:384aacddf2e5813a36495233b64cb96b1949da72bef933918ba5c84e06af8f0e", + "sha256:3879cc6ce938ff4eb4900d901ed63555c778731a96365e53fadb36437a131a99", + "sha256:3c174dc350d3ec52deb77f2faf05c439331d6ed5e702fc247ccb4e6b62d884b7", + "sha256:3eb44520c4724c2e1a57c0af33a379eee41792595023f367ba3952a2d96c2aab", + "sha256:406246b96d552e0503e17a1006fd27edac678b3fcc9f1be71a2f94b4ff61528d", + "sha256:41ce1f1e2c7755abfc7e759dc34d7d05fd221723ff822947132dc934d122fe22", + "sha256:423b121f7e6fa514ba0c7918e56955a1d4470ed35faa03e3d9f0e3baa4c7e492", + "sha256:44264ecae91b30e5633013fb66f6ddd05c006d3e0e884f75ce0b4755b3e3847b", + "sha256:482c2f67761868f0108b1743098640fbb2a28a8e15bf3f47ada9fa59d9fe08c3", + "sha256:4b0c7a688944891086ba192e21c5229dea54382f4836a209ff8d0a660fac06be", + "sha256:4c1fefd7e3d00921c44dc9ca80a775af49698bbfd92ea84498e56acffd4c5469", + "sha256:4e109ca30d1edec1ac60cdbe341905dc3b8f55b16855e03a54aaf59e51ec8c6f", + "sha256:501d0d7e26b4d261fca8132854d845e4988097611ba2531408ec91cf3fd9d20a", + "sha256:516f491c834eb320d6c843156440fe7fc0d50b33e44387fcec5b02f0bc118a4c", + "sha256:51806cfe0279e06ed8500ce19479d757db42a30fd509940b1701be9c86a5ff9a", + "sha256:562e7494778a69086f0312ec9689f6b6ac1c6b65670ed7d0267e49f57ffa08c4", + "sha256:56b9861a71575f5795bde89256e7467ece3d339c9b43141dbdd54544566b3b94", + "sha256:5b8f5db71b28b8c404956ddf79575ea77aa8b1538e8b2ef9ec877945b3f46442", + "sha256:5c2fb570d7823c2bbaf8b419ba6e5662137f8166e364a8b2b91051a1fb40ab8b", + "sha256:5c54afdcbb0182d06836cc3d1be921e540be3ebdf8b8a51ee3ef987537455f84", + "sha256:5d6a6972b93c426ace71e0be9a6f4b2cfae9b1baed2eed2006076a746692288c", + "sha256:609251a0ca4770e5a8768ff902aa02bf636339c5a93f9349b48eb1f606f7f3e9", + "sha256:62d172f358f33a26d6b41b28c170c63886742f5b6772a42b59b4f0fa10526cb1", + "sha256:62f7fdb0d1ed2065451f086519865b4c90aa19aed51081979ecd05a21eb4d1be", + "sha256:658f2aa69d31e09699705949b5fc4719cbecbd4a97f9656a232e7d6c7be1a367", + "sha256:65ab5685d56914b9a2a34d67dd5488b83213d680b0c5d10b47f81da5a16b0b0e", + "sha256:68934b242c51eb02907c5b81d138cb977b2129a0a75a8f8b60b01cb8586c7b21", + "sha256:68b87753c784d6acb8a25b05cb526c3406913c9d988d51f80adecc2b0775d6aa", + "sha256:69959bd3167b993e6e710b99051265654133a98f20cec1d9b493b931942e9c16", + "sha256:6a7095eeec6f89111d03dabfe5883a1fd54da319c94e0fb104ee8f23616b572d", + "sha256:6b038cc86b285e4f9fea2ba5ee76e89f21ed1ea898e287dc277a25884f3a7dfe", + "sha256:6ba0d3dcac281aad8a0e5b14c7ed6f9fa89c8612b47939fc94f80b16e2e9bc83", + "sha256:6e91cf736959057f7aac7adfc83481e03615a8e8dd5758aa1d95ea69e8931dba", + "sha256:6ee8c39582d2652dcd516d1b879451500f8db3fe3607ce45d7c5957ab2596040", + "sha256:6f651ebd0b21ec65dfca93aa629610a0dbc13dbc13554f19b0113da2e61a4763", + "sha256:71a8dd38fbd2f2319136d4ae855a7078c69c9a38ae06e0c17c73fd70fc6caad8", + "sha256:74068c601baff6ff021c70f0935b0c7bc528baa8ea210c202e03757c68c5a4ff", + "sha256:7437237c6a66b7ca341e868cda48be24b8701862757426852c9b3186de1da8a2", + "sha256:747a3d3e98e24597981ca0be0fd922aebd471fa99d0043a3842d00cdcad7ad6a", + "sha256:74bcb423462233bc5d6066e4e98b0264e7c1bed7541fff2f4e34fe6b21563c8b", + "sha256:78d9b952e07aed35fe2e1a7ad26e929595412db48535921c5013edc8aa4a35ce", + "sha256:7b1cd427cb0d5f7393c31b7496419da594fe600e6fdc4b105a54f82405e6626c", + "sha256:7d3d1ca42870cdb6d0d29939630dbe48fa511c203724820fc0fd507b2fb46577", + "sha256:7e2f58095acc211eb9d8b5771bf04df9ff37d6b87618d1cbf85f92399c98dae8", + "sha256:7f41026c1d64043a36fda21d64c5026762d53a77043e73e94b71f0521939cc71", + "sha256:81b4e48da4c69313192d8c8d4311e5d818b8be1afe68ee20f6385d0e96fc9512", + "sha256:86a6b24b19eaebc448dc56b87c4865527855145d851f9fc3891673ff97950540", + "sha256:874a216bf6afaf97c263b56371434e47e2c652d215788396f60477540298218f", + "sha256:89e043f1d9d341c52bf2af6d02e6adde62e0a46e6755d5eb60dc6e4f0b8aeca2", + "sha256:8c72e9563347c7395910de6a3100a4840a75a6f60e05af5e58566868d5eb2d6a", + "sha256:8dc2c0395bea8254d8daebc76dcf8eb3a95ec2a46fa6fae5eaccee366bfe02ce", + "sha256:8f0de2d390af441fe8b2c12626d103540b5d850d585b18fcada58d972b74a74e", + "sha256:92e67a0be1639c251d21e35fe74df6bcc40cba445c2cda7c4a967656733249e2", + "sha256:94d6c3782907b5e40e21cadf94b13b0842ac421192f26b84c45f13f3c9d5dc27", + "sha256:97acf1e1fd66ab53dacd2c35b319d7e548380c2e9e8c54525c6e76d21b1ae3b1", + "sha256:9ada35dd21dc6c039259596b358caab6b13f4db4d4a7f8665764d616daf9cc1d", + "sha256:9c52100e2c2dbb0649b90467935c4b0de5528833c76a35ea1a2691ec9f1ee7a1", + "sha256:9e41506fec7a7f9405b14aa2d5c8abbb4dbbd09d88f9496958b6d00cb4d45330", + "sha256:9e4b47ac0f5e749cfc618efdf4726269441014ae1d5583e047b452a32e221920", + "sha256:9fb81d2824dff4f2e297a276297e9031f46d2682cafc484f49de182aa5e5df99", + "sha256:a0eabd0a81625049c5df745209dc7fcef6e2aea7793e5f003ba363610aa0a3ff", + "sha256:a3d819eb6f9b8677f57f9664265d0a10dd6551d227afb4af2b9cd7bdc2ccbf18", + "sha256:a87de7dd873bf9a792bf1e58b1c3887b9264036629a5bf2d2e6579fe8e73edff", + "sha256:aa617107a410245b8660028a7483b68e7914304a6d4882b5ff3d2d3eb5948d8c", + "sha256:aac0bbd3e8dd2d9c45ceb82249e8bdd3ac99131a32b4d35c8af3cc9db1657179", + "sha256:ab6dd83b970dc97c2d10bc71aa925b84788c7c05de30241b9e96f9b6d9ea3080", + "sha256:ace2c2326a319a0bb8a8b0e5b570c764962e95818de9f259ce814ee666603f19", + "sha256:ae5fe5c4b525aa82b8076c1a59d642c17b6e8739ecf852522c6321852178119d", + "sha256:b11a5d918a6216e521c715b02749240fb07ae5a1fefd4b7bf12f833bc8b4fe70", + "sha256:b1c8c20847b9f34e98080da785bb2336ea982e7f913eed5809e5a3c872900f32", + "sha256:b369d3db3c22ed14c75ccd5af429086f166a19627e84a8fdade3f8f31426e52a", + "sha256:b710bc2b8292966b23a6a0121f7a6c51d45d2347edcc75f016ac123b8054d3f2", + "sha256:bd96517ef76c8654446fc3db9242d019a1bb5fe8b751ba414765d59f99210b79", + "sha256:c00f323cc00576df6165cc9d21a4c21285fa6b9989c5c39830c3903dc4303ef3", + "sha256:c162b216070f280fa7da844531169be0baf9ccb17263cf5a8bf876fcd3117fa5", + "sha256:c1a69e58a6bb2de65902051d57fde951febad631a20a64572677a1052690482f", + "sha256:c1f794c02903c2824fccce5b20c339a1a14b114e83b306ff11b597c5f71a1c8d", + "sha256:c24037349665434f375645fa9d1f5304800cec574d0310f618490c871fd902b3", + "sha256:c300306673aa0f3ed5ed9372b21867690a17dba38c68c44b287437c362ce486b", + "sha256:c56a1d43b2f9ee4786e4658c7903f05da35b923fb53c11025712562d5cc02753", + "sha256:c6379f35350b655fd817cd0d6cbeef7f265f3ae5fedb1caae2eb442bbeae9ab9", + "sha256:c802e1c2ed9f0c06a65bc4ed0189d000ada8049312cfeab6ca635e39c9608957", + "sha256:cb83f8a875b3d9b458cada4f880fa498646874ba4011dc974e071a0a84a1b033", + "sha256:cf120cce539453ae086eacc0130a324e7026113510efa83ab42ef3fcfccac7fb", + "sha256:dd36439be765e2dde7660212b5275641edbc813e7b24668831a5c8ac91180656", + "sha256:dd5350b55f9fecddc51385463a4f67a5da829bc741e38cf689f38ec9023f54ab", + "sha256:df5c7333167b9674aa8ae1d4008fa4bc17a313cc490b2cca27838bbdcc6bb15b", + "sha256:e63601ad5cd8f860aa99d109889b5ac34de571c7ee902d6812d5d9ddcc77fa7d", + "sha256:e92ce66cd919d18d14b3856906a61d3f6b6a8500e0794142338da644260595cd", + "sha256:e99f5507401436fdcc85036a2e7dc2e28d962550afe1cbfc07c40e454256a859", + "sha256:ea2e2f6f801696ad7de8aec061044d6c8c0dd4037608c7cab38a9a4d316bfb11", + "sha256:eafa2c8658f4e560b098fe9fc54539f86528651f61849b22111a9b107d18910c", + "sha256:ecd4ad8453ac17bc7ba3868371bffb46f628161ad0eefbd0a855d2c8c32dd81a", + "sha256:ee70d08fd60c9565ba8190f41a46a54096afa0eeb8f76bd66f2c25d3b1b83005", + "sha256:eec1bb8cdbba2925bedc887bc0609a80e599c75b12d87ae42ac23fd199445654", + "sha256:ef0c1fe22171dd7c7c27147f2e9c3e86f8bdf473fed75f16b0c2e84a5030ce80", + "sha256:f2901429da1e645ce548bf9171784c0f74f0718c3f6150ce166be39e4dd66c3e", + "sha256:f422a209d2455c56849442ae42f25dbaaba1c6c3f501d58761c619c7836642ec", + "sha256:f65e5120863c2b266dbcc927b306c5b78e502c71edf3295dfcb9501ec96e5fc7", + "sha256:f7d4a670107d75dfe5ad080bed6c341d18c4442f9378c9f58e5851e86eb79965", + "sha256:f914c03e6a31deb632e2daa881fe198461f4d06e57ac3d0e05bbcab8eae01945", + "sha256:fb66442c2546446944437df74379e9cf9e9db353e61301d1a0e26482f43f0dd8" + ], + "markers": "python_version >= '3.6'", + "version": "==5.3.0" + }, "markdown": { "hashes": [ "sha256:225c6123522495d4119a90b3a3ba31a1e87a70369e03f14799ea9c0d7183a3d6", @@ -1260,6 +1467,13 @@ "markers": "python_version >= '3.7'", "version": "==0.43b0" }, + "oscrypto": { + "hashes": [ + "sha256:2b2f1d2d42ec152ca90ccb5682f3e051fb55986e1b170ebde472b133713e7085", + "sha256:6f5fef59cb5b3708321db7cca56aed8ad7e662853351e7991fcf60ec606d47a4" + ], + "version": "==1.3.0" + }, "packaging": { "hashes": [ "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", @@ -1268,6 +1482,14 @@ "markers": "python_version >= '3.8'", "version": "==24.1" }, + "paramiko": { + "hashes": [ + "sha256:8b15302870af7f6652f2e038975c1d2973f06046cb5d7d65355668b3ecbece0c", + "sha256:8e49fd2f82f84acf7ffd57c64311aa2b30e575370dc23bdb375b10262f7eac32" + ], + "markers": "python_version >= '3.6'", + "version": "==3.4.1" + }, "parso": { "hashes": [ "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", @@ -1489,6 +1711,13 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==2.9.0.post0" }, + "python-pkcs11": { + "hashes": [ + "sha256:9737e0c24cabb8bc9d48bf8c57c3df2a70f8cdd96b70c50290803286f9e46bf7" + ], + "index": "pypi", + "version": "==0.7.0" + }, "pytz": { "hashes": [ "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a", diff --git a/Procfile b/Procfile index af1add373e..db03e6cfa6 100644 --- a/Procfile +++ b/Procfile @@ -1,3 +1,3 @@ -web: SWIG_LIB=/home/vcap/deps/0/apt/usr/share/swig4.0 CFLAGS=-I/home/vcap/deps/1/python/include/python3.9.18m pip3 install endesive==1.5.9 && python manage.py migrate && gunicorn --worker-class gevent -c api/conf/gconfig.py -b 0.0.0.0:$PORT api.conf.wsgi +web: python manage.py migrate && gunicorn --worker-class gevent -c api/conf/gconfig.py -b 0.0.0.0:$PORT api.conf.wsgi celeryworker: celery -A api.conf worker -l info celeryscheduler: celery -A api.conf beat diff --git a/api/conf/gconfig.py b/api/conf/gconfig.py index 11b3d242c9..8db4286607 100644 --- a/api/conf/gconfig.py +++ b/api/conf/gconfig.py @@ -1,7 +1,7 @@ import os -PORT = os.environ.get("PORT", 8080) -bind = "0.0.0.0:{PORT}".format(PORT=PORT) +# PORT = os.environ.get("PORT", 8080) +# bind = "0.0.0.0:{PORT}".format(PORT=PORT) workers = 4 worker_connections = 1000 # timeout affect document uploads diff --git a/api/conf/settings.py b/api/conf/settings.py index bc2b03f5a9..e44f629791 100644 --- a/api/conf/settings.py +++ b/api/conf/settings.py @@ -124,10 +124,6 @@ "api.external_data", "api.support", "health_check", - "health_check.db", - "health_check.cache", - "health_check.storage", - "health_check.contrib.migrations", "health_check.contrib.celery", "health_check.contrib.celery_ping", "django_audit_log_middleware", @@ -321,6 +317,7 @@ environment=env.str("SENTRY_ENVIRONMENT"), integrations=[DjangoIntegration()], send_default_pii=True, + traces_sample_rate=env.float("SENTRY_TRACES_SAMPLE_RATE", 1.0), ) # Application Performance Monitoring @@ -464,12 +461,27 @@ def _build_redis_url(base_url, db_number, **query_args): if IS_ENV_DBT_PLATFORM: ALLOWED_HOSTS = setup_allowed_hosts(ALLOWED_HOSTS) - + AWS_ENDPOINT_URL = env("AWS_ENDPOINT_URL", default=None) DATABASES = {"default": dj_database_url.config(default=database_url_from_env("DATABASE_CREDENTIALS"))} CELERY_BROKER_URL = env("CELERY_BROKER_URL", default=None) CELERY_RESULT_BACKEND = CELERY_BROKER_URL REDIS_BASE_URL = env("REDIS_BASE_URL", default=None) + AWS_STORAGE_BUCKET_NAME = env("AWS_STORAGE_BUCKET_NAME") + DB_ANONYMISER_AWS_ENDPOINT_URL = AWS_ENDPOINT_URL + DB_ANONYMISER_AWS_ACCESS_KEY_ID = env("DB_ANONYMISER_AWS_ACCESS_KEY_ID", default=None) + DB_ANONYMISER_AWS_SECRET_ACCESS_KEY = env("DB_ANONYMISER_AWS_SECRET_ACCESS_KEY", default=None) + DB_ANONYMISER_AWS_REGION = env("DB_ANONYMISER_AWS_REGION", default=None) + DB_ANONYMISER_AWS_STORAGE_BUCKET_NAME = env("DB_ANONYMISER_AWS_STORAGE_BUCKET_NAME", default=None) + + if REDIS_BASE_URL: + # Give celery tasks their own redis DB - future uses of redis should use a different DB + REDIS_CELERY_DB = env("REDIS_CELERY_DB", default=0) + is_redis_ssl = REDIS_BASE_URL.startswith("rediss://") + url_args = {"ssl_cert_reqs": "CERT_REQUIRED"} if is_redis_ssl else {} + CELERY_BROKER_URL = _build_redis_url(REDIS_BASE_URL, REDIS_CELERY_DB, **url_args) + CELERY_RESULT_BACKEND = CELERY_BROKER_URL + # Elasticsearch configuration LITE_API_ENABLE_ES = env.bool("LITE_API_ENABLE_ES", False) if LITE_API_ENABLE_ES: diff --git a/api/documents/libraries/s3_operations.py b/api/documents/libraries/s3_operations.py index 5253a17685..fe823780a0 100644 --- a/api/documents/libraries/s3_operations.py +++ b/api/documents/libraries/s3_operations.py @@ -25,9 +25,7 @@ def init_s3_client(): additional_s3_params["endpoint_url"] = settings.AWS_ENDPOINT_URL _client = boto3.client( "s3", - aws_access_key_id=settings.AWS_ACCESS_KEY_ID, - aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY, - region_name=settings.AWS_REGION, + region_name="eu-west-2", config=Config(connect_timeout=settings.S3_CONNECT_TIMEOUT, read_timeout=settings.S3_REQUEST_TIMEOUT), **additional_s3_params, ) From 4e22ee8d8546a51687d0da4ac2cc2464c20c7643 Mon Sep 17 00:00:00 2001 From: Emile Swarts Date: Thu, 12 Sep 2024 13:41:44 +0100 Subject: [PATCH 02/86] Install endesive in the procfile instead of the Pipfile --- Procfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Procfile b/Procfile index db03e6cfa6..9c70e5caa8 100644 --- a/Procfile +++ b/Procfile @@ -1,3 +1,3 @@ -web: python manage.py migrate && gunicorn --worker-class gevent -c api/conf/gconfig.py -b 0.0.0.0:$PORT api.conf.wsgi +web: pip3 install endesive==1.5.9 && python manage.py migrate && gunicorn --worker-class gevent -c api/conf/gconfig.py -b 0.0.0.0:$PORT api.conf.wsgi celeryworker: celery -A api.conf worker -l info celeryscheduler: celery -A api.conf beat From e85d3bdfcdc6e9f7056132da5ac5fc3b8e715869 Mon Sep 17 00:00:00 2001 From: James Francis Date: Thu, 12 Sep 2024 13:53:09 +0100 Subject: [PATCH 03/86] revert pipefile.lock to match master --- Pipfile.lock | 529 ++++++++++++++------------------------------------- 1 file changed, 144 insertions(+), 385 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 1dc92ec976..f733d9947e 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -25,14 +25,6 @@ "markers": "python_version >= '3.6'", "version": "==5.2.0" }, - "appnope": { - "hashes": [ - "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", - "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c" - ], - "markers": "sys_platform == 'darwin'", - "version": "==0.1.4" - }, "asgiref": { "hashes": [ "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47", @@ -41,13 +33,6 @@ "markers": "python_version >= '3.8'", "version": "==3.8.1" }, - "asn1crypto": { - "hashes": [ - "sha256:13ae38502be632115abf8a24cbe5f4da52e3b5231990aff31123c805306ccb9c", - "sha256:db4e40728b728508912cbb3d44f19ce188f218e9eba635821bb4b68564f8fd67" - ], - "version": "==1.5.1" - }, "async-timeout": { "hashes": [ "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", @@ -56,14 +41,6 @@ "markers": "python_version >= '3.7'", "version": "==4.0.3" }, - "attrs": { - "hashes": [ - "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", - "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2" - ], - "markers": "python_version >= '3.7'", - "version": "==24.2.0" - }, "autopep8": { "hashes": [ "sha256:8d6c87eba648fdcfc83e29b788910b8643171c395d9c4bcf115ece035b9c9dda", @@ -87,39 +64,6 @@ "markers": "python_version >= '3.7'", "version": "==2.2.1" }, - "bcrypt": { - "hashes": [ - "sha256:096a15d26ed6ce37a14c1ac1e48119660f21b24cba457f160a4b830f3fe6b5cb", - "sha256:0da52759f7f30e83f1e30a888d9163a81353ef224d82dc58eb5bb52efcabc399", - "sha256:1bb429fedbe0249465cdd85a58e8376f31bb315e484f16e68ca4c786dcc04291", - "sha256:1d84cf6d877918620b687b8fd1bf7781d11e8a0998f576c7aa939776b512b98d", - "sha256:1ee38e858bf5d0287c39b7a1fc59eec64bbf880c7d504d3a06a96c16e14058e7", - "sha256:1ff39b78a52cf03fdf902635e4c81e544714861ba3f0efc56558979dd4f09170", - "sha256:27fe0f57bb5573104b5a6de5e4153c60814c711b29364c10a75a54bb6d7ff48d", - "sha256:3413bd60460f76097ee2e0a493ccebe4a7601918219c02f503984f0a7ee0aebe", - "sha256:3698393a1b1f1fd5714524193849d0c6d524d33523acca37cd28f02899285060", - "sha256:373db9abe198e8e2c70d12b479464e0d5092cc122b20ec504097b5f2297ed184", - "sha256:39e1d30c7233cfc54f5c3f2c825156fe044efdd3e0b9d309512cc514a263ec2a", - "sha256:3bbbfb2734f0e4f37c5136130405332640a1e46e6b23e000eeff2ba8d005da68", - "sha256:3d3a6d28cb2305b43feac298774b997e372e56c7c7afd90a12b3dc49b189151c", - "sha256:5a1e8aa9b28ae28020a3ac4b053117fb51c57a010b9f969603ed885f23841458", - "sha256:61ed14326ee023917ecd093ee6ef422a72f3aec6f07e21ea5f10622b735538a9", - "sha256:655ea221910bcac76ea08aaa76df427ef8625f92e55a8ee44fbf7753dbabb328", - "sha256:762a2c5fb35f89606a9fde5e51392dad0cd1ab7ae64149a8b935fe8d79dd5ed7", - "sha256:77800b7147c9dc905db1cba26abe31e504d8247ac73580b4aa179f98e6608f34", - "sha256:8ac68872c82f1add6a20bd489870c71b00ebacd2e9134a8aa3f98a0052ab4b0e", - "sha256:8d7bb9c42801035e61c109c345a28ed7e84426ae4865511eb82e913df18f58c2", - "sha256:8f6ede91359e5df88d1f5c1ef47428a4420136f3ce97763e31b86dd8280fbdf5", - "sha256:9c1c4ad86351339c5f320ca372dfba6cb6beb25e8efc659bedd918d921956bae", - "sha256:c02d944ca89d9b1922ceb8a46460dd17df1ba37ab66feac4870f6862a1533c00", - "sha256:c52aac18ea1f4a4f65963ea4f9530c306b56ccd0c6f8c8da0c06976e34a6e841", - "sha256:cb2a8ec2bc07d3553ccebf0746bbf3d19426d1c6d1adbd4fa48925f66af7b9e8", - "sha256:cf69eaf5185fd58f268f805b505ce31f9b9fc2d64b376642164e9244540c1221", - "sha256:f4f4acf526fcd1c34e7ce851147deedd4e26e6402369304220250598b26448db" - ], - "markers": "python_version >= '3.7'", - "version": "==4.2.0" - }, "billiard": { "hashes": [ "sha256:12b641b0c539073fc8d3f5b8b7be998956665c4233c7c1fcd66a7e677c4fb36f", @@ -145,13 +89,6 @@ "markers": "python_version >= '3.7'", "version": "==1.29.165" }, - "cached-property": { - "hashes": [ - "sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130", - "sha256:df4f613cf7ad9a588cc381aaf4a512d26265ecebd5eb9e1ba12f1319eb85a6a0" - ], - "version": "==1.5.2" - }, "cairocffi": { "hashes": [ "sha256:2e48ee864884ec4a3a34bfa8c9ab9999f688286eb714a15a43ec9d068c36557b", @@ -647,20 +584,20 @@ }, "django-queryable-properties": { "hashes": [ - "sha256:9a2d35ea6cd33f80ac666f62009006a2373bcfbfc720981a60a9a428585659d1", - "sha256:aaec7d3ea9dc3be44e6114ca1ca705ac0e23b00c5209832aeb1c6ab5c4e9c345" + "sha256:68f3ed8cd6f03fb2993eabe1c3235091781f01266397b75319e1e20556991d7f", + "sha256:f272d5b68be3bd3a57004dcbe1f849ba5080a97069ff0f0f858c364a9eafedb6" ], "index": "pypi", - "version": "==1.9.3" + "version": "==1.9.2" }, "django-reversion": { "hashes": [ - "sha256:084d4f117d9e2b4e8dfdfaad83ebb34410a03eed6071c96089e6811fdea82ad3", - "sha256:3309821e5b6fceedcce6b6975f1a9c7fab6ae7c7d0e1276a90e345946fa0dcb8" + "sha256:5884e9f77f55c341b3f0a8d3b0af000f060530653776997267c8b1e5349d8fee", + "sha256:c047cc99a9f1ba4aae6db89c3ac243478d6de98ec8a60c7073fcc875d89c5cdb" ], "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==5.1.0" + "markers": "python_version >= '3.7'", + "version": "==5.0.12" }, "django-silk": { "hashes": [ @@ -773,14 +710,6 @@ "markers": "python_version >= '3.7'", "version": "==2.5.3" }, - "endesive": { - "hashes": [ - "sha256:20e279e1527e5259a0788285ac0397310ee1f3a51fc1b07d7a9261a4355e1cdb", - "sha256:e55fe62093be0f928d8513c821307d10749ecdf3712c7bb7db4e49916de6d466" - ], - "index": "pypi", - "version": "==1.5.12" - }, "et-xmlfile": { "hashes": [ "sha256:8eb9e2bc2f8c97e37a2dc85a09ecdcdec9d8a396530a6d5a33b30b9a92da0c5c", @@ -1139,150 +1068,6 @@ "markers": "python_version >= '3.6' and python_version < '4'", "version": "==0.1.2" }, - "lxml": { - "hashes": [ - "sha256:01220dca0d066d1349bd6a1726856a78f7929f3878f7e2ee83c296c69495309e", - "sha256:02ced472497b8362c8e902ade23e3300479f4f43e45f4105c85ef43b8db85229", - "sha256:052d99051e77a4f3e8482c65014cf6372e61b0a6f4fe9edb98503bb5364cfee3", - "sha256:07da23d7ee08577760f0a71d67a861019103e4812c87e2fab26b039054594cc5", - "sha256:094cb601ba9f55296774c2d57ad68730daa0b13dc260e1f941b4d13678239e70", - "sha256:0a7056921edbdd7560746f4221dca89bb7a3fe457d3d74267995253f46343f15", - "sha256:0c120f43553ec759f8de1fee2f4794452b0946773299d44c36bfe18e83caf002", - "sha256:0d7b36afa46c97875303a94e8f3ad932bf78bace9e18e603f2085b652422edcd", - "sha256:0fdf3a3059611f7585a78ee10399a15566356116a4288380921a4b598d807a22", - "sha256:109fa6fede314cc50eed29e6e56c540075e63d922455346f11e4d7a036d2b8cf", - "sha256:146173654d79eb1fc97498b4280c1d3e1e5d58c398fa530905c9ea50ea849b22", - "sha256:1473427aff3d66a3fa2199004c3e601e6c4500ab86696edffdbc84954c72d832", - "sha256:1483fd3358963cc5c1c9b122c80606a3a79ee0875bcac0204149fa09d6ff2727", - "sha256:168f2dfcfdedf611eb285efac1516c8454c8c99caf271dccda8943576b67552e", - "sha256:17e8d968d04a37c50ad9c456a286b525d78c4a1c15dd53aa46c1d8e06bf6fa30", - "sha256:18feb4b93302091b1541221196a2155aa296c363fd233814fa11e181adebc52f", - "sha256:1afe0a8c353746e610bd9031a630a95bcfb1a720684c3f2b36c4710a0a96528f", - "sha256:1d04f064bebdfef9240478f7a779e8c5dc32b8b7b0b2fc6a62e39b928d428e51", - "sha256:1fdc9fae8dd4c763e8a31e7630afef517eab9f5d5d31a278df087f307bf601f4", - "sha256:1ffc23010330c2ab67fac02781df60998ca8fe759e8efde6f8b756a20599c5de", - "sha256:20094fc3f21ea0a8669dc4c61ed7fa8263bd37d97d93b90f28fc613371e7a875", - "sha256:213261f168c5e1d9b7535a67e68b1f59f92398dd17a56d934550837143f79c42", - "sha256:218c1b2e17a710e363855594230f44060e2025b05c80d1f0661258142b2add2e", - "sha256:23e0553b8055600b3bf4a00b255ec5c92e1e4aebf8c2c09334f8368e8bd174d6", - "sha256:25f1b69d41656b05885aa185f5fdf822cb01a586d1b32739633679699f220391", - "sha256:2b3778cb38212f52fac9fe913017deea2fdf4eb1a4f8e4cfc6b009a13a6d3fcc", - "sha256:2bc9fd5ca4729af796f9f59cd8ff160fe06a474da40aca03fcc79655ddee1a8b", - "sha256:2c226a06ecb8cdef28845ae976da407917542c5e6e75dcac7cc33eb04aaeb237", - "sha256:2c3406b63232fc7e9b8783ab0b765d7c59e7c59ff96759d8ef9632fca27c7ee4", - "sha256:2c86bf781b12ba417f64f3422cfc302523ac9cd1d8ae8c0f92a1c66e56ef2e86", - "sha256:2d9b8d9177afaef80c53c0a9e30fa252ff3036fb1c6494d427c066a4ce6a282f", - "sha256:2dec2d1130a9cda5b904696cec33b2cfb451304ba9081eeda7f90f724097300a", - "sha256:2dfab5fa6a28a0b60a20638dc48e6343c02ea9933e3279ccb132f555a62323d8", - "sha256:2ecdd78ab768f844c7a1d4a03595038c166b609f6395e25af9b0f3f26ae1230f", - "sha256:315f9542011b2c4e1d280e4a20ddcca1761993dda3afc7a73b01235f8641e903", - "sha256:36aef61a1678cb778097b4a6eeae96a69875d51d1e8f4d4b491ab3cfb54b5a03", - "sha256:384aacddf2e5813a36495233b64cb96b1949da72bef933918ba5c84e06af8f0e", - "sha256:3879cc6ce938ff4eb4900d901ed63555c778731a96365e53fadb36437a131a99", - "sha256:3c174dc350d3ec52deb77f2faf05c439331d6ed5e702fc247ccb4e6b62d884b7", - "sha256:3eb44520c4724c2e1a57c0af33a379eee41792595023f367ba3952a2d96c2aab", - "sha256:406246b96d552e0503e17a1006fd27edac678b3fcc9f1be71a2f94b4ff61528d", - "sha256:41ce1f1e2c7755abfc7e759dc34d7d05fd221723ff822947132dc934d122fe22", - "sha256:423b121f7e6fa514ba0c7918e56955a1d4470ed35faa03e3d9f0e3baa4c7e492", - "sha256:44264ecae91b30e5633013fb66f6ddd05c006d3e0e884f75ce0b4755b3e3847b", - "sha256:482c2f67761868f0108b1743098640fbb2a28a8e15bf3f47ada9fa59d9fe08c3", - "sha256:4b0c7a688944891086ba192e21c5229dea54382f4836a209ff8d0a660fac06be", - "sha256:4c1fefd7e3d00921c44dc9ca80a775af49698bbfd92ea84498e56acffd4c5469", - "sha256:4e109ca30d1edec1ac60cdbe341905dc3b8f55b16855e03a54aaf59e51ec8c6f", - "sha256:501d0d7e26b4d261fca8132854d845e4988097611ba2531408ec91cf3fd9d20a", - "sha256:516f491c834eb320d6c843156440fe7fc0d50b33e44387fcec5b02f0bc118a4c", - "sha256:51806cfe0279e06ed8500ce19479d757db42a30fd509940b1701be9c86a5ff9a", - "sha256:562e7494778a69086f0312ec9689f6b6ac1c6b65670ed7d0267e49f57ffa08c4", - "sha256:56b9861a71575f5795bde89256e7467ece3d339c9b43141dbdd54544566b3b94", - "sha256:5b8f5db71b28b8c404956ddf79575ea77aa8b1538e8b2ef9ec877945b3f46442", - "sha256:5c2fb570d7823c2bbaf8b419ba6e5662137f8166e364a8b2b91051a1fb40ab8b", - "sha256:5c54afdcbb0182d06836cc3d1be921e540be3ebdf8b8a51ee3ef987537455f84", - "sha256:5d6a6972b93c426ace71e0be9a6f4b2cfae9b1baed2eed2006076a746692288c", - "sha256:609251a0ca4770e5a8768ff902aa02bf636339c5a93f9349b48eb1f606f7f3e9", - "sha256:62d172f358f33a26d6b41b28c170c63886742f5b6772a42b59b4f0fa10526cb1", - "sha256:62f7fdb0d1ed2065451f086519865b4c90aa19aed51081979ecd05a21eb4d1be", - "sha256:658f2aa69d31e09699705949b5fc4719cbecbd4a97f9656a232e7d6c7be1a367", - "sha256:65ab5685d56914b9a2a34d67dd5488b83213d680b0c5d10b47f81da5a16b0b0e", - "sha256:68934b242c51eb02907c5b81d138cb977b2129a0a75a8f8b60b01cb8586c7b21", - "sha256:68b87753c784d6acb8a25b05cb526c3406913c9d988d51f80adecc2b0775d6aa", - "sha256:69959bd3167b993e6e710b99051265654133a98f20cec1d9b493b931942e9c16", - "sha256:6a7095eeec6f89111d03dabfe5883a1fd54da319c94e0fb104ee8f23616b572d", - "sha256:6b038cc86b285e4f9fea2ba5ee76e89f21ed1ea898e287dc277a25884f3a7dfe", - "sha256:6ba0d3dcac281aad8a0e5b14c7ed6f9fa89c8612b47939fc94f80b16e2e9bc83", - "sha256:6e91cf736959057f7aac7adfc83481e03615a8e8dd5758aa1d95ea69e8931dba", - "sha256:6ee8c39582d2652dcd516d1b879451500f8db3fe3607ce45d7c5957ab2596040", - "sha256:6f651ebd0b21ec65dfca93aa629610a0dbc13dbc13554f19b0113da2e61a4763", - "sha256:71a8dd38fbd2f2319136d4ae855a7078c69c9a38ae06e0c17c73fd70fc6caad8", - "sha256:74068c601baff6ff021c70f0935b0c7bc528baa8ea210c202e03757c68c5a4ff", - "sha256:7437237c6a66b7ca341e868cda48be24b8701862757426852c9b3186de1da8a2", - "sha256:747a3d3e98e24597981ca0be0fd922aebd471fa99d0043a3842d00cdcad7ad6a", - "sha256:74bcb423462233bc5d6066e4e98b0264e7c1bed7541fff2f4e34fe6b21563c8b", - "sha256:78d9b952e07aed35fe2e1a7ad26e929595412db48535921c5013edc8aa4a35ce", - "sha256:7b1cd427cb0d5f7393c31b7496419da594fe600e6fdc4b105a54f82405e6626c", - "sha256:7d3d1ca42870cdb6d0d29939630dbe48fa511c203724820fc0fd507b2fb46577", - "sha256:7e2f58095acc211eb9d8b5771bf04df9ff37d6b87618d1cbf85f92399c98dae8", - "sha256:7f41026c1d64043a36fda21d64c5026762d53a77043e73e94b71f0521939cc71", - "sha256:81b4e48da4c69313192d8c8d4311e5d818b8be1afe68ee20f6385d0e96fc9512", - "sha256:86a6b24b19eaebc448dc56b87c4865527855145d851f9fc3891673ff97950540", - "sha256:874a216bf6afaf97c263b56371434e47e2c652d215788396f60477540298218f", - "sha256:89e043f1d9d341c52bf2af6d02e6adde62e0a46e6755d5eb60dc6e4f0b8aeca2", - "sha256:8c72e9563347c7395910de6a3100a4840a75a6f60e05af5e58566868d5eb2d6a", - "sha256:8dc2c0395bea8254d8daebc76dcf8eb3a95ec2a46fa6fae5eaccee366bfe02ce", - "sha256:8f0de2d390af441fe8b2c12626d103540b5d850d585b18fcada58d972b74a74e", - "sha256:92e67a0be1639c251d21e35fe74df6bcc40cba445c2cda7c4a967656733249e2", - "sha256:94d6c3782907b5e40e21cadf94b13b0842ac421192f26b84c45f13f3c9d5dc27", - "sha256:97acf1e1fd66ab53dacd2c35b319d7e548380c2e9e8c54525c6e76d21b1ae3b1", - "sha256:9ada35dd21dc6c039259596b358caab6b13f4db4d4a7f8665764d616daf9cc1d", - "sha256:9c52100e2c2dbb0649b90467935c4b0de5528833c76a35ea1a2691ec9f1ee7a1", - "sha256:9e41506fec7a7f9405b14aa2d5c8abbb4dbbd09d88f9496958b6d00cb4d45330", - "sha256:9e4b47ac0f5e749cfc618efdf4726269441014ae1d5583e047b452a32e221920", - "sha256:9fb81d2824dff4f2e297a276297e9031f46d2682cafc484f49de182aa5e5df99", - "sha256:a0eabd0a81625049c5df745209dc7fcef6e2aea7793e5f003ba363610aa0a3ff", - "sha256:a3d819eb6f9b8677f57f9664265d0a10dd6551d227afb4af2b9cd7bdc2ccbf18", - "sha256:a87de7dd873bf9a792bf1e58b1c3887b9264036629a5bf2d2e6579fe8e73edff", - "sha256:aa617107a410245b8660028a7483b68e7914304a6d4882b5ff3d2d3eb5948d8c", - "sha256:aac0bbd3e8dd2d9c45ceb82249e8bdd3ac99131a32b4d35c8af3cc9db1657179", - "sha256:ab6dd83b970dc97c2d10bc71aa925b84788c7c05de30241b9e96f9b6d9ea3080", - "sha256:ace2c2326a319a0bb8a8b0e5b570c764962e95818de9f259ce814ee666603f19", - "sha256:ae5fe5c4b525aa82b8076c1a59d642c17b6e8739ecf852522c6321852178119d", - "sha256:b11a5d918a6216e521c715b02749240fb07ae5a1fefd4b7bf12f833bc8b4fe70", - "sha256:b1c8c20847b9f34e98080da785bb2336ea982e7f913eed5809e5a3c872900f32", - "sha256:b369d3db3c22ed14c75ccd5af429086f166a19627e84a8fdade3f8f31426e52a", - "sha256:b710bc2b8292966b23a6a0121f7a6c51d45d2347edcc75f016ac123b8054d3f2", - "sha256:bd96517ef76c8654446fc3db9242d019a1bb5fe8b751ba414765d59f99210b79", - "sha256:c00f323cc00576df6165cc9d21a4c21285fa6b9989c5c39830c3903dc4303ef3", - "sha256:c162b216070f280fa7da844531169be0baf9ccb17263cf5a8bf876fcd3117fa5", - "sha256:c1a69e58a6bb2de65902051d57fde951febad631a20a64572677a1052690482f", - "sha256:c1f794c02903c2824fccce5b20c339a1a14b114e83b306ff11b597c5f71a1c8d", - "sha256:c24037349665434f375645fa9d1f5304800cec574d0310f618490c871fd902b3", - "sha256:c300306673aa0f3ed5ed9372b21867690a17dba38c68c44b287437c362ce486b", - "sha256:c56a1d43b2f9ee4786e4658c7903f05da35b923fb53c11025712562d5cc02753", - "sha256:c6379f35350b655fd817cd0d6cbeef7f265f3ae5fedb1caae2eb442bbeae9ab9", - "sha256:c802e1c2ed9f0c06a65bc4ed0189d000ada8049312cfeab6ca635e39c9608957", - "sha256:cb83f8a875b3d9b458cada4f880fa498646874ba4011dc974e071a0a84a1b033", - "sha256:cf120cce539453ae086eacc0130a324e7026113510efa83ab42ef3fcfccac7fb", - "sha256:dd36439be765e2dde7660212b5275641edbc813e7b24668831a5c8ac91180656", - "sha256:dd5350b55f9fecddc51385463a4f67a5da829bc741e38cf689f38ec9023f54ab", - "sha256:df5c7333167b9674aa8ae1d4008fa4bc17a313cc490b2cca27838bbdcc6bb15b", - "sha256:e63601ad5cd8f860aa99d109889b5ac34de571c7ee902d6812d5d9ddcc77fa7d", - "sha256:e92ce66cd919d18d14b3856906a61d3f6b6a8500e0794142338da644260595cd", - "sha256:e99f5507401436fdcc85036a2e7dc2e28d962550afe1cbfc07c40e454256a859", - "sha256:ea2e2f6f801696ad7de8aec061044d6c8c0dd4037608c7cab38a9a4d316bfb11", - "sha256:eafa2c8658f4e560b098fe9fc54539f86528651f61849b22111a9b107d18910c", - "sha256:ecd4ad8453ac17bc7ba3868371bffb46f628161ad0eefbd0a855d2c8c32dd81a", - "sha256:ee70d08fd60c9565ba8190f41a46a54096afa0eeb8f76bd66f2c25d3b1b83005", - "sha256:eec1bb8cdbba2925bedc887bc0609a80e599c75b12d87ae42ac23fd199445654", - "sha256:ef0c1fe22171dd7c7c27147f2e9c3e86f8bdf473fed75f16b0c2e84a5030ce80", - "sha256:f2901429da1e645ce548bf9171784c0f74f0718c3f6150ce166be39e4dd66c3e", - "sha256:f422a209d2455c56849442ae42f25dbaaba1c6c3f501d58761c619c7836642ec", - "sha256:f65e5120863c2b266dbcc927b306c5b78e502c71edf3295dfcb9501ec96e5fc7", - "sha256:f7d4a670107d75dfe5ad080bed6c341d18c4442f9378c9f58e5851e86eb79965", - "sha256:f914c03e6a31deb632e2daa881fe198461f4d06e57ac3d0e05bbcab8eae01945", - "sha256:fb66442c2546446944437df74379e9cf9e9db353e61301d1a0e26482f43f0dd8" - ], - "markers": "python_version >= '3.6'", - "version": "==5.3.0" - }, "markdown": { "hashes": [ "sha256:225c6123522495d4119a90b3a3ba31a1e87a70369e03f14799ea9c0d7183a3d6", @@ -1421,11 +1206,11 @@ }, "opentelemetry-propagator-aws-xray": { "hashes": [ - "sha256:1c99181ee228e99bddb638a0c911a297fa21f1c3a0af951f841e79919b5f1934", - "sha256:6b2cee5479d2ef0172307b66ed2ed151f598a0fd29b3c01133ac87ca06326260" + "sha256:49267a1d72b3f04880ac75e24f9ef38fe323e2f3156c4531e0e00c71c0829c0f", + "sha256:6e8be667bbcf17c3d81d70b2a7cdec0b11257ff64d3829ffe75b810ba1b49f86" ], - "markers": "python_version >= '3.8'", - "version": "==1.0.2" + "markers": "python_version >= '3.6'", + "version": "==1.0.1" }, "opentelemetry-proto": { "hashes": [ @@ -1445,11 +1230,11 @@ }, "opentelemetry-sdk-extension-aws": { "hashes": [ - "sha256:4c6e4b9fec01a4a9cfeac5272ce5aae6bc80e080a6bae1e52098746f53a7b32d", - "sha256:9faa9bdf480d1c5c53151dabee75735c94dbde09e4762c68ff5c7bd4aa3408f3" + "sha256:dd7cf6fc0e7c8070dbe179348f2f194ca4555601b60efb7264d82fc8df53f4ba", + "sha256:f964b0598793ded268d3329c33829fad33f63a8d9299fe51bf3a743e81fd7c67" ], - "markers": "python_version >= '3.8'", - "version": "==2.0.2" + "markers": "python_version >= '3.6'", + "version": "==2.0.1" }, "opentelemetry-semantic-conventions": { "hashes": [ @@ -1467,13 +1252,6 @@ "markers": "python_version >= '3.7'", "version": "==0.43b0" }, - "oscrypto": { - "hashes": [ - "sha256:2b2f1d2d42ec152ca90ccb5682f3e051fb55986e1b170ebde472b133713e7085", - "sha256:6f5fef59cb5b3708321db7cca56aed8ad7e662853351e7991fcf60ec606d47a4" - ], - "version": "==1.3.0" - }, "packaging": { "hashes": [ "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", @@ -1482,14 +1260,6 @@ "markers": "python_version >= '3.8'", "version": "==24.1" }, - "paramiko": { - "hashes": [ - "sha256:8b15302870af7f6652f2e038975c1d2973f06046cb5d7d65355668b3ecbece0c", - "sha256:8e49fd2f82f84acf7ffd57c64311aa2b30e575370dc23bdb375b10262f7eac32" - ], - "markers": "python_version >= '3.6'", - "version": "==3.4.1" - }, "parso": { "hashes": [ "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", @@ -1607,11 +1377,11 @@ }, "pre-commit": { "hashes": [ - "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af", - "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f" + "sha256:8ca3ad567bc78a4972a3f1a477e94a79d4597e8140a6e0b651c5e33899c3654a", + "sha256:fae36fd1d7ad7d6a5a1c0b0d5adb2ed1a3bda5a21bf6c3e5372073d7a11cd4c5" ], "markers": "python_version >= '3.9'", - "version": "==3.8.0" + "version": "==3.7.1" }, "prompt-toolkit": { "hashes": [ @@ -1640,12 +1410,12 @@ }, "psycopg": { "hashes": [ - "sha256:32f5862ab79f238496236f97fe374a7ab55b4b4bb839a74802026544735f9a07", - "sha256:898a29f49ac9c903d554f5a6cdc44a8fc564325557c18f82e51f39c1f4fc2aeb" + "sha256:92d7b78ad82426cdcf1a0440678209faa890c6e1721361c2f8901f0dccd62961", + "sha256:dca5e5521c859f6606686432ae1c94e8766d29cc91f2ee595378c510cc5b0731" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==3.1.20" + "version": "==3.1.19" }, "ptyprocess": { "hashes": [ @@ -1656,11 +1426,11 @@ }, "pycodestyle": { "hashes": [ - "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3", - "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521" + "sha256:442f950141b4f43df752dd303511ffded3a04c2b6fb7f65980574f0c31e6e79c", + "sha256:949a39f6b86c3e1515ba1787c2022131d165a8ad271b11370a8819aa070269e4" ], "markers": "python_version >= '3.8'", - "version": "==2.12.1" + "version": "==2.12.0" }, "pycparser": { "hashes": [ @@ -1697,11 +1467,11 @@ }, "pyphen": { "hashes": [ - "sha256:2c006b3ddf072c9571ab97606d9ab3c26a92eaced4c0d59fd1d26988f308f413", - "sha256:b4a4c6d7d5654b698b5fc68123148bb799b3debe0175d1d5dc3edfe93066fc4c" + "sha256:999b430916ab42ae9912537cd95c074e0c6691e89a9d05999f9b610a68f34858", + "sha256:a430623decac53dc3691241253263cba36b9dd7a44ffd2680b706af368cda2f2" ], "markers": "python_version >= '3.8'", - "version": "==0.16.0" + "version": "==0.15.0" }, "python-dateutil": { "hashes": [ @@ -1711,13 +1481,6 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==2.9.0.post0" }, - "python-pkcs11": { - "hashes": [ - "sha256:9737e0c24cabb8bc9d48bf8c57c3df2a70f8cdd96b70c50290803286f9e46bf7" - ], - "index": "pypi", - "version": "==0.7.0" - }, "pytz": { "hashes": [ "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a", @@ -1728,62 +1491,60 @@ }, "pyyaml": { "hashes": [ - "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", - "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", - "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", - "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", - "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", - "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", - "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", - "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", - "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", - "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", - "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", - "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", - "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", - "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", - "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", - "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", - "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", - "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", - "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", - "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", - "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", - "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", - "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", - "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", - "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", - "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", - "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", - "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", - "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", - "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", - "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", - "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", - "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", - "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", - "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", - "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", - "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", - "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", - "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", - "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", - "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", - "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", - "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", - "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", - "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", - "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", - "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", - "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", - "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", - "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", - "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", - "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", - "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" - ], - "markers": "python_version >= '3.8'", - "version": "==6.0.2" + "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5", + "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc", + "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df", + "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741", + "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206", + "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27", + "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595", + "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62", + "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98", + "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696", + "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290", + "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9", + "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d", + "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6", + "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867", + "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47", + "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486", + "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6", + "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3", + "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007", + "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938", + "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0", + "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c", + "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735", + "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d", + "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28", + "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4", + "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba", + "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8", + "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef", + "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5", + "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd", + "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3", + "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0", + "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515", + "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c", + "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c", + "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924", + "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34", + "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43", + "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859", + "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673", + "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54", + "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a", + "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b", + "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab", + "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa", + "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c", + "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585", + "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d", + "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f" + ], + "markers": "python_version >= '3.6'", + "version": "==6.0.1" }, "redis": { "hashes": [ @@ -2339,12 +2100,12 @@ }, "certifi": { "hashes": [ - "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b", - "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90" + "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516", + "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56" ], "index": "pypi", "markers": "python_version >= '3.6'", - "version": "==2024.7.4" + "version": "==2024.6.2" }, "cffi": { "hashes": [ @@ -2691,11 +2452,11 @@ }, "exceptiongroup": { "hashes": [ - "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", - "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" + "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad", + "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16" ], "markers": "python_version < '3.11'", - "version": "==1.2.2" + "version": "==1.2.1" }, "freezegun": { "hashes": [ @@ -3073,11 +2834,11 @@ }, "pycodestyle": { "hashes": [ - "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3", - "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521" + "sha256:442f950141b4f43df752dd303511ffded3a04c2b6fb7f65980574f0c31e6e79c", + "sha256:949a39f6b86c3e1515ba1787c2022131d165a8ad271b11370a8819aa070269e4" ], "markers": "python_version >= '3.8'", - "version": "==2.12.1" + "version": "==2.12.0" }, "pycparser": { "hashes": [ @@ -3200,62 +2961,60 @@ }, "pyyaml": { "hashes": [ - "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", - "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", - "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", - "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", - "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", - "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", - "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", - "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", - "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", - "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", - "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", - "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", - "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", - "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", - "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", - "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", - "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", - "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", - "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", - "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", - "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", - "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", - "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", - "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", - "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", - "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", - "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", - "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", - "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", - "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", - "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", - "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", - "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", - "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", - "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", - "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", - "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", - "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", - "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", - "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", - "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", - "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", - "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", - "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", - "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", - "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", - "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", - "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", - "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", - "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", - "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", - "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", - "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" - ], - "markers": "python_version >= '3.8'", - "version": "==6.0.2" + "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5", + "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc", + "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df", + "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741", + "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206", + "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27", + "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595", + "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62", + "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98", + "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696", + "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290", + "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9", + "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d", + "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6", + "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867", + "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47", + "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486", + "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6", + "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3", + "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007", + "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938", + "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0", + "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c", + "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735", + "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d", + "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28", + "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4", + "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba", + "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8", + "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef", + "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5", + "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd", + "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3", + "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0", + "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515", + "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c", + "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c", + "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924", + "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34", + "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43", + "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859", + "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673", + "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54", + "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a", + "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b", + "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab", + "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa", + "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c", + "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585", + "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d", + "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f" + ], + "markers": "python_version >= '3.6'", + "version": "==6.0.1" }, "referencing": { "hashes": [ From 6ee2223775f8ad76e2c1e5a5d3143ac788710b58 Mon Sep 17 00:00:00 2001 From: James Francis Date: Thu, 12 Sep 2024 13:56:52 +0100 Subject: [PATCH 04/86] update pipfile lock to match pipfile --- Pipfile.lock | 322 ++++++++++++++++++++++++++++----------------------- 1 file changed, 174 insertions(+), 148 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index f733d9947e..0274b273ac 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -25,6 +25,14 @@ "markers": "python_version >= '3.6'", "version": "==5.2.0" }, + "appnope": { + "hashes": [ + "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", + "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c" + ], + "markers": "sys_platform == 'darwin'", + "version": "==0.1.4" + }, "asgiref": { "hashes": [ "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47", @@ -33,6 +41,13 @@ "markers": "python_version >= '3.8'", "version": "==3.8.1" }, + "asn1crypto": { + "hashes": [ + "sha256:13ae38502be632115abf8a24cbe5f4da52e3b5231990aff31123c805306ccb9c", + "sha256:db4e40728b728508912cbb3d44f19ce188f218e9eba635821bb4b68564f8fd67" + ], + "version": "==1.5.1" + }, "async-timeout": { "hashes": [ "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", @@ -89,6 +104,13 @@ "markers": "python_version >= '3.7'", "version": "==1.29.165" }, + "cached-property": { + "hashes": [ + "sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130", + "sha256:df4f613cf7ad9a588cc381aaf4a512d26265ecebd5eb9e1ba12f1319eb85a6a0" + ], + "version": "==1.5.2" + }, "cairocffi": { "hashes": [ "sha256:2e48ee864884ec4a3a34bfa8c9ab9999f688286eb714a15a43ec9d068c36557b", @@ -116,12 +138,12 @@ }, "certifi": { "hashes": [ - "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b", - "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90" + "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", + "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9" ], "index": "pypi", "markers": "python_version >= '3.6'", - "version": "==2024.7.4" + "version": "==2024.8.30" }, "cffi": { "hashes": [ @@ -584,20 +606,20 @@ }, "django-queryable-properties": { "hashes": [ - "sha256:68f3ed8cd6f03fb2993eabe1c3235091781f01266397b75319e1e20556991d7f", - "sha256:f272d5b68be3bd3a57004dcbe1f849ba5080a97069ff0f0f858c364a9eafedb6" + "sha256:9a2d35ea6cd33f80ac666f62009006a2373bcfbfc720981a60a9a428585659d1", + "sha256:aaec7d3ea9dc3be44e6114ca1ca705ac0e23b00c5209832aeb1c6ab5c4e9c345" ], "index": "pypi", - "version": "==1.9.2" + "version": "==1.9.3" }, "django-reversion": { "hashes": [ - "sha256:5884e9f77f55c341b3f0a8d3b0af000f060530653776997267c8b1e5349d8fee", - "sha256:c047cc99a9f1ba4aae6db89c3ac243478d6de98ec8a60c7073fcc875d89c5cdb" + "sha256:084d4f117d9e2b4e8dfdfaad83ebb34410a03eed6071c96089e6811fdea82ad3", + "sha256:3309821e5b6fceedcce6b6975f1a9c7fab6ae7c7d0e1276a90e345946fa0dcb8" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==5.0.12" + "markers": "python_version >= '3.8'", + "version": "==5.1.0" }, "django-silk": { "hashes": [ @@ -1206,11 +1228,11 @@ }, "opentelemetry-propagator-aws-xray": { "hashes": [ - "sha256:49267a1d72b3f04880ac75e24f9ef38fe323e2f3156c4531e0e00c71c0829c0f", - "sha256:6e8be667bbcf17c3d81d70b2a7cdec0b11257ff64d3829ffe75b810ba1b49f86" + "sha256:1c99181ee228e99bddb638a0c911a297fa21f1c3a0af951f841e79919b5f1934", + "sha256:6b2cee5479d2ef0172307b66ed2ed151f598a0fd29b3c01133ac87ca06326260" ], - "markers": "python_version >= '3.6'", - "version": "==1.0.1" + "markers": "python_version >= '3.8'", + "version": "==1.0.2" }, "opentelemetry-proto": { "hashes": [ @@ -1230,11 +1252,11 @@ }, "opentelemetry-sdk-extension-aws": { "hashes": [ - "sha256:dd7cf6fc0e7c8070dbe179348f2f194ca4555601b60efb7264d82fc8df53f4ba", - "sha256:f964b0598793ded268d3329c33829fad33f63a8d9299fe51bf3a743e81fd7c67" + "sha256:4c6e4b9fec01a4a9cfeac5272ce5aae6bc80e080a6bae1e52098746f53a7b32d", + "sha256:9faa9bdf480d1c5c53151dabee75735c94dbde09e4762c68ff5c7bd4aa3408f3" ], - "markers": "python_version >= '3.6'", - "version": "==2.0.1" + "markers": "python_version >= '3.8'", + "version": "==2.0.2" }, "opentelemetry-semantic-conventions": { "hashes": [ @@ -1377,11 +1399,11 @@ }, "pre-commit": { "hashes": [ - "sha256:8ca3ad567bc78a4972a3f1a477e94a79d4597e8140a6e0b651c5e33899c3654a", - "sha256:fae36fd1d7ad7d6a5a1c0b0d5adb2ed1a3bda5a21bf6c3e5372073d7a11cd4c5" + "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af", + "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f" ], "markers": "python_version >= '3.9'", - "version": "==3.7.1" + "version": "==3.8.0" }, "prompt-toolkit": { "hashes": [ @@ -1410,12 +1432,12 @@ }, "psycopg": { "hashes": [ - "sha256:92d7b78ad82426cdcf1a0440678209faa890c6e1721361c2f8901f0dccd62961", - "sha256:dca5e5521c859f6606686432ae1c94e8766d29cc91f2ee595378c510cc5b0731" + "sha256:32f5862ab79f238496236f97fe374a7ab55b4b4bb839a74802026544735f9a07", + "sha256:898a29f49ac9c903d554f5a6cdc44a8fc564325557c18f82e51f39c1f4fc2aeb" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==3.1.19" + "version": "==3.1.20" }, "ptyprocess": { "hashes": [ @@ -1426,11 +1448,11 @@ }, "pycodestyle": { "hashes": [ - "sha256:442f950141b4f43df752dd303511ffded3a04c2b6fb7f65980574f0c31e6e79c", - "sha256:949a39f6b86c3e1515ba1787c2022131d165a8ad271b11370a8819aa070269e4" + "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3", + "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521" ], "markers": "python_version >= '3.8'", - "version": "==2.12.0" + "version": "==2.12.1" }, "pycparser": { "hashes": [ @@ -1467,11 +1489,11 @@ }, "pyphen": { "hashes": [ - "sha256:999b430916ab42ae9912537cd95c074e0c6691e89a9d05999f9b610a68f34858", - "sha256:a430623decac53dc3691241253263cba36b9dd7a44ffd2680b706af368cda2f2" + "sha256:2c006b3ddf072c9571ab97606d9ab3c26a92eaced4c0d59fd1d26988f308f413", + "sha256:b4a4c6d7d5654b698b5fc68123148bb799b3debe0175d1d5dc3edfe93066fc4c" ], "markers": "python_version >= '3.8'", - "version": "==0.15.0" + "version": "==0.16.0" }, "python-dateutil": { "hashes": [ @@ -1481,7 +1503,7 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==2.9.0.post0" }, - "pytz": { + "python-pkcs11": { "hashes": [ "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a", "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725" @@ -1491,60 +1513,62 @@ }, "pyyaml": { "hashes": [ - "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5", - "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc", - "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df", - "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741", - "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206", - "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27", - "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595", - "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62", - "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98", - "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696", - "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290", - "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9", - "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d", - "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6", - "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867", - "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47", - "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486", - "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6", - "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3", - "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007", - "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938", - "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0", - "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c", - "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735", - "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d", - "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28", - "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4", - "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba", - "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8", - "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef", - "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5", - "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd", - "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3", - "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0", - "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515", - "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c", - "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c", - "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924", - "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34", - "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43", - "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859", - "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673", - "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54", - "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a", - "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b", - "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab", - "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa", - "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c", - "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585", - "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d", - "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f" - ], - "markers": "python_version >= '3.6'", - "version": "==6.0.1" + "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", + "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", + "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", + "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", + "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", + "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", + "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", + "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", + "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", + "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", + "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", + "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", + "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", + "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", + "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", + "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", + "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", + "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", + "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", + "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", + "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", + "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", + "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", + "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", + "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", + "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", + "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", + "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", + "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", + "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", + "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", + "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", + "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", + "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", + "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", + "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", + "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", + "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", + "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", + "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", + "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", + "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", + "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", + "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", + "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", + "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", + "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", + "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", + "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", + "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", + "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", + "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", + "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" + ], + "markers": "python_version >= '3.8'", + "version": "==6.0.2" }, "redis": { "hashes": [ @@ -2100,12 +2124,12 @@ }, "certifi": { "hashes": [ - "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516", - "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56" + "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", + "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9" ], "index": "pypi", "markers": "python_version >= '3.6'", - "version": "==2024.6.2" + "version": "==2024.8.30" }, "cffi": { "hashes": [ @@ -2452,11 +2476,11 @@ }, "exceptiongroup": { "hashes": [ - "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad", - "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16" + "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", + "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" ], "markers": "python_version < '3.11'", - "version": "==1.2.1" + "version": "==1.2.2" }, "freezegun": { "hashes": [ @@ -2834,11 +2858,11 @@ }, "pycodestyle": { "hashes": [ - "sha256:442f950141b4f43df752dd303511ffded3a04c2b6fb7f65980574f0c31e6e79c", - "sha256:949a39f6b86c3e1515ba1787c2022131d165a8ad271b11370a8819aa070269e4" + "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3", + "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521" ], "markers": "python_version >= '3.8'", - "version": "==2.12.0" + "version": "==2.12.1" }, "pycparser": { "hashes": [ @@ -2961,60 +2985,62 @@ }, "pyyaml": { "hashes": [ - "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5", - "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc", - "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df", - "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741", - "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206", - "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27", - "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595", - "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62", - "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98", - "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696", - "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290", - "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9", - "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d", - "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6", - "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867", - "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47", - "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486", - "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6", - "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3", - "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007", - "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938", - "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0", - "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c", - "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735", - "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d", - "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28", - "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4", - "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba", - "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8", - "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef", - "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5", - "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd", - "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3", - "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0", - "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515", - "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c", - "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c", - "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924", - "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34", - "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43", - "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859", - "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673", - "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54", - "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a", - "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b", - "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab", - "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa", - "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c", - "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585", - "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d", - "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f" - ], - "markers": "python_version >= '3.6'", - "version": "==6.0.1" + "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", + "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", + "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", + "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", + "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", + "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", + "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", + "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", + "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", + "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", + "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", + "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", + "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", + "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", + "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", + "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", + "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", + "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", + "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", + "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", + "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", + "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", + "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", + "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", + "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", + "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", + "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", + "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", + "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", + "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", + "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", + "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", + "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", + "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", + "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", + "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", + "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", + "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", + "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", + "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", + "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", + "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", + "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", + "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", + "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", + "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", + "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", + "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", + "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", + "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", + "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", + "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", + "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" + ], + "markers": "python_version >= '3.8'", + "version": "==6.0.2" }, "referencing": { "hashes": [ From 386ac9ec59584a8efa7966e1ad1e028575461528 Mon Sep 17 00:00:00 2001 From: Emile Swarts Date: Fri, 13 Sep 2024 10:26:21 +0100 Subject: [PATCH 05/86] Add endesive dependency only on DBT Platform --- .copilot/phases/pre_build.sh | 49 +++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/.copilot/phases/pre_build.sh b/.copilot/phases/pre_build.sh index aa0c045dbd..9a750d76bf 100644 --- a/.copilot/phases/pre_build.sh +++ b/.copilot/phases/pre_build.sh @@ -3,23 +3,36 @@ # Exit early if something goes wrong set -e -git_clone_base_url="https://codestar-connections.eu-west-2.amazonaws.com/git-http/730335529260/eu-west-2/192881c6-e3f2-41a9-9dcb-fcc87d8b90be/uktrade" - -git config --global credential.helper '!aws codecommit credential-helper $@' -git config --global credential.UseHttpPath true - -cat < ./.gitmodules -[submodule "lite-content"] - path = lite_content - url = $git_clone_base_url/lite-content.git - branch = master -[submodule "lite_routing"] - path = lite_routing - url = $git_clone_base_url/lite-routing.git - branch = main -[submodule "django_db_anonymiser"] - path = django_db_anonymiser - url = $git_clone_base_url/django-db-anonymiser.git +update_git_submodules() {} + git_clone_base_url="https://codestar-connections.eu-west-2.amazonaws.com/git-http/730335529260/eu-west-2/192881c6-e3f2-41a9-9dcb-fcc87d8b90be/uktrade" + + git config --global credential.helper '!aws codecommit credential-helper $@' + git config --global credential.UseHttpPath true + + cat < ./.gitmodules + [submodule "lite-content"] + path = lite_content + url = $git_clone_base_url/lite-content.git + branch = master + [submodule "lite_routing"] + path = lite_routing + url = $git_clone_base_url/lite-routing.git + branch = main + [submodule "django_db_anonymiser"] + path = django_db_anonymiser + url = $git_clone_base_url/django-db-anonymiser.git EOF -git submodule update --init --remote --recursive + git submodule update --init --remote --recursive +} + +update_pip_file_for_dbt_platform() { + sed -i 's/\[packages\]/[packages]\nendesive = "~=1.5.9"/' Pipfile +} + +main() { + update_git_submodules + update_pip_file_for_dbt_platform +} + +main \ No newline at end of file From b1ab42f54a22cef88cc445ea26b31afbf471db6f Mon Sep 17 00:00:00 2001 From: Emile Swarts Date: Fri, 13 Sep 2024 10:28:48 +0100 Subject: [PATCH 06/86] Only insert dependencies at build time for DBT Platform --- .copilot/phases/pre_build.sh | 2 +- Pipfile.lock | 630 ++++++++++++++++------------------- 2 files changed, 288 insertions(+), 344 deletions(-) diff --git a/.copilot/phases/pre_build.sh b/.copilot/phases/pre_build.sh index 9a750d76bf..8440c07e4e 100644 --- a/.copilot/phases/pre_build.sh +++ b/.copilot/phases/pre_build.sh @@ -27,7 +27,7 @@ EOF } update_pip_file_for_dbt_platform() { - sed -i 's/\[packages\]/[packages]\nendesive = "~=1.5.9"/' Pipfile + sed -i 's/\[packages\]/[packages]\nendesive = "~=1.5.9"\npython-pkcs11 = "~=0.7.0"\npykcs11 = "~=1.4.4"\n/' Pipfile } main() { diff --git a/Pipfile.lock b/Pipfile.lock index 0274b273ac..68819c16e2 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -25,14 +25,6 @@ "markers": "python_version >= '3.6'", "version": "==5.2.0" }, - "appnope": { - "hashes": [ - "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", - "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c" - ], - "markers": "sys_platform == 'darwin'", - "version": "==0.1.4" - }, "asgiref": { "hashes": [ "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47", @@ -41,13 +33,6 @@ "markers": "python_version >= '3.8'", "version": "==3.8.1" }, - "asn1crypto": { - "hashes": [ - "sha256:13ae38502be632115abf8a24cbe5f4da52e3b5231990aff31123c805306ccb9c", - "sha256:db4e40728b728508912cbb3d44f19ce188f218e9eba635821bb4b68564f8fd67" - ], - "version": "==1.5.1" - }, "async-timeout": { "hashes": [ "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", @@ -104,13 +89,6 @@ "markers": "python_version >= '3.7'", "version": "==1.29.165" }, - "cached-property": { - "hashes": [ - "sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130", - "sha256:df4f613cf7ad9a588cc381aaf4a512d26265ecebd5eb9e1ba12f1319eb85a6a0" - ], - "version": "==1.5.2" - }, "cairocffi": { "hashes": [ "sha256:2e48ee864884ec4a3a34bfa8c9ab9999f688286eb714a15a43ec9d068c36557b", @@ -138,85 +116,70 @@ }, "certifi": { "hashes": [ - "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", - "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9" + "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b", + "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90" ], "index": "pypi", "markers": "python_version >= '3.6'", - "version": "==2024.8.30" + "version": "==2024.7.4" }, "cffi": { "hashes": [ - "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", - "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", - "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1", - "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", - "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", - "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", - "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8", - "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36", - "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", - "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", - "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc", - "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", - "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", - "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", - "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", - "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", - "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", - "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", - "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", - "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b", - "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", - "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", - "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c", - "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", - "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", - "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", - "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8", - "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1", - "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", - "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", - "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", - "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595", - "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0", - "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", - "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", - "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", - "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", - "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", - "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", - "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16", - "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", - "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e", - "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", - "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964", - "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", - "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576", - "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", - "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3", - "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662", - "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", - "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", - "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", - "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", - "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", - "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", - "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", - "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", - "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9", - "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7", - "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", - "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a", - "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", - "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", - "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", - "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", - "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87", - "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b" - ], - "markers": "python_version >= '3.8'", - "version": "==1.17.1" + "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc", + "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a", + "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417", + "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab", + "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520", + "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36", + "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743", + "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8", + "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed", + "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684", + "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56", + "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324", + "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d", + "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235", + "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e", + "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088", + "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000", + "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7", + "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e", + "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673", + "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c", + "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe", + "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2", + "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098", + "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8", + "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a", + "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0", + "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b", + "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896", + "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e", + "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9", + "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2", + "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b", + "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6", + "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404", + "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f", + "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0", + "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4", + "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc", + "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936", + "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba", + "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872", + "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb", + "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614", + "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1", + "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d", + "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969", + "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b", + "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4", + "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627", + "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956", + "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357" + ], + "markers": "python_version >= '3.8'", + "version": "==1.16.0" }, "cfgv": { "hashes": [ @@ -477,12 +440,12 @@ }, "django": { "hashes": [ - "sha256:1ddc333a16fc139fd253035a1606bb24261951bbc3a6ca256717fa06cc41a898", - "sha256:6f1616c2786c408ce86ab7e10f792b8f15742f7b7b7460243929cb371e7f1dad" + "sha256:61ee4a130efb8c451ef3467c67ca99fdce400fedd768634efc86a68c18d80d30", + "sha256:c77f926b81129493961e19c0e02188f8d07c112a1162df69bfab178ae447f94a" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.2.16" + "version": "==4.2.15" }, "django-activity-stream": { "hashes": [ @@ -606,20 +569,20 @@ }, "django-queryable-properties": { "hashes": [ - "sha256:9a2d35ea6cd33f80ac666f62009006a2373bcfbfc720981a60a9a428585659d1", - "sha256:aaec7d3ea9dc3be44e6114ca1ca705ac0e23b00c5209832aeb1c6ab5c4e9c345" + "sha256:68f3ed8cd6f03fb2993eabe1c3235091781f01266397b75319e1e20556991d7f", + "sha256:f272d5b68be3bd3a57004dcbe1f849ba5080a97069ff0f0f858c364a9eafedb6" ], "index": "pypi", - "version": "==1.9.3" + "version": "==1.9.2" }, "django-reversion": { "hashes": [ - "sha256:084d4f117d9e2b4e8dfdfaad83ebb34410a03eed6071c96089e6811fdea82ad3", - "sha256:3309821e5b6fceedcce6b6975f1a9c7fab6ae7c7d0e1276a90e345946fa0dcb8" + "sha256:5884e9f77f55c341b3f0a8d3b0af000f060530653776997267c8b1e5349d8fee", + "sha256:c047cc99a9f1ba4aae6db89c3ac243478d6de98ec8a60c7073fcc875d89c5cdb" ], "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==5.1.0" + "markers": "python_version >= '3.7'", + "version": "==5.0.12" }, "django-silk": { "hashes": [ @@ -823,11 +786,11 @@ }, "googleapis-common-protos": { "hashes": [ - "sha256:2972e6c496f435b92590fd54045060867f3fe9be2c82ab148fc8885035479a63", - "sha256:334a29d07cddc3aa01dee4988f9afd9b2916ee2ff49d6b757155dc0d197852c0" + "sha256:0e1c2cdfcbc354b76e4a211a35ea35d6926a835cba1377073c4861db904a1877", + "sha256:c6442f7a0a6b2a80369457d79e6672bb7dcbaab88e0848302497e3ec80780a6a" ], "markers": "python_version >= '3.7'", - "version": "==1.65.0" + "version": "==1.63.1" }, "gprof2dot": { "hashes": [ @@ -1228,11 +1191,11 @@ }, "opentelemetry-propagator-aws-xray": { "hashes": [ - "sha256:1c99181ee228e99bddb638a0c911a297fa21f1c3a0af951f841e79919b5f1934", - "sha256:6b2cee5479d2ef0172307b66ed2ed151f598a0fd29b3c01133ac87ca06326260" + "sha256:49267a1d72b3f04880ac75e24f9ef38fe323e2f3156c4531e0e00c71c0829c0f", + "sha256:6e8be667bbcf17c3d81d70b2a7cdec0b11257ff64d3829ffe75b810ba1b49f86" ], - "markers": "python_version >= '3.8'", - "version": "==1.0.2" + "markers": "python_version >= '3.6'", + "version": "==1.0.1" }, "opentelemetry-proto": { "hashes": [ @@ -1252,11 +1215,11 @@ }, "opentelemetry-sdk-extension-aws": { "hashes": [ - "sha256:4c6e4b9fec01a4a9cfeac5272ce5aae6bc80e080a6bae1e52098746f53a7b32d", - "sha256:9faa9bdf480d1c5c53151dabee75735c94dbde09e4762c68ff5c7bd4aa3408f3" + "sha256:dd7cf6fc0e7c8070dbe179348f2f194ca4555601b60efb7264d82fc8df53f4ba", + "sha256:f964b0598793ded268d3329c33829fad33f63a8d9299fe51bf3a743e81fd7c67" ], - "markers": "python_version >= '3.8'", - "version": "==2.0.2" + "markers": "python_version >= '3.6'", + "version": "==2.0.1" }, "opentelemetry-semantic-conventions": { "hashes": [ @@ -1399,11 +1362,11 @@ }, "pre-commit": { "hashes": [ - "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af", - "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f" + "sha256:8ca3ad567bc78a4972a3f1a477e94a79d4597e8140a6e0b651c5e33899c3654a", + "sha256:fae36fd1d7ad7d6a5a1c0b0d5adb2ed1a3bda5a21bf6c3e5372073d7a11cd4c5" ], "markers": "python_version >= '3.9'", - "version": "==3.8.0" + "version": "==3.7.1" }, "prompt-toolkit": { "hashes": [ @@ -1432,12 +1395,12 @@ }, "psycopg": { "hashes": [ - "sha256:32f5862ab79f238496236f97fe374a7ab55b4b4bb839a74802026544735f9a07", - "sha256:898a29f49ac9c903d554f5a6cdc44a8fc564325557c18f82e51f39c1f4fc2aeb" + "sha256:92d7b78ad82426cdcf1a0440678209faa890c6e1721361c2f8901f0dccd62961", + "sha256:dca5e5521c859f6606686432ae1c94e8766d29cc91f2ee595378c510cc5b0731" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==3.1.20" + "version": "==3.1.19" }, "ptyprocess": { "hashes": [ @@ -1448,11 +1411,11 @@ }, "pycodestyle": { "hashes": [ - "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3", - "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521" + "sha256:442f950141b4f43df752dd303511ffded3a04c2b6fb7f65980574f0c31e6e79c", + "sha256:949a39f6b86c3e1515ba1787c2022131d165a8ad271b11370a8819aa070269e4" ], "markers": "python_version >= '3.8'", - "version": "==2.12.1" + "version": "==2.12.0" }, "pycparser": { "hashes": [ @@ -1472,8 +1435,8 @@ }, "pyjwt": { "hashes": [ - "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850", - "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c" + "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de", + "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320" ], "markers": "python_version >= '3.8'", "version": "==2.9.0" @@ -1489,11 +1452,11 @@ }, "pyphen": { "hashes": [ - "sha256:2c006b3ddf072c9571ab97606d9ab3c26a92eaced4c0d59fd1d26988f308f413", - "sha256:b4a4c6d7d5654b698b5fc68123148bb799b3debe0175d1d5dc3edfe93066fc4c" + "sha256:999b430916ab42ae9912537cd95c074e0c6691e89a9d05999f9b610a68f34858", + "sha256:a430623decac53dc3691241253263cba36b9dd7a44ffd2680b706af368cda2f2" ], "markers": "python_version >= '3.8'", - "version": "==0.16.0" + "version": "==0.15.0" }, "python-dateutil": { "hashes": [ @@ -1503,7 +1466,7 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==2.9.0.post0" }, - "python-pkcs11": { + "pytz": { "hashes": [ "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a", "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725" @@ -1513,62 +1476,60 @@ }, "pyyaml": { "hashes": [ - "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", - "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", - "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", - "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", - "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", - "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", - "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", - "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", - "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", - "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", - "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", - "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", - "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", - "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", - "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", - "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", - "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", - "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", - "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", - "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", - "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", - "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", - "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", - "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", - "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", - "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", - "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", - "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", - "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", - "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", - "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", - "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", - "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", - "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", - "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", - "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", - "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", - "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", - "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", - "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", - "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", - "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", - "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", - "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", - "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", - "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", - "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", - "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", - "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", - "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", - "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", - "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", - "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" - ], - "markers": "python_version >= '3.8'", - "version": "==6.0.2" + "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5", + "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc", + "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df", + "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741", + "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206", + "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27", + "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595", + "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62", + "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98", + "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696", + "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290", + "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9", + "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d", + "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6", + "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867", + "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47", + "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486", + "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6", + "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3", + "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007", + "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938", + "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0", + "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c", + "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735", + "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d", + "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28", + "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4", + "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba", + "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8", + "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef", + "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5", + "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd", + "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3", + "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0", + "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515", + "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c", + "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c", + "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924", + "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34", + "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43", + "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859", + "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673", + "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54", + "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a", + "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b", + "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab", + "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa", + "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c", + "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585", + "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d", + "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f" + ], + "markers": "python_version >= '3.6'", + "version": "==6.0.1" }, "redis": { "hashes": [ @@ -1829,11 +1790,11 @@ }, "urllib3": { "hashes": [ - "sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e", - "sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32" + "sha256:37a0344459b199fce0e80b0d3569837ec6b6937435c5244e7fd73fa6006830f3", + "sha256:3e3d753a8618b86d7de333b4223005f68720bcd6a7d2bcb9fbd2229ec7c1e429" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==1.26.20" + "version": "==1.26.19" }, "vine": { "hashes": [ @@ -2124,85 +2085,70 @@ }, "certifi": { "hashes": [ - "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", - "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9" + "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516", + "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56" ], "index": "pypi", "markers": "python_version >= '3.6'", - "version": "==2024.8.30" + "version": "==2024.6.2" }, "cffi": { "hashes": [ - "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", - "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", - "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1", - "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", - "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", - "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", - "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8", - "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36", - "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", - "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", - "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc", - "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", - "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", - "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", - "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", - "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", - "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", - "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", - "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", - "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b", - "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", - "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", - "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c", - "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", - "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", - "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", - "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8", - "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1", - "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", - "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", - "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", - "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595", - "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0", - "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", - "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", - "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", - "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", - "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", - "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", - "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16", - "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", - "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e", - "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", - "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964", - "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", - "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576", - "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", - "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3", - "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662", - "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", - "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", - "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", - "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", - "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", - "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", - "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", - "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", - "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9", - "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7", - "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", - "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a", - "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", - "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", - "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", - "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", - "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87", - "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b" - ], - "markers": "python_version >= '3.8'", - "version": "==1.17.1" + "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc", + "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a", + "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417", + "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab", + "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520", + "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36", + "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743", + "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8", + "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed", + "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684", + "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56", + "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324", + "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d", + "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235", + "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e", + "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088", + "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000", + "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7", + "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e", + "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673", + "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c", + "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe", + "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2", + "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098", + "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8", + "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a", + "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0", + "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b", + "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896", + "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e", + "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9", + "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2", + "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b", + "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6", + "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404", + "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f", + "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0", + "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4", + "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc", + "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936", + "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba", + "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872", + "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb", + "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614", + "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1", + "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d", + "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969", + "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b", + "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4", + "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627", + "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956", + "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357" + ], + "markers": "python_version >= '3.8'", + "version": "==1.16.0" }, "charset-normalizer": { "hashes": [ @@ -2476,11 +2422,11 @@ }, "exceptiongroup": { "hashes": [ - "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", - "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" + "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad", + "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16" ], "markers": "python_version < '3.11'", - "version": "==1.2.2" + "version": "==1.2.1" }, "freezegun": { "hashes": [ @@ -2783,11 +2729,11 @@ }, "pbr": { "hashes": [ - "sha256:788183e382e3d1d7707db08978239965e8b9e4e5ed42669bf4758186734d5f24", - "sha256:a776ae228892d8013649c0aeccbb3d5f99ee15e005a4cbb7e61d55a067b28a2a" + "sha256:4a7317d5e3b17a3dccb6a8cfe67dab65b20551404c52c8ed41279fa4f0cb4cda", + "sha256:d1377122a5a00e2f940ee482999518efe16d745d423a670c27773dfbc3c9a7d9" ], "markers": "python_version >= '2.6'", - "version": "==6.1.0" + "version": "==6.0.0" }, "pep8-naming": { "hashes": [ @@ -2858,11 +2804,11 @@ }, "pycodestyle": { "hashes": [ - "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3", - "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521" + "sha256:442f950141b4f43df752dd303511ffded3a04c2b6fb7f65980574f0c31e6e79c", + "sha256:949a39f6b86c3e1515ba1787c2022131d165a8ad271b11370a8819aa070269e4" ], "markers": "python_version >= '3.8'", - "version": "==2.12.1" + "version": "==2.12.0" }, "pycparser": { "hashes": [ @@ -2933,12 +2879,12 @@ }, "pytest": { "hashes": [ - "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", - "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2" + "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343", + "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==8.3.3" + "version": "==8.2.2" }, "pytest-bdd": { "hashes": [ @@ -2968,12 +2914,12 @@ }, "pytest-django": { "hashes": [ - "sha256:1d83692cb39188682dbb419ff0393867e9904094a549a7d38a3154d5731b2b99", - "sha256:8bf7bc358c9ae6f6fc51b6cebb190fe20212196e6807121f11bd6a3b03428314" + "sha256:5d054fe011c56f3b10f978f41a8efb2e5adfc7e680ef36fb571ada1f24779d90", + "sha256:ca1ddd1e0e4c227cf9e3e40a6afc6d106b3e70868fd2ac5798a22501271cd0c7" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.9.0" + "version": "==4.8.0" }, "python-dateutil": { "hashes": [ @@ -2985,62 +2931,60 @@ }, "pyyaml": { "hashes": [ - "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", - "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", - "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", - "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", - "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", - "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", - "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", - "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", - "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", - "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", - "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", - "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", - "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", - "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", - "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", - "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", - "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", - "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", - "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", - "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", - "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", - "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", - "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", - "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", - "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", - "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", - "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", - "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", - "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", - "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", - "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", - "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", - "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", - "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", - "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", - "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", - "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", - "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", - "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", - "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", - "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", - "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", - "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", - "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", - "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", - "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", - "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", - "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", - "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", - "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", - "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", - "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", - "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" - ], - "markers": "python_version >= '3.8'", - "version": "==6.0.2" + "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5", + "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc", + "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df", + "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741", + "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206", + "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27", + "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595", + "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62", + "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98", + "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696", + "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290", + "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9", + "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d", + "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6", + "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867", + "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47", + "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486", + "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6", + "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3", + "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007", + "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938", + "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0", + "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c", + "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735", + "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d", + "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28", + "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4", + "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba", + "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8", + "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef", + "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5", + "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd", + "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3", + "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0", + "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515", + "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c", + "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c", + "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924", + "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34", + "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43", + "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859", + "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673", + "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54", + "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a", + "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b", + "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab", + "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa", + "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c", + "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585", + "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d", + "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f" + ], + "markers": "python_version >= '3.6'", + "version": "==6.0.1" }, "referencing": { "hashes": [ @@ -3257,11 +3201,11 @@ }, "stevedore": { "hashes": [ - "sha256:1efd34ca08f474dad08d9b19e934a22c68bb6fe416926479ba29e5013bcc8f78", - "sha256:9a64265f4060312828151c204efbe9b7a9852a0d9228756344dbc7e4023e375a" + "sha256:1c15d95766ca0569cad14cb6272d4d31dae66b011a929d7c18219c176ea1b5c9", + "sha256:46b93ca40e1114cea93d738a6c1e365396981bb6bb78c27045b7587c9473544d" ], "markers": "python_version >= '3.8'", - "version": "==5.3.0" + "version": "==5.2.0" }, "toml": { "hashes": [ @@ -3305,11 +3249,11 @@ }, "urllib3": { "hashes": [ - "sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e", - "sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32" + "sha256:37a0344459b199fce0e80b0d3569837ec6b6937435c5244e7fd73fa6006830f3", + "sha256:3e3d753a8618b86d7de333b4223005f68720bcd6a7d2bcb9fbd2229ec7c1e429" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==1.26.20" + "version": "==1.26.19" }, "watchdog": { "extras": [ @@ -3359,11 +3303,11 @@ }, "werkzeug": { "hashes": [ - "sha256:02c9eb92b7d6c06f31a782811505d2157837cea66aaede3e217c7c27c039476c", - "sha256:34f2371506b250df4d4f84bfe7b0921e4762525762bbd936614909fe25cd7306" + "sha256:097e5bfda9f0aba8da6b8545146def481d06aa7d3266e7448e2cccf67dd8bd18", + "sha256:fc9645dc43e03e4d630d23143a04a7f947a9a3b5727cd535fdfe155a17cc48c8" ], "markers": "python_version >= '3.8'", - "version": "==3.0.4" + "version": "==3.0.3" }, "wrapt": { "hashes": [ From a6babef4f33c8fb69c4af41ed1c1a81a2af9adbc Mon Sep 17 00:00:00 2001 From: Emile Swarts Date: Fri, 13 Sep 2024 10:32:06 +0100 Subject: [PATCH 07/86] Use different entrypoint when booting on DBT Platform --- Procfile | 3 ++- api/conf/gconfig-dbt-platform.py | 8 ++++++++ api/conf/gconfig.py | 4 ++-- 3 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 api/conf/gconfig-dbt-platform.py diff --git a/Procfile b/Procfile index 9c70e5caa8..709af5ae18 100644 --- a/Procfile +++ b/Procfile @@ -1,3 +1,4 @@ -web: pip3 install endesive==1.5.9 && python manage.py migrate && gunicorn --worker-class gevent -c api/conf/gconfig.py -b 0.0.0.0:$PORT api.conf.wsgi +web: SWIG_LIB=/home/vcap/deps/0/apt/usr/share/swig4.0 CFLAGS=-I/home/vcap/deps/1/python/include/python3.9.18m pip3 install endesive==1.5.9 && python manage.py migrate && gunicorn --worker-class gevent -c api/conf/gconfig.py -b 0.0.0.0:$PORT api.conf.wsgi +web-dbt-platform: python manage.py migrate && gunicorn --worker-class gevent -c api/conf/gconfig-dbt-platform.py -b 0.0.0.0:$PORT api.conf.wsgi celeryworker: celery -A api.conf worker -l info celeryscheduler: celery -A api.conf beat diff --git a/api/conf/gconfig-dbt-platform.py b/api/conf/gconfig-dbt-platform.py new file mode 100644 index 0000000000..beba006111 --- /dev/null +++ b/api/conf/gconfig-dbt-platform.py @@ -0,0 +1,8 @@ +import os + +workers = 4 +worker_connections = 1000 +# timeout affect document uploads +# if timeout is set to be too low, documents that would successfully upload will fail. +# creating a 502 bad gateway error +timeout = 600 diff --git a/api/conf/gconfig.py b/api/conf/gconfig.py index 8db4286607..11b3d242c9 100644 --- a/api/conf/gconfig.py +++ b/api/conf/gconfig.py @@ -1,7 +1,7 @@ import os -# PORT = os.environ.get("PORT", 8080) -# bind = "0.0.0.0:{PORT}".format(PORT=PORT) +PORT = os.environ.get("PORT", 8080) +bind = "0.0.0.0:{PORT}".format(PORT=PORT) workers = 4 worker_connections = 1000 # timeout affect document uploads From 37e715f503eb721ec3b0b4fef5f54e30b591b421 Mon Sep 17 00:00:00 2001 From: Emile Swarts Date: Fri, 13 Sep 2024 10:37:11 +0100 Subject: [PATCH 08/86] Return S3 boto client for DBT Platform We don't use IAM keys on DBT platform, we use roles instead. Don't instantiate the client with keys when on DBT Platform. --- api/documents/libraries/s3_operations.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/api/documents/libraries/s3_operations.py b/api/documents/libraries/s3_operations.py index fe823780a0..9891986d69 100644 --- a/api/documents/libraries/s3_operations.py +++ b/api/documents/libraries/s3_operations.py @@ -8,6 +8,7 @@ from django.conf import settings from django.http import FileResponse +from dbt_copilot_python.utility import is_copilot logger = logging.getLogger(__name__) @@ -23,12 +24,23 @@ def init_s3_client(): additional_s3_params = {} if settings.AWS_ENDPOINT_URL: additional_s3_params["endpoint_url"] = settings.AWS_ENDPOINT_URL - _client = boto3.client( - "s3", - region_name="eu-west-2", - config=Config(connect_timeout=settings.S3_CONNECT_TIMEOUT, read_timeout=settings.S3_REQUEST_TIMEOUT), - **additional_s3_params, - ) + + if is_copilot(): + _client = boto3.client( + "s3", + region_name="eu-west-2", + config=Config(connect_timeout=settings.S3_CONNECT_TIMEOUT, read_timeout=settings.S3_REQUEST_TIMEOUT), + **additional_s3_params, + ) + else: + _client = boto3.client( + "s3", + aws_access_key_id=settings.AWS_ACCESS_KEY_ID, + aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY, + region_name=settings.AWS_REGION, + config=Config(connect_timeout=settings.S3_CONNECT_TIMEOUT, read_timeout=settings.S3_REQUEST_TIMEOUT), + **additional_s3_params, + ) return _client From 9597db8e506198c52c03d3a89147da44bc3d0003 Mon Sep 17 00:00:00 2001 From: Emile Swarts Date: Fri, 13 Sep 2024 10:39:28 +0100 Subject: [PATCH 09/86] Remove comments in build shell scripts --- .copilot/phases/build.sh | 3 --- .copilot/phases/install.sh | 3 --- .copilot/phases/post_build.sh | 3 --- 3 files changed, 9 deletions(-) diff --git a/.copilot/phases/build.sh b/.copilot/phases/build.sh index c1a73f284b..df82332cd8 100644 --- a/.copilot/phases/build.sh +++ b/.copilot/phases/build.sh @@ -1,6 +1,3 @@ #!/usr/bin/env bash -# Exit early if something goes wrong set -e - -# Add commands below to run as part of the build phase diff --git a/.copilot/phases/install.sh b/.copilot/phases/install.sh index 17794e84a4..df82332cd8 100644 --- a/.copilot/phases/install.sh +++ b/.copilot/phases/install.sh @@ -1,6 +1,3 @@ #!/usr/bin/env bash -# Exit early if something goes wrong set -e - -# Add commands below to run as part of the install phase diff --git a/.copilot/phases/post_build.sh b/.copilot/phases/post_build.sh index 1676bb5b32..df82332cd8 100644 --- a/.copilot/phases/post_build.sh +++ b/.copilot/phases/post_build.sh @@ -1,6 +1,3 @@ #!/usr/bin/env bash -# Exit early if something goes wrong set -e - -# Add commands below to run as part of the post_build phase From 86d6606fa61dcd11208cba5004ff203a56ddf9d4 Mon Sep 17 00:00:00 2001 From: Emile Swarts Date: Fri, 13 Sep 2024 10:40:19 +0100 Subject: [PATCH 10/86] Add newline --- .InstallPackages | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.InstallPackages b/.InstallPackages index 95263bb8af..1f4b46d7bf 100644 --- a/.InstallPackages +++ b/.InstallPackages @@ -9,4 +9,4 @@ shared-mime-info swig imagemagick poppler-utils -libsqlite3-dev \ No newline at end of file +libsqlite3-dev From 83c8f2456084521bb55f0d0ffe1545bba7dffb9a Mon Sep 17 00:00:00 2001 From: Emile Swarts Date: Fri, 13 Sep 2024 10:41:46 +0100 Subject: [PATCH 11/86] Remove unused comments --- .copilot/image_build_run.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/.copilot/image_build_run.sh b/.copilot/image_build_run.sh index 8ac7a39065..df82332cd8 100755 --- a/.copilot/image_build_run.sh +++ b/.copilot/image_build_run.sh @@ -1,6 +1,3 @@ #!/usr/bin/env bash -# Exit early if something goes wrong set -e - -# Add commands below to run inside the container after all the other buildpacks have been applied From 02c0eacf59b7244e12ae58d20c262a5e8f19b955 Mon Sep 17 00:00:00 2001 From: Emile Swarts Date: Fri, 13 Sep 2024 10:50:36 +0100 Subject: [PATCH 12/86] Only enable additional health checks when not on DBT Platform --- api/conf/settings.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/api/conf/settings.py b/api/conf/settings.py index e44f629791..9b2895b14e 100644 --- a/api/conf/settings.py +++ b/api/conf/settings.py @@ -137,6 +137,14 @@ "drf_spectacular", ] +if not IS_ENV_DBT_PLATFORM: + INSTALLED_APPS += [ + "health_check.db", + "health_check.cache", + "health_check.storage", + "health_check.contrib.migrations" + ] + MOCK_VIRUS_SCAN_ACTIVATE_ENDPOINTS = env("MOCK_VIRUS_SCAN_ACTIVATE_ENDPOINTS") if MOCK_VIRUS_SCAN_ACTIVATE_ENDPOINTS: From 2a4cf67b1f40bd95050a677450843010b22ca4c6 Mon Sep 17 00:00:00 2001 From: Emile Swarts Date: Fri, 13 Sep 2024 10:51:23 +0100 Subject: [PATCH 13/86] Add newline to pre_build shell script --- .copilot/phases/pre_build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.copilot/phases/pre_build.sh b/.copilot/phases/pre_build.sh index 8440c07e4e..2183152636 100644 --- a/.copilot/phases/pre_build.sh +++ b/.copilot/phases/pre_build.sh @@ -35,4 +35,4 @@ main() { update_pip_file_for_dbt_platform } -main \ No newline at end of file +main From 61628d9adf10ab0aedeebb29c2d99ecb1daaf905 Mon Sep 17 00:00:00 2001 From: Emile Swarts Date: Fri, 13 Sep 2024 10:55:19 +0100 Subject: [PATCH 14/86] Fix syntax error --- .copilot/phases/pre_build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.copilot/phases/pre_build.sh b/.copilot/phases/pre_build.sh index 2183152636..66777e5042 100644 --- a/.copilot/phases/pre_build.sh +++ b/.copilot/phases/pre_build.sh @@ -3,7 +3,7 @@ # Exit early if something goes wrong set -e -update_git_submodules() {} +update_git_submodules() { git_clone_base_url="https://codestar-connections.eu-west-2.amazonaws.com/git-http/730335529260/eu-west-2/192881c6-e3f2-41a9-9dcb-fcc87d8b90be/uktrade" git config --global credential.helper '!aws codecommit credential-helper $@' From ce87a2a9b17540cdb6a1226cd0c70d3a415e5297 Mon Sep 17 00:00:00 2001 From: Emile Swarts Date: Fri, 13 Sep 2024 11:07:22 +0100 Subject: [PATCH 15/86] Update Pipfile.lock in pre_build step --- .copilot/phases/pre_build.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/.copilot/phases/pre_build.sh b/.copilot/phases/pre_build.sh index 66777e5042..b2e5ba36af 100644 --- a/.copilot/phases/pre_build.sh +++ b/.copilot/phases/pre_build.sh @@ -28,6 +28,7 @@ EOF update_pip_file_for_dbt_platform() { sed -i 's/\[packages\]/[packages]\nendesive = "~=1.5.9"\npython-pkcs11 = "~=0.7.0"\npykcs11 = "~=1.4.4"\n/' Pipfile + pipenv lock } main() { From d44260b2841d86535a24879e4ede63197815e443 Mon Sep 17 00:00:00 2001 From: Gurdeep Atwal Date: Thu, 19 Sep 2024 13:52:29 +0100 Subject: [PATCH 16/86] lint fix --- api/conf/gconfig-dbt-platform.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/api/conf/gconfig-dbt-platform.py b/api/conf/gconfig-dbt-platform.py index beba006111..920a7ab514 100644 --- a/api/conf/gconfig-dbt-platform.py +++ b/api/conf/gconfig-dbt-platform.py @@ -1,5 +1,3 @@ -import os - workers = 4 worker_connections = 1000 # timeout affect document uploads From 64be6663e08c783eaeb268ce8696a2d8514e7ac4 Mon Sep 17 00:00:00 2001 From: Gurdeep Atwal Date: Thu, 19 Sep 2024 14:34:40 +0100 Subject: [PATCH 17/86] lint --- api/conf/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/conf/settings.py b/api/conf/settings.py index 9b2895b14e..9a95e1740e 100644 --- a/api/conf/settings.py +++ b/api/conf/settings.py @@ -142,7 +142,7 @@ "health_check.db", "health_check.cache", "health_check.storage", - "health_check.contrib.migrations" + "health_check.contrib.migrations", ] MOCK_VIRUS_SCAN_ACTIVATE_ENDPOINTS = env("MOCK_VIRUS_SCAN_ACTIVATE_ENDPOINTS") From a79498d6341f42f1f40e8ca9eb7643d082ed7af0 Mon Sep 17 00:00:00 2001 From: Gurdeep Atwal Date: Thu, 19 Sep 2024 16:07:45 +0100 Subject: [PATCH 18/86] fix s3 operation --- .coveragerc | 1 + api/documents/libraries/s3_operations.py | 2 +- .../libraries/tests/test_s3_operations.py | 25 +++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/.coveragerc b/.coveragerc index ec64a7cf9e..14ef97732a 100644 --- a/.coveragerc +++ b/.coveragerc @@ -8,6 +8,7 @@ omit = ./*/migrations/* ./api/conf/schema_generator_urls.py ./api/conf/settings.py + ./api/conf/gconfig-dbt-platform.py ./api/conf/wsgi.py ./static/management/* *test* diff --git a/api/documents/libraries/s3_operations.py b/api/documents/libraries/s3_operations.py index 9891986d69..98d7daf163 100644 --- a/api/documents/libraries/s3_operations.py +++ b/api/documents/libraries/s3_operations.py @@ -28,7 +28,7 @@ def init_s3_client(): if is_copilot(): _client = boto3.client( "s3", - region_name="eu-west-2", + region_name=settings.AWS_REGION, config=Config(connect_timeout=settings.S3_CONNECT_TIMEOUT, read_timeout=settings.S3_REQUEST_TIMEOUT), **additional_s3_params, ) diff --git a/api/documents/libraries/tests/test_s3_operations.py b/api/documents/libraries/tests/test_s3_operations.py index 02fb348911..17e4889c47 100644 --- a/api/documents/libraries/tests/test_s3_operations.py +++ b/api/documents/libraries/tests/test_s3_operations.py @@ -87,6 +87,31 @@ def test_get_client_with_aws_endpoint_url(self, mock_Config, mock_boto3): endpoint_url="AWS_ENDPOINT_URL", ) + @patch("api.documents.libraries.s3_operations.is_copilot") + @patch("api.documents.libraries.s3_operations._client") + def test_get_client_with_is_copilot(self, mock_client, mock_is_copilot, mock_Config, mock_boto3): + mock_is_copilot.return_value = True + mock_client = Mock() + mock_boto3.client.return_value = mock_client + + returned_client = init_s3_client() + self.assertEqual(returned_client, mock_client) + + mock_Config.assert_called_with( + connect_timeout=22, + read_timeout=44, + ) + config = mock_Config( + connection_timeout=22, + read_timeout=44, + ) + mock_boto3.client.assert_called_with( + "s3", + region_name="AWS_REGION", + config=config, + endpoint_url="AWS_ENDPOINT_URL", + ) + @override_settings( AWS_STORAGE_BUCKET_NAME="test-bucket", From 4782bc1c98cca8d2d1be04829d8c9aa09e10fc00 Mon Sep 17 00:00:00 2001 From: James Francis Date: Mon, 23 Sep 2024 16:36:25 +0100 Subject: [PATCH 19/86] make pg_dump command available in image --- .InstallPackages | 1 + api/conf/settings.py | 1 + 2 files changed, 2 insertions(+) diff --git a/.InstallPackages b/.InstallPackages index 1f4b46d7bf..bc3c5b89d9 100644 --- a/.InstallPackages +++ b/.InstallPackages @@ -10,3 +10,4 @@ swig imagemagick poppler-utils libsqlite3-dev +postgresql-client-14 diff --git a/api/conf/settings.py b/api/conf/settings.py index 9a95e1740e..6275bb0c31 100644 --- a/api/conf/settings.py +++ b/api/conf/settings.py @@ -470,6 +470,7 @@ def _build_redis_url(base_url, db_number, **query_args): if IS_ENV_DBT_PLATFORM: ALLOWED_HOSTS = setup_allowed_hosts(ALLOWED_HOSTS) AWS_ENDPOINT_URL = env("AWS_ENDPOINT_URL", default=None) + AWS_REGION = "eu-west-2" DATABASES = {"default": dj_database_url.config(default=database_url_from_env("DATABASE_CREDENTIALS"))} CELERY_BROKER_URL = env("CELERY_BROKER_URL", default=None) CELERY_RESULT_BACKEND = CELERY_BROKER_URL From f503c5a882ae0bfd85eea6ead73cfa37336c5f18 Mon Sep 17 00:00:00 2001 From: Emile Swarts Date: Tue, 24 Sep 2024 15:33:25 +0100 Subject: [PATCH 20/86] Add Python Getevent os package --- .InstallPackages | 1 + Pipfile.lock | 600 +++++++++++++++++++++++++---------------------- 2 files changed, 318 insertions(+), 283 deletions(-) diff --git a/.InstallPackages b/.InstallPackages index bc3c5b89d9..ad708a61db 100644 --- a/.InstallPackages +++ b/.InstallPackages @@ -11,3 +11,4 @@ imagemagick poppler-utils libsqlite3-dev postgresql-client-14 +python-gevent diff --git a/Pipfile.lock b/Pipfile.lock index 68819c16e2..0dab1ebf35 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -125,61 +125,76 @@ }, "cffi": { "hashes": [ - "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc", - "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a", - "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417", - "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab", - "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520", - "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36", - "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743", - "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8", - "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed", - "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684", - "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56", - "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324", - "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d", - "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235", - "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e", - "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088", - "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000", - "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7", - "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e", - "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673", - "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c", - "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe", - "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2", - "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098", - "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8", - "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a", - "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0", - "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b", - "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896", - "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e", - "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9", - "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2", - "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b", - "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6", - "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404", - "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f", - "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0", - "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4", - "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc", - "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936", - "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba", - "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872", - "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb", - "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614", - "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1", - "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d", - "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969", - "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b", - "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4", - "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627", - "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956", - "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357" - ], - "markers": "python_version >= '3.8'", - "version": "==1.16.0" + "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", + "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", + "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1", + "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", + "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", + "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", + "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8", + "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36", + "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", + "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", + "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc", + "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", + "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", + "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", + "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", + "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", + "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", + "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", + "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", + "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b", + "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", + "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", + "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c", + "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", + "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", + "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", + "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8", + "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1", + "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", + "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", + "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", + "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595", + "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0", + "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", + "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", + "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", + "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", + "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", + "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", + "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16", + "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", + "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e", + "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", + "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964", + "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", + "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576", + "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", + "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3", + "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662", + "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", + "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", + "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", + "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", + "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", + "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", + "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", + "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", + "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9", + "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7", + "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", + "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a", + "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", + "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", + "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", + "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", + "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87", + "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b" + ], + "markers": "python_version >= '3.8'", + "version": "==1.17.1" }, "cfgv": { "hashes": [ @@ -440,12 +455,12 @@ }, "django": { "hashes": [ - "sha256:61ee4a130efb8c451ef3467c67ca99fdce400fedd768634efc86a68c18d80d30", - "sha256:c77f926b81129493961e19c0e02188f8d07c112a1162df69bfab178ae447f94a" + "sha256:1ddc333a16fc139fd253035a1606bb24261951bbc3a6ca256717fa06cc41a898", + "sha256:6f1616c2786c408ce86ab7e10f792b8f15742f7b7b7460243929cb371e7f1dad" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.2.15" + "version": "==4.2.16" }, "django-activity-stream": { "hashes": [ @@ -569,20 +584,20 @@ }, "django-queryable-properties": { "hashes": [ - "sha256:68f3ed8cd6f03fb2993eabe1c3235091781f01266397b75319e1e20556991d7f", - "sha256:f272d5b68be3bd3a57004dcbe1f849ba5080a97069ff0f0f858c364a9eafedb6" + "sha256:9a2d35ea6cd33f80ac666f62009006a2373bcfbfc720981a60a9a428585659d1", + "sha256:aaec7d3ea9dc3be44e6114ca1ca705ac0e23b00c5209832aeb1c6ab5c4e9c345" ], "index": "pypi", - "version": "==1.9.2" + "version": "==1.9.3" }, "django-reversion": { "hashes": [ - "sha256:5884e9f77f55c341b3f0a8d3b0af000f060530653776997267c8b1e5349d8fee", - "sha256:c047cc99a9f1ba4aae6db89c3ac243478d6de98ec8a60c7073fcc875d89c5cdb" + "sha256:084d4f117d9e2b4e8dfdfaad83ebb34410a03eed6071c96089e6811fdea82ad3", + "sha256:3309821e5b6fceedcce6b6975f1a9c7fab6ae7c7d0e1276a90e345946fa0dcb8" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==5.0.12" + "markers": "python_version >= '3.8'", + "version": "==5.1.0" }, "django-silk": { "hashes": [ @@ -786,11 +801,11 @@ }, "googleapis-common-protos": { "hashes": [ - "sha256:0e1c2cdfcbc354b76e4a211a35ea35d6926a835cba1377073c4861db904a1877", - "sha256:c6442f7a0a6b2a80369457d79e6672bb7dcbaab88e0848302497e3ec80780a6a" + "sha256:2972e6c496f435b92590fd54045060867f3fe9be2c82ab148fc8885035479a63", + "sha256:334a29d07cddc3aa01dee4988f9afd9b2916ee2ff49d6b757155dc0d197852c0" ], "markers": "python_version >= '3.7'", - "version": "==1.63.1" + "version": "==1.65.0" }, "gprof2dot": { "hashes": [ @@ -1191,11 +1206,11 @@ }, "opentelemetry-propagator-aws-xray": { "hashes": [ - "sha256:49267a1d72b3f04880ac75e24f9ef38fe323e2f3156c4531e0e00c71c0829c0f", - "sha256:6e8be667bbcf17c3d81d70b2a7cdec0b11257ff64d3829ffe75b810ba1b49f86" + "sha256:1c99181ee228e99bddb638a0c911a297fa21f1c3a0af951f841e79919b5f1934", + "sha256:6b2cee5479d2ef0172307b66ed2ed151f598a0fd29b3c01133ac87ca06326260" ], - "markers": "python_version >= '3.6'", - "version": "==1.0.1" + "markers": "python_version >= '3.8'", + "version": "==1.0.2" }, "opentelemetry-proto": { "hashes": [ @@ -1215,11 +1230,11 @@ }, "opentelemetry-sdk-extension-aws": { "hashes": [ - "sha256:dd7cf6fc0e7c8070dbe179348f2f194ca4555601b60efb7264d82fc8df53f4ba", - "sha256:f964b0598793ded268d3329c33829fad33f63a8d9299fe51bf3a743e81fd7c67" + "sha256:4c6e4b9fec01a4a9cfeac5272ce5aae6bc80e080a6bae1e52098746f53a7b32d", + "sha256:9faa9bdf480d1c5c53151dabee75735c94dbde09e4762c68ff5c7bd4aa3408f3" ], - "markers": "python_version >= '3.6'", - "version": "==2.0.1" + "markers": "python_version >= '3.8'", + "version": "==2.0.2" }, "opentelemetry-semantic-conventions": { "hashes": [ @@ -1362,11 +1377,11 @@ }, "pre-commit": { "hashes": [ - "sha256:8ca3ad567bc78a4972a3f1a477e94a79d4597e8140a6e0b651c5e33899c3654a", - "sha256:fae36fd1d7ad7d6a5a1c0b0d5adb2ed1a3bda5a21bf6c3e5372073d7a11cd4c5" + "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af", + "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f" ], "markers": "python_version >= '3.9'", - "version": "==3.7.1" + "version": "==3.8.0" }, "prompt-toolkit": { "hashes": [ @@ -1395,12 +1410,12 @@ }, "psycopg": { "hashes": [ - "sha256:92d7b78ad82426cdcf1a0440678209faa890c6e1721361c2f8901f0dccd62961", - "sha256:dca5e5521c859f6606686432ae1c94e8766d29cc91f2ee595378c510cc5b0731" + "sha256:32f5862ab79f238496236f97fe374a7ab55b4b4bb839a74802026544735f9a07", + "sha256:898a29f49ac9c903d554f5a6cdc44a8fc564325557c18f82e51f39c1f4fc2aeb" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==3.1.19" + "version": "==3.1.20" }, "ptyprocess": { "hashes": [ @@ -1411,11 +1426,11 @@ }, "pycodestyle": { "hashes": [ - "sha256:442f950141b4f43df752dd303511ffded3a04c2b6fb7f65980574f0c31e6e79c", - "sha256:949a39f6b86c3e1515ba1787c2022131d165a8ad271b11370a8819aa070269e4" + "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3", + "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521" ], "markers": "python_version >= '3.8'", - "version": "==2.12.0" + "version": "==2.12.1" }, "pycparser": { "hashes": [ @@ -1435,8 +1450,8 @@ }, "pyjwt": { "hashes": [ - "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de", - "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320" + "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850", + "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c" ], "markers": "python_version >= '3.8'", "version": "==2.9.0" @@ -1452,11 +1467,11 @@ }, "pyphen": { "hashes": [ - "sha256:999b430916ab42ae9912537cd95c074e0c6691e89a9d05999f9b610a68f34858", - "sha256:a430623decac53dc3691241253263cba36b9dd7a44ffd2680b706af368cda2f2" + "sha256:2c006b3ddf072c9571ab97606d9ab3c26a92eaced4c0d59fd1d26988f308f413", + "sha256:b4a4c6d7d5654b698b5fc68123148bb799b3debe0175d1d5dc3edfe93066fc4c" ], "markers": "python_version >= '3.8'", - "version": "==0.15.0" + "version": "==0.16.0" }, "python-dateutil": { "hashes": [ @@ -1476,60 +1491,62 @@ }, "pyyaml": { "hashes": [ - "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5", - "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc", - "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df", - "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741", - "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206", - "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27", - "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595", - "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62", - "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98", - "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696", - "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290", - "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9", - "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d", - "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6", - "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867", - "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47", - "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486", - "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6", - "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3", - "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007", - "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938", - "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0", - "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c", - "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735", - "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d", - "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28", - "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4", - "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba", - "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8", - "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef", - "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5", - "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd", - "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3", - "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0", - "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515", - "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c", - "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c", - "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924", - "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34", - "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43", - "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859", - "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673", - "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54", - "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a", - "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b", - "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab", - "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa", - "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c", - "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585", - "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d", - "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f" - ], - "markers": "python_version >= '3.6'", - "version": "==6.0.1" + "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", + "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", + "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", + "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", + "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", + "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", + "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", + "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", + "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", + "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", + "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", + "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", + "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", + "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", + "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", + "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", + "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", + "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", + "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", + "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", + "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", + "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", + "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", + "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", + "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", + "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", + "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", + "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", + "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", + "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", + "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", + "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", + "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", + "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", + "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", + "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", + "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", + "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", + "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", + "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", + "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", + "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", + "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", + "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", + "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", + "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", + "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", + "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", + "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", + "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", + "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", + "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", + "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" + ], + "markers": "python_version >= '3.8'", + "version": "==6.0.2" }, "redis": { "hashes": [ @@ -1790,11 +1807,11 @@ }, "urllib3": { "hashes": [ - "sha256:37a0344459b199fce0e80b0d3569837ec6b6937435c5244e7fd73fa6006830f3", - "sha256:3e3d753a8618b86d7de333b4223005f68720bcd6a7d2bcb9fbd2229ec7c1e429" + "sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e", + "sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==1.26.19" + "version": "==1.26.20" }, "vine": { "hashes": [ @@ -2085,70 +2102,85 @@ }, "certifi": { "hashes": [ - "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516", - "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56" + "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b", + "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90" ], "index": "pypi", "markers": "python_version >= '3.6'", - "version": "==2024.6.2" + "version": "==2024.7.4" }, "cffi": { "hashes": [ - "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc", - "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a", - "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417", - "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab", - "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520", - "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36", - "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743", - "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8", - "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed", - "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684", - "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56", - "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324", - "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d", - "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235", - "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e", - "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088", - "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000", - "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7", - "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e", - "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673", - "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c", - "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe", - "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2", - "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098", - "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8", - "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a", - "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0", - "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b", - "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896", - "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e", - "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9", - "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2", - "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b", - "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6", - "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404", - "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f", - "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0", - "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4", - "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc", - "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936", - "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba", - "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872", - "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb", - "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614", - "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1", - "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d", - "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969", - "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b", - "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4", - "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627", - "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956", - "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357" - ], - "markers": "python_version >= '3.8'", - "version": "==1.16.0" + "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", + "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", + "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1", + "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", + "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", + "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", + "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8", + "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36", + "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", + "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", + "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc", + "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", + "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", + "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", + "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", + "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", + "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", + "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", + "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", + "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b", + "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", + "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", + "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c", + "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", + "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", + "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", + "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8", + "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1", + "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", + "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", + "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", + "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595", + "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0", + "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", + "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", + "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", + "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", + "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", + "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", + "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16", + "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", + "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e", + "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", + "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964", + "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", + "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576", + "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", + "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3", + "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662", + "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", + "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", + "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", + "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", + "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", + "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", + "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", + "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", + "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9", + "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7", + "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", + "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a", + "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", + "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", + "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", + "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", + "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87", + "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b" + ], + "markers": "python_version >= '3.8'", + "version": "==1.17.1" }, "charset-normalizer": { "hashes": [ @@ -2422,11 +2454,11 @@ }, "exceptiongroup": { "hashes": [ - "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad", - "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16" + "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", + "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" ], "markers": "python_version < '3.11'", - "version": "==1.2.1" + "version": "==1.2.2" }, "freezegun": { "hashes": [ @@ -2729,11 +2761,11 @@ }, "pbr": { "hashes": [ - "sha256:4a7317d5e3b17a3dccb6a8cfe67dab65b20551404c52c8ed41279fa4f0cb4cda", - "sha256:d1377122a5a00e2f940ee482999518efe16d745d423a670c27773dfbc3c9a7d9" + "sha256:788183e382e3d1d7707db08978239965e8b9e4e5ed42669bf4758186734d5f24", + "sha256:a776ae228892d8013649c0aeccbb3d5f99ee15e005a4cbb7e61d55a067b28a2a" ], "markers": "python_version >= '2.6'", - "version": "==6.0.0" + "version": "==6.1.0" }, "pep8-naming": { "hashes": [ @@ -2804,11 +2836,11 @@ }, "pycodestyle": { "hashes": [ - "sha256:442f950141b4f43df752dd303511ffded3a04c2b6fb7f65980574f0c31e6e79c", - "sha256:949a39f6b86c3e1515ba1787c2022131d165a8ad271b11370a8819aa070269e4" + "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3", + "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521" ], "markers": "python_version >= '3.8'", - "version": "==2.12.0" + "version": "==2.12.1" }, "pycparser": { "hashes": [ @@ -2879,12 +2911,12 @@ }, "pytest": { "hashes": [ - "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343", - "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977" + "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", + "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==8.2.2" + "version": "==8.3.3" }, "pytest-bdd": { "hashes": [ @@ -2914,12 +2946,12 @@ }, "pytest-django": { "hashes": [ - "sha256:5d054fe011c56f3b10f978f41a8efb2e5adfc7e680ef36fb571ada1f24779d90", - "sha256:ca1ddd1e0e4c227cf9e3e40a6afc6d106b3e70868fd2ac5798a22501271cd0c7" + "sha256:1d83692cb39188682dbb419ff0393867e9904094a549a7d38a3154d5731b2b99", + "sha256:8bf7bc358c9ae6f6fc51b6cebb190fe20212196e6807121f11bd6a3b03428314" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.8.0" + "version": "==4.9.0" }, "python-dateutil": { "hashes": [ @@ -2931,60 +2963,62 @@ }, "pyyaml": { "hashes": [ - "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5", - "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc", - "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df", - "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741", - "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206", - "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27", - "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595", - "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62", - "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98", - "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696", - "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290", - "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9", - "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d", - "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6", - "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867", - "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47", - "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486", - "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6", - "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3", - "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007", - "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938", - "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0", - "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c", - "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735", - "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d", - "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28", - "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4", - "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba", - "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8", - "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef", - "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5", - "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd", - "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3", - "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0", - "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515", - "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c", - "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c", - "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924", - "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34", - "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43", - "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859", - "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673", - "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54", - "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a", - "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b", - "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab", - "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa", - "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c", - "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585", - "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d", - "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f" - ], - "markers": "python_version >= '3.6'", - "version": "==6.0.1" + "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", + "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", + "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", + "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", + "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", + "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", + "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", + "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", + "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", + "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", + "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", + "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", + "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", + "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", + "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", + "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", + "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", + "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", + "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", + "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", + "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", + "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", + "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", + "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", + "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", + "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", + "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", + "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", + "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", + "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", + "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", + "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", + "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", + "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", + "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", + "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", + "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", + "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", + "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", + "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", + "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", + "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", + "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", + "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", + "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", + "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", + "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", + "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", + "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", + "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", + "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", + "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", + "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" + ], + "markers": "python_version >= '3.8'", + "version": "==6.0.2" }, "referencing": { "hashes": [ @@ -3201,11 +3235,11 @@ }, "stevedore": { "hashes": [ - "sha256:1c15d95766ca0569cad14cb6272d4d31dae66b011a929d7c18219c176ea1b5c9", - "sha256:46b93ca40e1114cea93d738a6c1e365396981bb6bb78c27045b7587c9473544d" + "sha256:1efd34ca08f474dad08d9b19e934a22c68bb6fe416926479ba29e5013bcc8f78", + "sha256:9a64265f4060312828151c204efbe9b7a9852a0d9228756344dbc7e4023e375a" ], "markers": "python_version >= '3.8'", - "version": "==5.2.0" + "version": "==5.3.0" }, "toml": { "hashes": [ @@ -3249,11 +3283,11 @@ }, "urllib3": { "hashes": [ - "sha256:37a0344459b199fce0e80b0d3569837ec6b6937435c5244e7fd73fa6006830f3", - "sha256:3e3d753a8618b86d7de333b4223005f68720bcd6a7d2bcb9fbd2229ec7c1e429" + "sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e", + "sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==1.26.19" + "version": "==1.26.20" }, "watchdog": { "extras": [ @@ -3303,11 +3337,11 @@ }, "werkzeug": { "hashes": [ - "sha256:097e5bfda9f0aba8da6b8545146def481d06aa7d3266e7448e2cccf67dd8bd18", - "sha256:fc9645dc43e03e4d630d23143a04a7f947a9a3b5727cd535fdfe155a17cc48c8" + "sha256:02c9eb92b7d6c06f31a782811505d2157837cea66aaede3e217c7c27c039476c", + "sha256:34f2371506b250df4d4f84bfe7b0921e4762525762bbd936614909fe25cd7306" ], "markers": "python_version >= '3.8'", - "version": "==3.0.3" + "version": "==3.0.4" }, "wrapt": { "hashes": [ From 9f363dfbe35ce8ee500b66c6e3c8f5e560be8b05 Mon Sep 17 00:00:00 2001 From: Emile Swarts Date: Tue, 24 Sep 2024 15:47:53 +0100 Subject: [PATCH 21/86] Attempt to use correct version of Gevent --- .InstallPackages | 1 - Pipfile | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.InstallPackages b/.InstallPackages index ad708a61db..bc3c5b89d9 100644 --- a/.InstallPackages +++ b/.InstallPackages @@ -11,4 +11,3 @@ imagemagick poppler-utils libsqlite3-dev postgresql-client-14 -python-gevent diff --git a/Pipfile b/Pipfile index 5efe7d68be..601b0026b4 100644 --- a/Pipfile +++ b/Pipfile @@ -54,7 +54,7 @@ cryptography = "~=43.0.1" sentry-sdk = "~=2.8.0" elastic-apm = "~=6.7.2" gunicorn = "~=22.0.0" -gevent = "~=23.9.1" +gevent = "~=1.4" xmltodict = "~=0.12.0" Pillow = "~=10.3.0" django-phonenumber-field = "==6.4.0" From 1bbcd4dacec35b86aec0fab13d3d6f85e792b48a Mon Sep 17 00:00:00 2001 From: Emile Swarts Date: Tue, 24 Sep 2024 16:01:37 +0100 Subject: [PATCH 22/86] revert bumping gevent --- Pipfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pipfile b/Pipfile index 601b0026b4..5efe7d68be 100644 --- a/Pipfile +++ b/Pipfile @@ -54,7 +54,7 @@ cryptography = "~=43.0.1" sentry-sdk = "~=2.8.0" elastic-apm = "~=6.7.2" gunicorn = "~=22.0.0" -gevent = "~=1.4" +gevent = "~=23.9.1" xmltodict = "~=0.12.0" Pillow = "~=10.3.0" django-phonenumber-field = "==6.4.0" From 0344cf1e0137a4db03f28dbf1aea8e9cc3154dab Mon Sep 17 00:00:00 2001 From: Emile Swarts Date: Thu, 26 Sep 2024 11:12:58 +0100 Subject: [PATCH 23/86] Bump gevent to the latest supported version --- Pipfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pipfile b/Pipfile index 5efe7d68be..dd389c8038 100644 --- a/Pipfile +++ b/Pipfile @@ -54,7 +54,7 @@ cryptography = "~=43.0.1" sentry-sdk = "~=2.8.0" elastic-apm = "~=6.7.2" gunicorn = "~=22.0.0" -gevent = "~=23.9.1" +gevent = "~=24.2.1" xmltodict = "~=0.12.0" Pillow = "~=10.3.0" django-phonenumber-field = "==6.4.0" From 098b0bed1fbf1c52dfb5c2714f322543116f361f Mon Sep 17 00:00:00 2001 From: James Francis Date: Thu, 26 Sep 2024 11:48:16 +0100 Subject: [PATCH 24/86] replace codestar string with env vars --- .copilot/phases/pre_build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.copilot/phases/pre_build.sh b/.copilot/phases/pre_build.sh index b2e5ba36af..27c33abd08 100644 --- a/.copilot/phases/pre_build.sh +++ b/.copilot/phases/pre_build.sh @@ -4,7 +4,7 @@ set -e update_git_submodules() { - git_clone_base_url="https://codestar-connections.eu-west-2.amazonaws.com/git-http/730335529260/eu-west-2/192881c6-e3f2-41a9-9dcb-fcc87d8b90be/uktrade" + git_clone_base_url="https://codestar-connections.eu-west-2.amazonaws.com/git-http/$AWS_ACCOUNT_ID/eu-west-2/$CODESTAR_CONNECTION_ID/uktrade" git config --global credential.helper '!aws codecommit credential-helper $@' git config --global credential.UseHttpPath true From 2627c22fe37bd2365829be3ae8098108cf8a9ed9 Mon Sep 17 00:00:00 2001 From: Emile Swarts Date: Thu, 26 Sep 2024 14:51:25 +0100 Subject: [PATCH 25/86] Cat packages --- Procfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Procfile b/Procfile index 709af5ae18..1ffb2f3eb2 100644 --- a/Procfile +++ b/Procfile @@ -1,4 +1,4 @@ web: SWIG_LIB=/home/vcap/deps/0/apt/usr/share/swig4.0 CFLAGS=-I/home/vcap/deps/1/python/include/python3.9.18m pip3 install endesive==1.5.9 && python manage.py migrate && gunicorn --worker-class gevent -c api/conf/gconfig.py -b 0.0.0.0:$PORT api.conf.wsgi -web-dbt-platform: python manage.py migrate && gunicorn --worker-class gevent -c api/conf/gconfig-dbt-platform.py -b 0.0.0.0:$PORT api.conf.wsgi +web-dbt-platform: cat /layers/paketo-buildpacks_pipenv-install/packages/workspace-dqq3IVyd/lib/python3.9/site-packages/ && python manage.py migrate && gunicorn --worker-class gevent -c api/conf/gconfig-dbt-platform.py -b 0.0.0.0:$PORT api.conf.wsgi celeryworker: celery -A api.conf worker -l info celeryscheduler: celery -A api.conf beat From f3506693dbf07bda21095f9df33819b4ccf16060 Mon Sep 17 00:00:00 2001 From: Emile Swarts Date: Thu, 26 Sep 2024 15:01:56 +0100 Subject: [PATCH 26/86] More debugging of installed packages --- Procfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Procfile b/Procfile index 1ffb2f3eb2..bb44317f3f 100644 --- a/Procfile +++ b/Procfile @@ -1,4 +1,4 @@ web: SWIG_LIB=/home/vcap/deps/0/apt/usr/share/swig4.0 CFLAGS=-I/home/vcap/deps/1/python/include/python3.9.18m pip3 install endesive==1.5.9 && python manage.py migrate && gunicorn --worker-class gevent -c api/conf/gconfig.py -b 0.0.0.0:$PORT api.conf.wsgi -web-dbt-platform: cat /layers/paketo-buildpacks_pipenv-install/packages/workspace-dqq3IVyd/lib/python3.9/site-packages/ && python manage.py migrate && gunicorn --worker-class gevent -c api/conf/gconfig-dbt-platform.py -b 0.0.0.0:$PORT api.conf.wsgi +web-dbt-platform: ls -al /layers/paketo-buildpacks_pipenv-install/packages/workspace-dqq3IVyd/lib/python3.9/site-packages/ && python manage.py migrate && gunicorn --worker-class gevent -c api/conf/gconfig-dbt-platform.py -b 0.0.0.0:$PORT api.conf.wsgi celeryworker: celery -A api.conf worker -l info celeryscheduler: celery -A api.conf beat From 94f54ee26c47e75cd3fabd64964e0bd9413bc4d8 Mon Sep 17 00:00:00 2001 From: Emile Swarts Date: Thu, 26 Sep 2024 15:25:16 +0100 Subject: [PATCH 27/86] Add debugging --- .copilot/phases/pre_build.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.copilot/phases/pre_build.sh b/.copilot/phases/pre_build.sh index 27c33abd08..426aadc184 100644 --- a/.copilot/phases/pre_build.sh +++ b/.copilot/phases/pre_build.sh @@ -29,6 +29,13 @@ EOF update_pip_file_for_dbt_platform() { sed -i 's/\[packages\]/[packages]\nendesive = "~=1.5.9"\npython-pkcs11 = "~=0.7.0"\npykcs11 = "~=1.4.4"\n/' Pipfile pipenv lock + + echo "PIPFILE ---" + cat Pipfile + echo + echo + echo "PIPFILE LOCK ---" + cat Pipfile.lock } main() { From f1b9f999d869ab1da9211a4b00e3d1e7650974c7 Mon Sep 17 00:00:00 2001 From: Emile Swarts Date: Thu, 26 Sep 2024 15:47:28 +0100 Subject: [PATCH 28/86] Temporarily disable gevent workers --- Procfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Procfile b/Procfile index bb44317f3f..290e459db9 100644 --- a/Procfile +++ b/Procfile @@ -1,4 +1,4 @@ web: SWIG_LIB=/home/vcap/deps/0/apt/usr/share/swig4.0 CFLAGS=-I/home/vcap/deps/1/python/include/python3.9.18m pip3 install endesive==1.5.9 && python manage.py migrate && gunicorn --worker-class gevent -c api/conf/gconfig.py -b 0.0.0.0:$PORT api.conf.wsgi -web-dbt-platform: ls -al /layers/paketo-buildpacks_pipenv-install/packages/workspace-dqq3IVyd/lib/python3.9/site-packages/ && python manage.py migrate && gunicorn --worker-class gevent -c api/conf/gconfig-dbt-platform.py -b 0.0.0.0:$PORT api.conf.wsgi +web-dbt-platform: python manage.py migrate && gunicorn -c api/conf/gconfig-dbt-platform.py -b 0.0.0.0:$PORT api.conf.wsgi celeryworker: celery -A api.conf worker -l info celeryscheduler: celery -A api.conf beat From 18140b13041d560d9c2611a838f18ec4df1dc777 Mon Sep 17 00:00:00 2001 From: James Francis Date: Thu, 26 Sep 2024 16:04:47 +0100 Subject: [PATCH 29/86] set python version for pyenv --- .gitignore | 1 - .python-version | 1 + Pipfile | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 .python-version diff --git a/.gitignore b/.gitignore index b52ccb6279..1d484007a7 100644 --- a/.gitignore +++ b/.gitignore @@ -171,7 +171,6 @@ bank-holidays.csv /test_helpers/test_endpoints/results/*.csv *.p12 -.python-version # pii file .pii-secret-hook diff --git a/.python-version b/.python-version new file mode 100644 index 0000000000..bd28b9c5c2 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.9 diff --git a/Pipfile b/Pipfile index dd389c8038..5efe7d68be 100644 --- a/Pipfile +++ b/Pipfile @@ -54,7 +54,7 @@ cryptography = "~=43.0.1" sentry-sdk = "~=2.8.0" elastic-apm = "~=6.7.2" gunicorn = "~=22.0.0" -gevent = "~=24.2.1" +gevent = "~=23.9.1" xmltodict = "~=0.12.0" Pillow = "~=10.3.0" django-phonenumber-field = "==6.4.0" From b069316b5965cd07b724e06c388645e7867fad08 Mon Sep 17 00:00:00 2001 From: James Francis Date: Thu, 26 Sep 2024 16:18:47 +0100 Subject: [PATCH 30/86] revert backwards compatible changes --- .copilot/phases/pre_build.sh | 57 +++----- .python-version | 1 - Pipfile.lock | 268 +++++++++++++++++++++++++++++++++++ 3 files changed, 286 insertions(+), 40 deletions(-) delete mode 100644 .python-version diff --git a/.copilot/phases/pre_build.sh b/.copilot/phases/pre_build.sh index 426aadc184..0bc9486520 100644 --- a/.copilot/phases/pre_build.sh +++ b/.copilot/phases/pre_build.sh @@ -3,44 +3,23 @@ # Exit early if something goes wrong set -e -update_git_submodules() { - git_clone_base_url="https://codestar-connections.eu-west-2.amazonaws.com/git-http/$AWS_ACCOUNT_ID/eu-west-2/$CODESTAR_CONNECTION_ID/uktrade" - - git config --global credential.helper '!aws codecommit credential-helper $@' - git config --global credential.UseHttpPath true - - cat < ./.gitmodules - [submodule "lite-content"] - path = lite_content - url = $git_clone_base_url/lite-content.git - branch = master - [submodule "lite_routing"] - path = lite_routing - url = $git_clone_base_url/lite-routing.git - branch = main - [submodule "django_db_anonymiser"] - path = django_db_anonymiser - url = $git_clone_base_url/django-db-anonymiser.git +git_clone_base_url="https://codestar-connections.eu-west-2.amazonaws.com/git-http/$AWS_ACCOUNT_ID/eu-west-2/$CODESTAR_CONNECTION_ID/uktrade" + +git config --global credential.helper '!aws codecommit credential-helper $@' +git config --global credential.UseHttpPath true + +cat < ./.gitmodules +[submodule "lite-content"] +path = lite_content +url = $git_clone_base_url/lite-content.git +branch = master +[submodule "lite_routing"] +path = lite_routing +url = $git_clone_base_url/lite-routing.git +branch = main +[submodule "django_db_anonymiser"] +path = django_db_anonymiser +url = $git_clone_base_url/django-db-anonymiser.git EOF - git submodule update --init --remote --recursive -} - -update_pip_file_for_dbt_platform() { - sed -i 's/\[packages\]/[packages]\nendesive = "~=1.5.9"\npython-pkcs11 = "~=0.7.0"\npykcs11 = "~=1.4.4"\n/' Pipfile - pipenv lock - - echo "PIPFILE ---" - cat Pipfile - echo - echo - echo "PIPFILE LOCK ---" - cat Pipfile.lock -} - -main() { - update_git_submodules - update_pip_file_for_dbt_platform -} - -main +git submodule update --init --remote --recursive diff --git a/.python-version b/.python-version deleted file mode 100644 index bd28b9c5c2..0000000000 --- a/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.9 diff --git a/Pipfile.lock b/Pipfile.lock index 0dab1ebf35..cf4044a480 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -25,6 +25,14 @@ "markers": "python_version >= '3.6'", "version": "==5.2.0" }, + "appnope": { + "hashes": [ + "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", + "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c" + ], + "markers": "sys_platform == 'darwin'", + "version": "==0.1.4" + }, "asgiref": { "hashes": [ "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47", @@ -33,6 +41,13 @@ "markers": "python_version >= '3.8'", "version": "==3.8.1" }, + "asn1crypto": { + "hashes": [ + "sha256:13ae38502be632115abf8a24cbe5f4da52e3b5231990aff31123c805306ccb9c", + "sha256:db4e40728b728508912cbb3d44f19ce188f218e9eba635821bb4b68564f8fd67" + ], + "version": "==1.5.1" + }, "async-timeout": { "hashes": [ "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", @@ -41,6 +56,14 @@ "markers": "python_version >= '3.7'", "version": "==4.0.3" }, + "attrs": { + "hashes": [ + "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", + "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2" + ], + "markers": "python_version >= '3.7'", + "version": "==24.2.0" + }, "autopep8": { "hashes": [ "sha256:8d6c87eba648fdcfc83e29b788910b8643171c395d9c4bcf115ece035b9c9dda", @@ -64,6 +87,39 @@ "markers": "python_version >= '3.7'", "version": "==2.2.1" }, + "bcrypt": { + "hashes": [ + "sha256:096a15d26ed6ce37a14c1ac1e48119660f21b24cba457f160a4b830f3fe6b5cb", + "sha256:0da52759f7f30e83f1e30a888d9163a81353ef224d82dc58eb5bb52efcabc399", + "sha256:1bb429fedbe0249465cdd85a58e8376f31bb315e484f16e68ca4c786dcc04291", + "sha256:1d84cf6d877918620b687b8fd1bf7781d11e8a0998f576c7aa939776b512b98d", + "sha256:1ee38e858bf5d0287c39b7a1fc59eec64bbf880c7d504d3a06a96c16e14058e7", + "sha256:1ff39b78a52cf03fdf902635e4c81e544714861ba3f0efc56558979dd4f09170", + "sha256:27fe0f57bb5573104b5a6de5e4153c60814c711b29364c10a75a54bb6d7ff48d", + "sha256:3413bd60460f76097ee2e0a493ccebe4a7601918219c02f503984f0a7ee0aebe", + "sha256:3698393a1b1f1fd5714524193849d0c6d524d33523acca37cd28f02899285060", + "sha256:373db9abe198e8e2c70d12b479464e0d5092cc122b20ec504097b5f2297ed184", + "sha256:39e1d30c7233cfc54f5c3f2c825156fe044efdd3e0b9d309512cc514a263ec2a", + "sha256:3bbbfb2734f0e4f37c5136130405332640a1e46e6b23e000eeff2ba8d005da68", + "sha256:3d3a6d28cb2305b43feac298774b997e372e56c7c7afd90a12b3dc49b189151c", + "sha256:5a1e8aa9b28ae28020a3ac4b053117fb51c57a010b9f969603ed885f23841458", + "sha256:61ed14326ee023917ecd093ee6ef422a72f3aec6f07e21ea5f10622b735538a9", + "sha256:655ea221910bcac76ea08aaa76df427ef8625f92e55a8ee44fbf7753dbabb328", + "sha256:762a2c5fb35f89606a9fde5e51392dad0cd1ab7ae64149a8b935fe8d79dd5ed7", + "sha256:77800b7147c9dc905db1cba26abe31e504d8247ac73580b4aa179f98e6608f34", + "sha256:8ac68872c82f1add6a20bd489870c71b00ebacd2e9134a8aa3f98a0052ab4b0e", + "sha256:8d7bb9c42801035e61c109c345a28ed7e84426ae4865511eb82e913df18f58c2", + "sha256:8f6ede91359e5df88d1f5c1ef47428a4420136f3ce97763e31b86dd8280fbdf5", + "sha256:9c1c4ad86351339c5f320ca372dfba6cb6beb25e8efc659bedd918d921956bae", + "sha256:c02d944ca89d9b1922ceb8a46460dd17df1ba37ab66feac4870f6862a1533c00", + "sha256:c52aac18ea1f4a4f65963ea4f9530c306b56ccd0c6f8c8da0c06976e34a6e841", + "sha256:cb2a8ec2bc07d3553ccebf0746bbf3d19426d1c6d1adbd4fa48925f66af7b9e8", + "sha256:cf69eaf5185fd58f268f805b505ce31f9b9fc2d64b376642164e9244540c1221", + "sha256:f4f4acf526fcd1c34e7ce851147deedd4e26e6402369304220250598b26448db" + ], + "markers": "python_version >= '3.7'", + "version": "==4.2.0" + }, "billiard": { "hashes": [ "sha256:12b641b0c539073fc8d3f5b8b7be998956665c4233c7c1fcd66a7e677c4fb36f", @@ -89,6 +145,13 @@ "markers": "python_version >= '3.7'", "version": "==1.29.165" }, + "cached-property": { + "hashes": [ + "sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130", + "sha256:df4f613cf7ad9a588cc381aaf4a512d26265ecebd5eb9e1ba12f1319eb85a6a0" + ], + "version": "==1.5.2" + }, "cairocffi": { "hashes": [ "sha256:2e48ee864884ec4a3a34bfa8c9ab9999f688286eb714a15a43ec9d068c36557b", @@ -710,6 +773,14 @@ "markers": "python_version >= '3.7'", "version": "==2.5.3" }, + "endesive": { + "hashes": [ + "sha256:20e279e1527e5259a0788285ac0397310ee1f3a51fc1b07d7a9261a4355e1cdb", + "sha256:e55fe62093be0f928d8513c821307d10749ecdf3712c7bb7db4e49916de6d466" + ], + "index": "pypi", + "version": "==1.5.12" + }, "et-xmlfile": { "hashes": [ "sha256:8eb9e2bc2f8c97e37a2dc85a09ecdcdec9d8a396530a6d5a33b30b9a92da0c5c", @@ -1068,6 +1139,150 @@ "markers": "python_version >= '3.6' and python_version < '4'", "version": "==0.1.2" }, + "lxml": { + "hashes": [ + "sha256:01220dca0d066d1349bd6a1726856a78f7929f3878f7e2ee83c296c69495309e", + "sha256:02ced472497b8362c8e902ade23e3300479f4f43e45f4105c85ef43b8db85229", + "sha256:052d99051e77a4f3e8482c65014cf6372e61b0a6f4fe9edb98503bb5364cfee3", + "sha256:07da23d7ee08577760f0a71d67a861019103e4812c87e2fab26b039054594cc5", + "sha256:094cb601ba9f55296774c2d57ad68730daa0b13dc260e1f941b4d13678239e70", + "sha256:0a7056921edbdd7560746f4221dca89bb7a3fe457d3d74267995253f46343f15", + "sha256:0c120f43553ec759f8de1fee2f4794452b0946773299d44c36bfe18e83caf002", + "sha256:0d7b36afa46c97875303a94e8f3ad932bf78bace9e18e603f2085b652422edcd", + "sha256:0fdf3a3059611f7585a78ee10399a15566356116a4288380921a4b598d807a22", + "sha256:109fa6fede314cc50eed29e6e56c540075e63d922455346f11e4d7a036d2b8cf", + "sha256:146173654d79eb1fc97498b4280c1d3e1e5d58c398fa530905c9ea50ea849b22", + "sha256:1473427aff3d66a3fa2199004c3e601e6c4500ab86696edffdbc84954c72d832", + "sha256:1483fd3358963cc5c1c9b122c80606a3a79ee0875bcac0204149fa09d6ff2727", + "sha256:168f2dfcfdedf611eb285efac1516c8454c8c99caf271dccda8943576b67552e", + "sha256:17e8d968d04a37c50ad9c456a286b525d78c4a1c15dd53aa46c1d8e06bf6fa30", + "sha256:18feb4b93302091b1541221196a2155aa296c363fd233814fa11e181adebc52f", + "sha256:1afe0a8c353746e610bd9031a630a95bcfb1a720684c3f2b36c4710a0a96528f", + "sha256:1d04f064bebdfef9240478f7a779e8c5dc32b8b7b0b2fc6a62e39b928d428e51", + "sha256:1fdc9fae8dd4c763e8a31e7630afef517eab9f5d5d31a278df087f307bf601f4", + "sha256:1ffc23010330c2ab67fac02781df60998ca8fe759e8efde6f8b756a20599c5de", + "sha256:20094fc3f21ea0a8669dc4c61ed7fa8263bd37d97d93b90f28fc613371e7a875", + "sha256:213261f168c5e1d9b7535a67e68b1f59f92398dd17a56d934550837143f79c42", + "sha256:218c1b2e17a710e363855594230f44060e2025b05c80d1f0661258142b2add2e", + "sha256:23e0553b8055600b3bf4a00b255ec5c92e1e4aebf8c2c09334f8368e8bd174d6", + "sha256:25f1b69d41656b05885aa185f5fdf822cb01a586d1b32739633679699f220391", + "sha256:2b3778cb38212f52fac9fe913017deea2fdf4eb1a4f8e4cfc6b009a13a6d3fcc", + "sha256:2bc9fd5ca4729af796f9f59cd8ff160fe06a474da40aca03fcc79655ddee1a8b", + "sha256:2c226a06ecb8cdef28845ae976da407917542c5e6e75dcac7cc33eb04aaeb237", + "sha256:2c3406b63232fc7e9b8783ab0b765d7c59e7c59ff96759d8ef9632fca27c7ee4", + "sha256:2c86bf781b12ba417f64f3422cfc302523ac9cd1d8ae8c0f92a1c66e56ef2e86", + "sha256:2d9b8d9177afaef80c53c0a9e30fa252ff3036fb1c6494d427c066a4ce6a282f", + "sha256:2dec2d1130a9cda5b904696cec33b2cfb451304ba9081eeda7f90f724097300a", + "sha256:2dfab5fa6a28a0b60a20638dc48e6343c02ea9933e3279ccb132f555a62323d8", + "sha256:2ecdd78ab768f844c7a1d4a03595038c166b609f6395e25af9b0f3f26ae1230f", + "sha256:315f9542011b2c4e1d280e4a20ddcca1761993dda3afc7a73b01235f8641e903", + "sha256:36aef61a1678cb778097b4a6eeae96a69875d51d1e8f4d4b491ab3cfb54b5a03", + "sha256:384aacddf2e5813a36495233b64cb96b1949da72bef933918ba5c84e06af8f0e", + "sha256:3879cc6ce938ff4eb4900d901ed63555c778731a96365e53fadb36437a131a99", + "sha256:3c174dc350d3ec52deb77f2faf05c439331d6ed5e702fc247ccb4e6b62d884b7", + "sha256:3eb44520c4724c2e1a57c0af33a379eee41792595023f367ba3952a2d96c2aab", + "sha256:406246b96d552e0503e17a1006fd27edac678b3fcc9f1be71a2f94b4ff61528d", + "sha256:41ce1f1e2c7755abfc7e759dc34d7d05fd221723ff822947132dc934d122fe22", + "sha256:423b121f7e6fa514ba0c7918e56955a1d4470ed35faa03e3d9f0e3baa4c7e492", + "sha256:44264ecae91b30e5633013fb66f6ddd05c006d3e0e884f75ce0b4755b3e3847b", + "sha256:482c2f67761868f0108b1743098640fbb2a28a8e15bf3f47ada9fa59d9fe08c3", + "sha256:4b0c7a688944891086ba192e21c5229dea54382f4836a209ff8d0a660fac06be", + "sha256:4c1fefd7e3d00921c44dc9ca80a775af49698bbfd92ea84498e56acffd4c5469", + "sha256:4e109ca30d1edec1ac60cdbe341905dc3b8f55b16855e03a54aaf59e51ec8c6f", + "sha256:501d0d7e26b4d261fca8132854d845e4988097611ba2531408ec91cf3fd9d20a", + "sha256:516f491c834eb320d6c843156440fe7fc0d50b33e44387fcec5b02f0bc118a4c", + "sha256:51806cfe0279e06ed8500ce19479d757db42a30fd509940b1701be9c86a5ff9a", + "sha256:562e7494778a69086f0312ec9689f6b6ac1c6b65670ed7d0267e49f57ffa08c4", + "sha256:56b9861a71575f5795bde89256e7467ece3d339c9b43141dbdd54544566b3b94", + "sha256:5b8f5db71b28b8c404956ddf79575ea77aa8b1538e8b2ef9ec877945b3f46442", + "sha256:5c2fb570d7823c2bbaf8b419ba6e5662137f8166e364a8b2b91051a1fb40ab8b", + "sha256:5c54afdcbb0182d06836cc3d1be921e540be3ebdf8b8a51ee3ef987537455f84", + "sha256:5d6a6972b93c426ace71e0be9a6f4b2cfae9b1baed2eed2006076a746692288c", + "sha256:609251a0ca4770e5a8768ff902aa02bf636339c5a93f9349b48eb1f606f7f3e9", + "sha256:62d172f358f33a26d6b41b28c170c63886742f5b6772a42b59b4f0fa10526cb1", + "sha256:62f7fdb0d1ed2065451f086519865b4c90aa19aed51081979ecd05a21eb4d1be", + "sha256:658f2aa69d31e09699705949b5fc4719cbecbd4a97f9656a232e7d6c7be1a367", + "sha256:65ab5685d56914b9a2a34d67dd5488b83213d680b0c5d10b47f81da5a16b0b0e", + "sha256:68934b242c51eb02907c5b81d138cb977b2129a0a75a8f8b60b01cb8586c7b21", + "sha256:68b87753c784d6acb8a25b05cb526c3406913c9d988d51f80adecc2b0775d6aa", + "sha256:69959bd3167b993e6e710b99051265654133a98f20cec1d9b493b931942e9c16", + "sha256:6a7095eeec6f89111d03dabfe5883a1fd54da319c94e0fb104ee8f23616b572d", + "sha256:6b038cc86b285e4f9fea2ba5ee76e89f21ed1ea898e287dc277a25884f3a7dfe", + "sha256:6ba0d3dcac281aad8a0e5b14c7ed6f9fa89c8612b47939fc94f80b16e2e9bc83", + "sha256:6e91cf736959057f7aac7adfc83481e03615a8e8dd5758aa1d95ea69e8931dba", + "sha256:6ee8c39582d2652dcd516d1b879451500f8db3fe3607ce45d7c5957ab2596040", + "sha256:6f651ebd0b21ec65dfca93aa629610a0dbc13dbc13554f19b0113da2e61a4763", + "sha256:71a8dd38fbd2f2319136d4ae855a7078c69c9a38ae06e0c17c73fd70fc6caad8", + "sha256:74068c601baff6ff021c70f0935b0c7bc528baa8ea210c202e03757c68c5a4ff", + "sha256:7437237c6a66b7ca341e868cda48be24b8701862757426852c9b3186de1da8a2", + "sha256:747a3d3e98e24597981ca0be0fd922aebd471fa99d0043a3842d00cdcad7ad6a", + "sha256:74bcb423462233bc5d6066e4e98b0264e7c1bed7541fff2f4e34fe6b21563c8b", + "sha256:78d9b952e07aed35fe2e1a7ad26e929595412db48535921c5013edc8aa4a35ce", + "sha256:7b1cd427cb0d5f7393c31b7496419da594fe600e6fdc4b105a54f82405e6626c", + "sha256:7d3d1ca42870cdb6d0d29939630dbe48fa511c203724820fc0fd507b2fb46577", + "sha256:7e2f58095acc211eb9d8b5771bf04df9ff37d6b87618d1cbf85f92399c98dae8", + "sha256:7f41026c1d64043a36fda21d64c5026762d53a77043e73e94b71f0521939cc71", + "sha256:81b4e48da4c69313192d8c8d4311e5d818b8be1afe68ee20f6385d0e96fc9512", + "sha256:86a6b24b19eaebc448dc56b87c4865527855145d851f9fc3891673ff97950540", + "sha256:874a216bf6afaf97c263b56371434e47e2c652d215788396f60477540298218f", + "sha256:89e043f1d9d341c52bf2af6d02e6adde62e0a46e6755d5eb60dc6e4f0b8aeca2", + "sha256:8c72e9563347c7395910de6a3100a4840a75a6f60e05af5e58566868d5eb2d6a", + "sha256:8dc2c0395bea8254d8daebc76dcf8eb3a95ec2a46fa6fae5eaccee366bfe02ce", + "sha256:8f0de2d390af441fe8b2c12626d103540b5d850d585b18fcada58d972b74a74e", + "sha256:92e67a0be1639c251d21e35fe74df6bcc40cba445c2cda7c4a967656733249e2", + "sha256:94d6c3782907b5e40e21cadf94b13b0842ac421192f26b84c45f13f3c9d5dc27", + "sha256:97acf1e1fd66ab53dacd2c35b319d7e548380c2e9e8c54525c6e76d21b1ae3b1", + "sha256:9ada35dd21dc6c039259596b358caab6b13f4db4d4a7f8665764d616daf9cc1d", + "sha256:9c52100e2c2dbb0649b90467935c4b0de5528833c76a35ea1a2691ec9f1ee7a1", + "sha256:9e41506fec7a7f9405b14aa2d5c8abbb4dbbd09d88f9496958b6d00cb4d45330", + "sha256:9e4b47ac0f5e749cfc618efdf4726269441014ae1d5583e047b452a32e221920", + "sha256:9fb81d2824dff4f2e297a276297e9031f46d2682cafc484f49de182aa5e5df99", + "sha256:a0eabd0a81625049c5df745209dc7fcef6e2aea7793e5f003ba363610aa0a3ff", + "sha256:a3d819eb6f9b8677f57f9664265d0a10dd6551d227afb4af2b9cd7bdc2ccbf18", + "sha256:a87de7dd873bf9a792bf1e58b1c3887b9264036629a5bf2d2e6579fe8e73edff", + "sha256:aa617107a410245b8660028a7483b68e7914304a6d4882b5ff3d2d3eb5948d8c", + "sha256:aac0bbd3e8dd2d9c45ceb82249e8bdd3ac99131a32b4d35c8af3cc9db1657179", + "sha256:ab6dd83b970dc97c2d10bc71aa925b84788c7c05de30241b9e96f9b6d9ea3080", + "sha256:ace2c2326a319a0bb8a8b0e5b570c764962e95818de9f259ce814ee666603f19", + "sha256:ae5fe5c4b525aa82b8076c1a59d642c17b6e8739ecf852522c6321852178119d", + "sha256:b11a5d918a6216e521c715b02749240fb07ae5a1fefd4b7bf12f833bc8b4fe70", + "sha256:b1c8c20847b9f34e98080da785bb2336ea982e7f913eed5809e5a3c872900f32", + "sha256:b369d3db3c22ed14c75ccd5af429086f166a19627e84a8fdade3f8f31426e52a", + "sha256:b710bc2b8292966b23a6a0121f7a6c51d45d2347edcc75f016ac123b8054d3f2", + "sha256:bd96517ef76c8654446fc3db9242d019a1bb5fe8b751ba414765d59f99210b79", + "sha256:c00f323cc00576df6165cc9d21a4c21285fa6b9989c5c39830c3903dc4303ef3", + "sha256:c162b216070f280fa7da844531169be0baf9ccb17263cf5a8bf876fcd3117fa5", + "sha256:c1a69e58a6bb2de65902051d57fde951febad631a20a64572677a1052690482f", + "sha256:c1f794c02903c2824fccce5b20c339a1a14b114e83b306ff11b597c5f71a1c8d", + "sha256:c24037349665434f375645fa9d1f5304800cec574d0310f618490c871fd902b3", + "sha256:c300306673aa0f3ed5ed9372b21867690a17dba38c68c44b287437c362ce486b", + "sha256:c56a1d43b2f9ee4786e4658c7903f05da35b923fb53c11025712562d5cc02753", + "sha256:c6379f35350b655fd817cd0d6cbeef7f265f3ae5fedb1caae2eb442bbeae9ab9", + "sha256:c802e1c2ed9f0c06a65bc4ed0189d000ada8049312cfeab6ca635e39c9608957", + "sha256:cb83f8a875b3d9b458cada4f880fa498646874ba4011dc974e071a0a84a1b033", + "sha256:cf120cce539453ae086eacc0130a324e7026113510efa83ab42ef3fcfccac7fb", + "sha256:dd36439be765e2dde7660212b5275641edbc813e7b24668831a5c8ac91180656", + "sha256:dd5350b55f9fecddc51385463a4f67a5da829bc741e38cf689f38ec9023f54ab", + "sha256:df5c7333167b9674aa8ae1d4008fa4bc17a313cc490b2cca27838bbdcc6bb15b", + "sha256:e63601ad5cd8f860aa99d109889b5ac34de571c7ee902d6812d5d9ddcc77fa7d", + "sha256:e92ce66cd919d18d14b3856906a61d3f6b6a8500e0794142338da644260595cd", + "sha256:e99f5507401436fdcc85036a2e7dc2e28d962550afe1cbfc07c40e454256a859", + "sha256:ea2e2f6f801696ad7de8aec061044d6c8c0dd4037608c7cab38a9a4d316bfb11", + "sha256:eafa2c8658f4e560b098fe9fc54539f86528651f61849b22111a9b107d18910c", + "sha256:ecd4ad8453ac17bc7ba3868371bffb46f628161ad0eefbd0a855d2c8c32dd81a", + "sha256:ee70d08fd60c9565ba8190f41a46a54096afa0eeb8f76bd66f2c25d3b1b83005", + "sha256:eec1bb8cdbba2925bedc887bc0609a80e599c75b12d87ae42ac23fd199445654", + "sha256:ef0c1fe22171dd7c7c27147f2e9c3e86f8bdf473fed75f16b0c2e84a5030ce80", + "sha256:f2901429da1e645ce548bf9171784c0f74f0718c3f6150ce166be39e4dd66c3e", + "sha256:f422a209d2455c56849442ae42f25dbaaba1c6c3f501d58761c619c7836642ec", + "sha256:f65e5120863c2b266dbcc927b306c5b78e502c71edf3295dfcb9501ec96e5fc7", + "sha256:f7d4a670107d75dfe5ad080bed6c341d18c4442f9378c9f58e5851e86eb79965", + "sha256:f914c03e6a31deb632e2daa881fe198461f4d06e57ac3d0e05bbcab8eae01945", + "sha256:fb66442c2546446944437df74379e9cf9e9db353e61301d1a0e26482f43f0dd8" + ], + "markers": "python_version >= '3.6'", + "version": "==5.3.0" + }, "markdown": { "hashes": [ "sha256:225c6123522495d4119a90b3a3ba31a1e87a70369e03f14799ea9c0d7183a3d6", @@ -1252,6 +1467,13 @@ "markers": "python_version >= '3.7'", "version": "==0.43b0" }, + "oscrypto": { + "hashes": [ + "sha256:2b2f1d2d42ec152ca90ccb5682f3e051fb55986e1b170ebde472b133713e7085", + "sha256:6f5fef59cb5b3708321db7cca56aed8ad7e662853351e7991fcf60ec606d47a4" + ], + "version": "==1.3.0" + }, "packaging": { "hashes": [ "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", @@ -1260,6 +1482,14 @@ "markers": "python_version >= '3.8'", "version": "==24.1" }, + "paramiko": { + "hashes": [ + "sha256:1fedf06b085359051cd7d0d270cebe19e755a8a921cc2ddbfa647fb0cd7d68f9", + "sha256:ad11e540da4f55cedda52931f1a3f812a8238a7af7f62a60de538cd80bb28124" + ], + "markers": "python_version >= '3.6'", + "version": "==3.5.0" + }, "parso": { "hashes": [ "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", @@ -1456,6 +1686,37 @@ "markers": "python_version >= '3.8'", "version": "==2.9.0" }, + "pykcs11": { + "hashes": [ + "sha256:812336cab2c51c013be6b132e3636d6ed27c14588b4a448871847cc750d10e2b" + ], + "index": "pypi", + "version": "==1.4.4" + }, + "pynacl": { + "hashes": [ + "sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858", + "sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d", + "sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93", + "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1", + "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92", + "sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff", + "sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba", + "sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394", + "sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b", + "sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543" + ], + "markers": "python_version >= '3.6'", + "version": "==1.5.0" + }, + "pyopenssl": { + "hashes": [ + "sha256:4247f0dbe3748d560dcbb2ff3ea01af0f9a1a001ef5f7c4c647956ed8cbf0e95", + "sha256:967d5719b12b243588573f39b0c677637145c7a1ffedcd495a487e58177fbb8d" + ], + "markers": "python_version >= '3.7'", + "version": "==24.2.1" + }, "pypdf2": { "hashes": [ "sha256:20929fad10a3b4890862f65f3a46f563cfdf53132faae5193b54e18658467a60", @@ -1481,6 +1742,13 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==2.9.0.post0" }, + "python-pkcs11": { + "hashes": [ + "sha256:9737e0c24cabb8bc9d48bf8c57c3df2a70f8cdd96b70c50290803286f9e46bf7" + ], + "index": "pypi", + "version": "==0.7.0" + }, "pytz": { "hashes": [ "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a", From 4eb9be1452e55661f01369764223df1365a9407e Mon Sep 17 00:00:00 2001 From: James Francis Date: Fri, 27 Sep 2024 11:52:19 +0100 Subject: [PATCH 31/86] add entry point for data anonymise --- Procfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Procfile b/Procfile index 290e459db9..7209272127 100644 --- a/Procfile +++ b/Procfile @@ -1,4 +1,5 @@ web: SWIG_LIB=/home/vcap/deps/0/apt/usr/share/swig4.0 CFLAGS=-I/home/vcap/deps/1/python/include/python3.9.18m pip3 install endesive==1.5.9 && python manage.py migrate && gunicorn --worker-class gevent -c api/conf/gconfig.py -b 0.0.0.0:$PORT api.conf.wsgi web-dbt-platform: python manage.py migrate && gunicorn -c api/conf/gconfig-dbt-platform.py -b 0.0.0.0:$PORT api.conf.wsgi +dump-and-anonymise: python manage.py dump_and_anonymise celeryworker: celery -A api.conf worker -l info celeryscheduler: celery -A api.conf beat From 2870b1c5a329f49fd41b0c98a1b158adeb47f75f Mon Sep 17 00:00:00 2001 From: Gurdeep Atwal Date: Mon, 30 Sep 2024 12:18:10 +0100 Subject: [PATCH 32/86] update readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 72a4209f7d..93fcc825e6 100644 --- a/README.md +++ b/README.md @@ -154,6 +154,7 @@ Gegenerate diagrams ## Running tests - `pipenv run pytest` +- `pipenv run pytest --reuse-db` to speed up tests ## Running code coverage From fb4f697a86b2db0e1ca18e7d04147879d67bbf9d Mon Sep 17 00:00:00 2001 From: Gareth Pitt-Nash Date: Tue, 1 Oct 2024 12:57:42 +0100 Subject: [PATCH 33/86] fix: update pipfile.lock for pykcs11 --- Pipfile.lock | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index cf4044a480..0b091eab83 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1688,10 +1688,23 @@ }, "pykcs11": { "hashes": [ - "sha256:812336cab2c51c013be6b132e3636d6ed27c14588b4a448871847cc750d10e2b" - ], - "index": "pypi", - "version": "==1.4.4" + "sha256:02a06e5058becb74463ec1f99403d66ea7891d08172e6e3afeec3c402d4a70e6", + "sha256:02ad45104550c9fda1919ed9da8ac6cedb6b1f16e10c21d38e9c004b08014944", + "sha256:210b3d1a9f658fd756e4a9bf8e84de86eb3f06dd7edcaad6dced20c1e2108748", + "sha256:39ab4cef6c724b35688d7ea2ffc1e2a02921f5f9e3a29398d95746ff216f6e73", + "sha256:43d746b0677f43cc634b9f7c4dab2d9ba6b1a83b931e2598247062f8ff641e07", + "sha256:4f2b19d95ccc731c88c83cfa5017044ff3c01df3bcbad9756997af071fc29bfd", + "sha256:50c9e19b61603a23c9a8df2adaf1a06c7695c433ae183528d615c414f01641cb", + "sha256:74093d40b8377c8c3cddbf5ac8f0035c0c2594690a0bf65c8ad77ea566fa4cc5", + "sha256:94f379688b34ffe321da78518e0595e492cfef84f38b4f00def63758ef37f678", + "sha256:ab92c042c105f68e8995559702e776caed7e8998b1403fec168e09cdbfd2c3f3", + "sha256:ae14da1602ff7b75b6f3af1a7e9602e167b3e51317c999b858f0dc2e883f21dd", + "sha256:b3076cab2aa78709b36c069b47352fa36f7608723ab3543146a4529e3ddf7bdc", + "sha256:f2cb84c28436d2e9b4de34588bc3a13670e0cef6b011e2ad6751c6687373c749", + "sha256:fa1b3c226de080e7b64276b299f6763508ed1b8c84122011846f25349a911ddf" + ], + "index": "pypi", + "version": "==1.5.16" }, "pynacl": { "hashes": [ From 14dda3507878a935d434ed38ec79842d56d19470 Mon Sep 17 00:00:00 2001 From: Gareth Pitt-Nash Date: Tue, 1 Oct 2024 14:11:58 +0100 Subject: [PATCH 34/86] fix: remove python-pkcs11 from pipfile.lock --- Pipfile.lock | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 0b091eab83..d1d7322a17 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1755,13 +1755,6 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==2.9.0.post0" }, - "python-pkcs11": { - "hashes": [ - "sha256:9737e0c24cabb8bc9d48bf8c57c3df2a70f8cdd96b70c50290803286f9e46bf7" - ], - "index": "pypi", - "version": "==0.7.0" - }, "pytz": { "hashes": [ "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a", From b79fbfa7b1bc05f0775b8914d89b29a7fe6a0160 Mon Sep 17 00:00:00 2001 From: Emile Swarts Date: Thu, 31 Oct 2024 10:32:39 +0000 Subject: [PATCH 35/86] Trigger deploy From 15fa8e7a50b176c9b7cb627442da10069ee77827 Mon Sep 17 00:00:00 2001 From: Emile Swarts Date: Thu, 31 Oct 2024 12:18:04 +0000 Subject: [PATCH 36/86] Trigger deploy From 234777ee578b8486048e448c3948f54fec6797c0 Mon Sep 17 00:00:00 2001 From: Emile Swarts Date: Fri, 1 Nov 2024 09:21:07 +0000 Subject: [PATCH 37/86] Trigger deploy From ebfc01b42237b1392f96966a4235920afd78197c Mon Sep 17 00:00:00 2001 From: Emile Swarts Date: Fri, 1 Nov 2024 15:24:38 +0000 Subject: [PATCH 38/86] Trigger deploy From 2635788e32c99343084bd9317ebe7ddcf5cfe4e1 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Thu, 31 Oct 2024 12:41:50 +0000 Subject: [PATCH 39/86] Add LicenceDecision model to concretely define a case outcome A case can have multiple outcomes and we create instances of this model for each outcome. --- api/cases/enums.py | 32 ++++++++++ api/cases/migrations/0067_licencedecision.py | 63 ++++++++++++++++++++ api/cases/models.py | 13 ++++ 3 files changed, 108 insertions(+) create mode 100644 api/cases/migrations/0067_licencedecision.py diff --git a/api/cases/enums.py b/api/cases/enums.py index 6376a92a49..6d21e6407c 100644 --- a/api/cases/enums.py +++ b/api/cases/enums.py @@ -4,6 +4,9 @@ from lite_content.lite_api import strings +SIEL_LICENCE_TEMPLATE_ID = "d159b195-9256-4a00-9bc8-1eb2cebfa1d2" +SIEL_REFUSAL_TEMPLATE_ID = "074d8a54-ee10-4dca-82ba-650460650342" + class CaseTypeReferenceEnum: OIEL = "oiel" @@ -408,3 +411,32 @@ class EnforcementXMLEntityTypes: (SITE, "site"), (ORGANISATION, "organisation"), ] + + +class LicenceDecisionType: + ISSUED = "issued" + REFUSED = "refused" + REVOKED = "revoked" + + choices = [ + (ISSUED, "issued"), + (REFUSED, "refused"), + (REVOKED, "revoked"), + ] + + decision_map = { + AdviceType.APPROVE: ISSUED, + AdviceType.REFUSE: REFUSED, + } + + @classmethod + def templates(cls): + return { + cls.ISSUED: SIEL_LICENCE_TEMPLATE_ID, + cls.REFUSED: SIEL_REFUSAL_TEMPLATE_ID, + cls.REVOKED: None, + } + + @classmethod + def advice_type_to_decision(cls, advice_type): + return cls.decision_map[advice_type] diff --git a/api/cases/migrations/0067_licencedecision.py b/api/cases/migrations/0067_licencedecision.py new file mode 100644 index 0000000000..a5cdebb8fa --- /dev/null +++ b/api/cases/migrations/0067_licencedecision.py @@ -0,0 +1,63 @@ +# Generated by Django 4.2.16 on 2024-11-01 11:48 + +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone +import model_utils.fields +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ("licences", "0019_auto_20210506_0340"), + ("cases", "0066_delete_casereviewdate"), + ] + + operations = [ + migrations.CreateModel( + name="LicenceDecision", + fields=[ + ( + "created_at", + model_utils.fields.AutoCreatedField( + default=django.utils.timezone.now, editable=False, verbose_name="created_at" + ), + ), + ( + "updated_at", + model_utils.fields.AutoLastModifiedField( + default=django.utils.timezone.now, editable=False, verbose_name="updated_at" + ), + ), + ("id", models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ( + "decision", + models.CharField( + choices=[("issued", "issued"), ("refused", "refused"), ("revoked", "revoked")], max_length=50 + ), + ), + ( + "case", + models.ForeignKey( + on_delete=django.db.models.deletion.DO_NOTHING, + related_name="licence_decisions", + to="cases.case", + ), + ), + ( + "licence", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.DO_NOTHING, + related_name="licence_decisions", + to="licences.licence", + ), + ), + ], + options={ + "abstract": False, + }, + ), + ] diff --git a/api/cases/models.py b/api/cases/models.py index 1735d392bd..f69016bc11 100644 --- a/api/cases/models.py +++ b/api/cases/models.py @@ -23,6 +23,7 @@ ECJUQueryType, AdviceLevel, EnforcementXMLEntityTypes, + LicenceDecisionType, ) from api.cases.helpers import working_days_in_range from api.cases.libraries.reference_code import generate_reference_code @@ -686,3 +687,15 @@ class EnforcementCheckID(models.Model): id = models.AutoField(primary_key=True) entity_id = models.UUIDField(unique=True) entity_type = models.CharField(choices=EnforcementXMLEntityTypes.choices, max_length=20) + + +class LicenceDecision(TimestampableModel): + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + case = models.ForeignKey(Case, on_delete=models.DO_NOTHING, related_name="licence_decisions") + decision = models.CharField(choices=LicenceDecisionType.choices, max_length=50, null=False, blank=False) + licence = models.ForeignKey( + "licences.Licence", on_delete=models.DO_NOTHING, related_name="licence_decisions", null=True, blank=True + ) + + def __str__(self): + return f"{self.case.reference_code} - {self.decision} ({self.created_at})" From e51943c709e4345bb9b34b6679b7c41303304700 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Thu, 31 Oct 2024 12:47:11 +0000 Subject: [PATCH 40/86] Add migration to back populate LicenceDecision instances These are created for issued, refused and revoked outcomes. We use CREATE_FINAL_RECOMMENDATION timestamp as the primary source when back populating licence decisions however this audit log is not available from the beginning. So for the case where this log is missing we just take the licence decision document creation date as the decision date. --- api/cases/enums.py | 4 + .../0068_populate_licence_decisions.py | 121 ++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 api/cases/migrations/0068_populate_licence_decisions.py diff --git a/api/cases/enums.py b/api/cases/enums.py index 6d21e6407c..8113cd8d60 100644 --- a/api/cases/enums.py +++ b/api/cases/enums.py @@ -440,3 +440,7 @@ def templates(cls): @classmethod def advice_type_to_decision(cls, advice_type): return cls.decision_map[advice_type] + + @classmethod + def get_template(cls, decision): + return cls.templates()[decision] diff --git a/api/cases/migrations/0068_populate_licence_decisions.py b/api/cases/migrations/0068_populate_licence_decisions.py new file mode 100644 index 0000000000..21480c6c7a --- /dev/null +++ b/api/cases/migrations/0068_populate_licence_decisions.py @@ -0,0 +1,121 @@ +# Generated by Django 4.2.16 on 2024-10-31 12:43 +import functools +import operator + +from django.contrib.postgres.aggregates import ArrayAgg +from django.db import migrations, transaction +from django.db.models import Case as DBCase, Q, TextField, Value, When +from django.db.models.functions import Cast + +from api.audit_trail.enums import AuditType +from api.cases.enums import AdviceType, LicenceDecisionType +from api.licences.enums import LicenceStatus + + +@transaction.atomic +def populate_licence_decisions(apps, schema_editor): + """ + To back populate licence decision we primarily take the timestamp of CREATED_FINAL_RECOMMENDATION audit log + as the decision date. This is emitted when the case is finalised and all decision documents are published + to Exporter so this is the accurate decision date. + However this event is introduced at a later point of time and not available for cases. In these cases + we fallback to using the document generation date as the decision date. Usually these two steps happen + without much time difference (generating documents and publishing them) so it is a reliable approximation. + We also observed that only few cases differ and maximum variation is ~3days which doesn't affect reports. + """ + + Audit = apps.get_model("audit_trail", "Audit") + GeneratedCaseDocument = apps.get_model("generated_documents", "GeneratedCaseDocument") + LicenceDecision = apps.get_model("cases", "LicenceDecision") + + licence_decisions = [] + + final_decision_qs = Audit.objects.filter(verb=AuditType.CREATED_FINAL_RECOMMENDATION).order_by("-created_at") + + document_qs = ( + GeneratedCaseDocument.objects.filter( + template_id__in=LicenceDecisionType.templates().values(), + advice_type__in=[AdviceType.APPROVE, AdviceType.REFUSE], + visible_to_exporter=True, + safe=True, + ) + .annotate(template_ids=ArrayAgg(Cast("template_id", output_field=TextField()), distinct=True)) + .filter( + functools.reduce( + operator.or_, + [Q(template_ids=[template_id]) for template_id in LicenceDecisionType.templates().values()], + ) + ) + .annotate( + decision=DBCase( + *[ + When(template_ids=[template_id], then=Value(decision)) + for decision, template_id in LicenceDecisionType.templates().items() + ] + ) + ) + ) + + # When running tests audit entries are not available so filtering documents + # the audit log created date earlier fails + if final_decision_qs: + earliest_audit_log = final_decision_qs.last() + document_qs = document_qs.filter( + created_at__date__lt=earliest_audit_log.created_at.date(), + ) + + for audit_log in final_decision_qs: + advice_type = audit_log.payload["decision"] + if advice_type not in [AdviceType.APPROVE, AdviceType.REFUSE]: + continue + + decision = LicenceDecisionType.advice_type_to_decision(advice_type) + licence_decisions.append( + LicenceDecision( + case_id=str(audit_log.target_object_id), + decision=decision, + created_at=audit_log.created_at, + ) + ) + + for document in document_qs: + licence_decisions.append( + LicenceDecision( + case_id=str(document.case_id), + decision=document.decision, + created_at=document.created_at, + ) + ) + + # Revoked cases + revoked_audit_qs = Audit.objects.filter( + payload__status=LicenceStatus.REVOKED, + verb=AuditType.LICENCE_UPDATED_STATUS, + ) + + for audit_log in revoked_audit_qs: + case_id = audit_log.target_object_id + licence_decisions.append( + LicenceDecision( + case_id=case_id, + decision=LicenceDecisionType.REVOKED, + created_at=audit_log.created_at, + ) + ) + + LicenceDecision.objects.bulk_create(licence_decisions) + + +class Migration(migrations.Migration): + + dependencies = [ + ("cases", "0067_licencedecision"), + ("generated_documents", "0002_alter_generatedcasedocument_advice_type"), + ] + + operations = [ + migrations.RunPython( + populate_licence_decisions, + migrations.RunPython.noop, + ), + ] From 698c084efbd2765790ada57cb9b9e0d86e64b9b7 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Tue, 29 Oct 2024 12:11:38 +0000 Subject: [PATCH 41/86] Remove unsupported licence type related code --- api/cases/views/views.py | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/api/cases/views/views.py b/api/cases/views/views.py index 1d4bdbb2ae..327f282abe 100644 --- a/api/cases/views/views.py +++ b/api/cases/views/views.py @@ -21,11 +21,7 @@ from api.audit_trail import service as audit_trail_service from api.audit_trail.enums import AuditType from api.cases import notify -from api.cases.enums import ( - CaseTypeSubTypeEnum, - AdviceType, - AdviceLevel, -) +from api.cases.enums import AdviceType, AdviceLevel from api.cases.generated_documents.models import GeneratedCaseDocument from api.cases.generated_documents.serializers import AdviceDocumentGovSerializer from api.cases.helpers import create_system_mention @@ -79,7 +75,6 @@ EcjuQueryDocumentCreateSerializer, EcjuQueryDocumentViewSerializer, ) -from api.compliance.helpers import generate_compliance_site_case from api.core import constants from api.core.authentication import GovAuthentication, SharedAuthentication, ExporterAuthentication from api.core.constants import GovPermissions @@ -887,11 +882,7 @@ def put(self, request, pk): """ case = get_case(pk) - # Check Permissions - if CaseTypeSubTypeEnum.is_mod_clearance(case.case_type.sub_type): - assert_user_has_permission(request.user.govuser, GovPermissions.MANAGE_CLEARANCE_FINAL_ADVICE) - else: - assert_user_has_permission(request.user.govuser, GovPermissions.MANAGE_LICENCE_FINAL_ADVICE) + assert_user_has_permission(request.user.govuser, GovPermissions.MANAGE_LICENCE_FINAL_ADVICE) required_decisions = get_required_decision_document_types(case) @@ -957,7 +948,6 @@ def put(self, request, pk): "start_date": licence.start_date.strftime("%Y-%m-%d"), }, ) - generate_compliance_site_case(case) except Licence.DoesNotExist: # Do nothing if Licence doesn't exist pass From 2a158960abfb7d217fca87a8bada5e3dfa926edf Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Wed, 6 Nov 2024 23:19:12 +0000 Subject: [PATCH 42/86] Refactor case finalise view Move finalise code from the view to the model. Separate functionality into discrete model functions. --- api/cases/libraries/finalise.py | 4 +- api/cases/models.py | 108 ++++++++++++++++++++++- api/cases/tests/test_grant_licence.py | 9 +- api/cases/views/views.py | 121 ++------------------------ 4 files changed, 124 insertions(+), 118 deletions(-) diff --git a/api/cases/libraries/finalise.py b/api/cases/libraries/finalise.py index 104b7b139b..4fdbf70283 100644 --- a/api/cases/libraries/finalise.py +++ b/api/cases/libraries/finalise.py @@ -1,8 +1,8 @@ +from api.audit_trail.models import Audit +from api.applications.models import GoodOnApplication from api.cases.enums import AdviceType, CaseTypeSubTypeEnum, AdviceLevel from api.cases.models import Advice, GoodCountryDecision -from api.applications.models import GoodOnApplication from api.flags.models import Flag -from api.audit_trail.models import Audit def get_required_decision_document_types(case): diff --git a/api/cases/models.py b/api/cases/models.py index f69016bc11..56be305f7f 100644 --- a/api/cases/models.py +++ b/api/cases/models.py @@ -5,7 +5,7 @@ from django.conf import settings from django.contrib.contenttypes.fields import GenericRelation -from django.db import models +from django.db import models, transaction from django.db.models import Q from django.utils import timezone from api.users.enums import UserType @@ -35,8 +35,9 @@ from api.organisations.models import Organisation from api.queues.models import Queue from api.staticdata.countries.models import Country +from api.staticdata.decisions.models import Decision from api.staticdata.denial_reasons.models import DenialReason -from api.staticdata.statuses.enums import CaseStatusEnum +from api.staticdata.statuses.enums import CaseStatusEnum, CaseSubStatusIdEnum from api.staticdata.statuses.libraries.get_case_status import get_case_status_by_status from api.staticdata.statuses.models import ( CaseStatus, @@ -124,6 +125,15 @@ class Case(TimestampableModel): objects = CaseManager() + @classmethod + def get_decision_actions(cls): + return { + AdviceType.APPROVE: cls.approve, + AdviceType.REFUSE: cls.refuse, + AdviceType.NO_LICENCE_REQUIRED: cls.no_licence_required, + AdviceType.INFORM: lambda x: x, + } + def save(self, *args, **kwargs): if CaseStatusEnum.is_terminal(self.status.status): self.case_officer = None @@ -308,6 +318,100 @@ def set_sub_status(self, sub_status_id): payload={"sub_status": self.sub_status.name, "status": CaseStatusEnum.get_text(self.status.status)}, ) + def approve(self): + from api.cases.notify import notify_exporter_licence_issued + + self.set_sub_status(CaseSubStatusIdEnum.FINALISED__APPROVED) + notify_exporter_licence_issued(self) + + def refuse(self): + from api.cases.notify import notify_exporter_licence_refused + + self.set_sub_status(CaseSubStatusIdEnum.FINALISED__REFUSED) + notify_exporter_licence_refused(self) + + def no_licence_required(self): + from api.cases.notify import notify_exporter_no_licence_required + + notify_exporter_no_licence_required(self) + + @transaction.atomic + def finalise(self, request, decisions): + from api.audit_trail import service as audit_trail_service + from api.cases.libraries.finalise import remove_flags_on_finalisation, remove_flags_from_audit_trail + from api.licences.models import Licence + + try: + licence = Licence.objects.get_draft_licence(self) + except Licence.DoesNotExist: + # This is not an error as there won't be a licence for refusal cases + licence = None + + if AdviceType.APPROVE in decisions and licence: + licence.decisions.set([Decision.objects.get(name=decision) for decision in decisions]) + + logging.info("Initiate issue of licence %s (status: %s)", licence.reference_code, licence.status) + licence.issue() + + if Licence.objects.filter(case=self).count() > 1: + audit_trail_service.create( + actor=request.user, + verb=AuditType.REINSTATED_APPLICATION, + target=self, + payload={ + "licence_duration": licence.duration, + "start_date": licence.start_date.strftime("%Y-%m-%d"), + }, + ) + + # Finalise Case + old_status = self.status.status + self.status = get_case_status_by_status(CaseStatusEnum.FINALISED) + self.save() + + audit_trail_service.create( + actor=request.user, + verb=AuditType.UPDATED_STATUS, + target=self, + payload={ + "status": {"new": self.status.status, "old": old_status}, + "additional_text": request.data.get("note"), + }, + ) + logging.info("Case is now finalised") + + decision_actions = self.get_decision_actions() + for advice_type in decisions: + decision_actions[advice_type](self) + + licence_reference = licence.reference_code if advice_type == AdviceType.APPROVE else "" + audit_trail_service.create( + actor=request.user, + verb=AuditType.CREATED_FINAL_RECOMMENDATION, + target=self, + payload={ + "case_reference": self.reference_code, + "decision": advice_type, + "licence_reference": licence_reference, + }, + ) + + self.publish_decision_documents() + + # Remove Flags and related Audits when Finalising + remove_flags_on_finalisation(self) + remove_flags_from_audit_trail(self) + + def publish_decision_documents(self): + from api.cases.generated_documents.models import GeneratedCaseDocument + + documents = GeneratedCaseDocument.objects.filter(advice_type__isnull=False, case=self) + documents.update(visible_to_exporter=True) + for document in documents: + document.send_exporter_notifications() + + logging.info("Licence documents published to exporter, notification sent") + class CaseQueue(TimestampableModel): case = models.ForeignKey(Case, related_name="casequeues", on_delete=models.DO_NOTHING) diff --git a/api/cases/tests/test_grant_licence.py b/api/cases/tests/test_grant_licence.py index 9ac100ac9b..b02e20a20d 100644 --- a/api/cases/tests/test_grant_licence.py +++ b/api/cases/tests/test_grant_licence.py @@ -4,6 +4,7 @@ from api.licences.enums import LicenceStatus from api.licences.models import Licence +from api.audit_trail.enums import AuditType from api.audit_trail.models import Audit from api.cases.enums import AdviceType, CaseTypeEnum from api.cases.generated_documents.models import GeneratedCaseDocument @@ -31,7 +32,7 @@ def setUp(self): decisions=[Decision.objects.get(name=AdviceType.APPROVE)], ) - @mock.patch("api.cases.views.views.notify_exporter_licence_issued") + @mock.patch("api.cases.notify.notify_exporter_licence_issued") @mock.patch("api.cases.generated_documents.models.GeneratedCaseDocument.send_exporter_notifications") def test_grant_standard_application_success(self, send_exporter_notifications_func, mock_notify): self.gov_user.role.permissions.set([GovPermissions.MANAGE_LICENCE_FINAL_ADVICE.name]) @@ -59,6 +60,12 @@ def test_grant_standard_application_success(self, send_exporter_notifications_fu self.assertTrue(document.visible_to_exporter) self.assertEqual(Audit.objects.count(), 6) + final_audit_qs = Audit.objects.filter( + target_object_id=self.standard_case.id, verb=AuditType.CREATED_FINAL_RECOMMENDATION + ) + self.assertEqual(final_audit_qs.count(), 1) + self.assertEqual(final_audit_qs[0].payload["decision"], AdviceType.APPROVE) + self.assertIsNone(self.standard_case.appeal_deadline) send_exporter_notifications_func.assert_called() mock_notify.assert_called_with(self.standard_case.get_case()) diff --git a/api/cases/views/views.py b/api/cases/views/views.py index 327f282abe..ddd7c4c8b8 100644 --- a/api/cases/views/views.py +++ b/api/cases/views/views.py @@ -1,5 +1,3 @@ -import logging - from django.core.exceptions import PermissionDenied from django.db import transaction from django.http.response import JsonResponse, HttpResponse @@ -26,11 +24,7 @@ from api.cases.generated_documents.serializers import AdviceDocumentGovSerializer from api.cases.helpers import create_system_mention from api.cases.libraries.advice import group_advice -from api.cases.libraries.finalise import ( - get_required_decision_document_types, - remove_flags_on_finalisation, - remove_flags_from_audit_trail, -) +from api.cases.libraries.finalise import get_required_decision_document_types from api.cases.libraries.get_case import get_case, get_case_document from api.cases.libraries.get_destination import get_destination from api.cases.libraries.get_ecju_queries import get_ecju_query @@ -56,11 +50,7 @@ CaseAssignment, ) from api.cases.models import CountersignAdvice -from api.cases.notify import ( - notify_exporter_licence_issued, - notify_exporter_licence_refused, - notify_exporter_no_licence_required, -) + from api.cases.serializers import ( CaseDocumentViewSerializer, CaseDocumentCreateSerializer, @@ -92,9 +82,7 @@ from api.parties.serializers import PartySerializer, AdditionalContactSerializer from api.queues.models import Queue from api.staticdata.countries.models import Country -from api.staticdata.decisions.models import Decision -from api.staticdata.statuses.enums import CaseStatusEnum, CaseSubStatusIdEnum -from api.staticdata.statuses.libraries.get_case_status import get_case_status_by_status +from api.staticdata.statuses.enums import CaseStatusEnum from api.users.libraries.get_user import get_user_by_pk from lite_content.lite_api import strings from lite_content.lite_api.strings import Documents, Cases @@ -891,7 +879,6 @@ def put(self, request, pk): required_decisions.remove(AdviceType.INFORM) # Check that each decision has a document - # Excluding approve (done in the licence section below) generated_document_decisions = set( GeneratedCaseDocument.objects.filter(advice_type__isnull=False, case=case).values_list( "advice_type", flat=True @@ -906,105 +893,13 @@ def put(self, request, pk): } ) - return_payload = {"case": pk} - - # If a licence object exists, finalise the licence. - try: - licence = Licence.objects.get_draft_licence(pk) - - if AdviceType.APPROVE in required_decisions: - # Check that a licence document has been created - # (new document required for new licence) - licence_document_exists = GeneratedCaseDocument.objects.filter( - advice_type=AdviceType.APPROVE, licence=licence - ).exists() - if not licence_document_exists: - raise ParseError({"decision-approve": [Cases.Licence.MISSING_LICENCE_DOCUMENT]}) - - audit_trail_service.create( - actor=request.user, - verb=AuditType.CREATED_FINAL_RECOMMENDATION, - target=case, - payload={ - "case_reference": case.reference_code, - "decision": AdviceType.APPROVE, - "licence_reference": licence.reference_code, - }, - ) - - licence.decisions.set([Decision.objects.get(name=decision) for decision in required_decisions]) - - logging.info("Initiate issue of licence %s (status: %s)", licence.reference_code, licence.status) - licence.issue() - - return_payload["licence"] = licence.id - if Licence.objects.filter(case=case).count() > 1: - audit_trail_service.create( - actor=request.user, - verb=AuditType.REINSTATED_APPLICATION, - target=case, - payload={ - "licence_duration": licence.duration, - "start_date": licence.start_date.strftime("%Y-%m-%d"), - }, - ) - except Licence.DoesNotExist: - # Do nothing if Licence doesn't exist - pass - - # Finalise Case - old_status = case.status.status - case.status = get_case_status_by_status(CaseStatusEnum.FINALISED) - case.save() - logging.info("Case status is now finalised") - - # Remove Flags and related Audits when Finalising - remove_flags_on_finalisation(case) - remove_flags_from_audit_trail(case) - - decisions = required_decisions.copy() - - if AdviceType.REFUSE in decisions: - case.set_sub_status(CaseSubStatusIdEnum.FINALISED__REFUSED) - notify_exporter_licence_refused(case) - - if AdviceType.NO_LICENCE_REQUIRED in decisions: - notify_exporter_no_licence_required(case) - - if AdviceType.APPROVE in decisions: - case.set_sub_status(CaseSubStatusIdEnum.FINALISED__APPROVED) - notify_exporter_licence_issued(case) - - if AdviceType.APPROVE in decisions: - decisions.remove(AdviceType.APPROVE) - - for decision in decisions: - audit_trail_service.create( - actor=request.user, - verb=AuditType.CREATED_FINAL_RECOMMENDATION, - target=case, - payload={"case_reference": case.reference_code, "decision": decision, "licence_reference": ""}, - ) - - audit_trail_service.create( - actor=request.user, - verb=AuditType.UPDATED_STATUS, - target=case, - payload={ - "status": {"new": case.status.status, "old": old_status}, - "additional_text": request.data.get("note"), - }, - ) - - # Show documents to exporter & notify - documents = GeneratedCaseDocument.objects.filter(advice_type__isnull=False, case=case) - documents.update(visible_to_exporter=True) - for document in documents: - document.send_exporter_notifications() + case.finalise(request, required_decisions) - logging.info("Licence documents visible to exporter, notification sent") + licence_id = "" + if AdviceType.APPROVE in required_decisions: + licence_id = Licence.objects.get_active_licence(case).id - return JsonResponse(return_payload, status=status.HTTP_201_CREATED) + return JsonResponse({"case": pk, "licence": licence_id}, status=status.HTTP_201_CREATED) class AdditionalContacts(ListCreateAPIView): From a9e636789f7e10896901a95da993761256395846 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Wed, 6 Nov 2024 23:34:49 +0000 Subject: [PATCH 43/86] Create LicenceDecision instances when the decision is made --- api/cases/models.py | 10 +++++ api/cases/tests/test_finalise_advice.py | 55 ++++++++++++++++++------- api/cases/tests/test_grant_licence.py | 20 +++++---- api/licences/models.py | 8 +++- 4 files changed, 71 insertions(+), 22 deletions(-) diff --git a/api/cases/models.py b/api/cases/models.py index 56be305f7f..0b376edabb 100644 --- a/api/cases/models.py +++ b/api/cases/models.py @@ -384,6 +384,16 @@ def finalise(self, request, decisions): for advice_type in decisions: decision_actions[advice_type](self) + licence_reference = licence if advice_type == AdviceType.APPROVE else "" + + # NLR is not considered as licence decision + if advice_type in [AdviceType.APPROVE, AdviceType.REFUSE]: + LicenceDecision.objects.create( + case=self, + decision=LicenceDecisionType.advice_type_to_decision(advice_type), + licence=licence, + ) + licence_reference = licence.reference_code if advice_type == AdviceType.APPROVE else "" audit_trail_service.create( actor=request.user, diff --git a/api/cases/tests/test_finalise_advice.py b/api/cases/tests/test_finalise_advice.py index 2f9a533af1..2b37af8240 100644 --- a/api/cases/tests/test_finalise_advice.py +++ b/api/cases/tests/test_finalise_advice.py @@ -1,23 +1,26 @@ from unittest import mock from django.urls import reverse -from api.audit_trail.enums import AuditType -from api.flags.models import Flag -from api.users.enums import UserType -from api.users.models import BaseUser from rest_framework import status from parameterized import parameterized +from api.audit_trail.enums import AuditType from api.audit_trail.models import Audit -from api.cases.enums import AdviceType, CaseTypeEnum +from api.audit_trail import service as audit_trail_service +from api.cases.enums import AdviceType, CaseTypeEnum, LicenceDecisionType +from api.cases.models import LicenceDecision from api.cases.tests.factories import FinalAdviceFactory from api.cases.libraries.get_case import get_case from api.cases.generated_documents.models import GeneratedCaseDocument from api.core.constants import GovPermissions +from api.flags.models import Flag +from api.licences.enums import LicenceStatus +from api.licences.tests.factories import StandardLicenceFactory from api.staticdata.decisions.models import Decision from api.staticdata.statuses.enums import CaseStatusEnum from api.staticdata.statuses.models import CaseStatus +from api.users.enums import UserType +from api.users.models import BaseUser from test_helpers.clients import DataTestClient -from api.audit_trail import service as audit_trail_service from api.staticdata.statuses.libraries.get_case_status import get_case_status_by_status @@ -33,7 +36,7 @@ def setUp(self): decisions=[Decision.objects.get(name=AdviceType.REFUSE)], ) - @mock.patch("api.cases.views.views.notify_exporter_licence_refused") + @mock.patch("api.cases.notify.notify_exporter_licence_refused") @mock.patch("api.cases.generated_documents.models.GeneratedCaseDocument.send_exporter_notifications") def test_refuse_standard_application_success(self, send_exporter_notifications_func, mock_notify): self.gov_user.role.permissions.set([GovPermissions.MANAGE_LICENCE_FINAL_ADVICE.name]) @@ -56,8 +59,18 @@ def test_refuse_standard_application_success(self, send_exporter_notifications_f mock_notify.assert_called_with(case) send_exporter_notifications_func.assert_called() assert case.sub_status.name == "Refused" + self.assertTrue( + Audit.objects.filter( + target_object_id=self.application.id, + verb=AuditType.CREATED_FINAL_RECOMMENDATION, + payload__decision=AdviceType.REFUSE, + ).exists() + ) + self.assertTrue( + LicenceDecision.objects.filter(case=self.application, decision=LicenceDecisionType.REFUSED).exists() + ) - @mock.patch("api.cases.views.views.notify_exporter_licence_refused") + @mock.patch("api.cases.notify.notify_exporter_licence_refused") @mock.patch("api.cases.generated_documents.models.GeneratedCaseDocument.send_exporter_notifications") def test_refuse_standard_application_success_inform_letter_feature_letter_on( self, send_exporter_notifications_func, mock_notify @@ -95,8 +108,8 @@ def setUp(self): decisions=[Decision.objects.get(name=AdviceType.NO_LICENCE_REQUIRED)], ) - @mock.patch("api.cases.views.views.notify_exporter_licence_issued") - @mock.patch("api.cases.views.views.notify_exporter_no_licence_required") + @mock.patch("api.cases.notify.notify_exporter_licence_issued") + @mock.patch("api.cases.notify.notify_exporter_no_licence_required") @mock.patch("api.cases.generated_documents.models.GeneratedCaseDocument.send_exporter_notifications") def test_no_licence_required_standard_application_success( self, @@ -121,6 +134,14 @@ def test_no_licence_required_standard_application_success( mock_notify_exporter_licence_issued.assert_not_called() send_exporter_notifications_func.assert_called() + self.assertTrue( + Audit.objects.filter( + target_object_id=self.application.id, + verb=AuditType.CREATED_FINAL_RECOMMENDATION, + payload__decision=AdviceType.NO_LICENCE_REQUIRED, + ).exists() + ) + assert case.sub_status == None @@ -159,7 +180,7 @@ def setUp(self): decisions=[Decision.objects.get(name=AdviceType.NO_LICENCE_REQUIRED)], ) - @mock.patch("api.cases.views.views.notify_exporter_licence_issued") + @mock.patch("api.cases.notify.notify_exporter_licence_issued") @mock.patch("api.cases.generated_documents.models.GeneratedCaseDocument.send_exporter_notifications") def test_approve_standard_application_success( self, @@ -167,7 +188,10 @@ def test_approve_standard_application_success( mock_notify_exporter_licence_issued, ): self.gov_user.role.permissions.set([GovPermissions.MANAGE_LICENCE_FINAL_ADVICE.name]) - self.create_generated_case_document(self.application, self.template, advice_type=AdviceType.APPROVE) + licence = StandardLicenceFactory(case=self.application, status=LicenceStatus.DRAFT) + self.create_generated_case_document( + self.application, self.template, advice_type=AdviceType.APPROVE, licence=licence + ) response = self.client.put(self.url, data={}, **self.gov_headers) self.application.refresh_from_db() @@ -182,7 +206,7 @@ def test_approve_standard_application_success( assert case.sub_status.name == "Approved" - @mock.patch("api.cases.views.views.notify_exporter_licence_issued") + @mock.patch("api.cases.notify.notify_exporter_licence_issued") @mock.patch("api.cases.generated_documents.models.GeneratedCaseDocument.send_exporter_notifications") def test_finalised_standard_application_with_flags_removed( self, @@ -190,7 +214,10 @@ def test_finalised_standard_application_with_flags_removed( mock_notify_exporter_licence_issued, ): self.gov_user.role.permissions.set([GovPermissions.MANAGE_LICENCE_FINAL_ADVICE.name]) - self.create_generated_case_document(self.application, self.template, advice_type=AdviceType.APPROVE) + licence = StandardLicenceFactory(case=self.application, status=LicenceStatus.DRAFT) + self.create_generated_case_document( + self.application, self.template, advice_type=AdviceType.APPROVE, licence=licence + ) self.assertEqual(self.application.flags.count(), 2) diff --git a/api/cases/tests/test_grant_licence.py b/api/cases/tests/test_grant_licence.py index b02e20a20d..4ae46d6462 100644 --- a/api/cases/tests/test_grant_licence.py +++ b/api/cases/tests/test_grant_licence.py @@ -6,7 +6,8 @@ from api.licences.models import Licence from api.audit_trail.enums import AuditType from api.audit_trail.models import Audit -from api.cases.enums import AdviceType, CaseTypeEnum +from api.cases.enums import AdviceType, CaseTypeEnum, LicenceDecisionType +from api.licences.models import LicenceDecision from api.cases.generated_documents.models import GeneratedCaseDocument from api.cases.tests.factories import FinalAdviceFactory from api.core.constants import GovPermissions @@ -60,11 +61,16 @@ def test_grant_standard_application_success(self, send_exporter_notifications_fu self.assertTrue(document.visible_to_exporter) self.assertEqual(Audit.objects.count(), 6) - final_audit_qs = Audit.objects.filter( - target_object_id=self.standard_case.id, verb=AuditType.CREATED_FINAL_RECOMMENDATION + self.assertTrue( + Audit.objects.filter( + target_object_id=self.standard_case.id, + verb=AuditType.CREATED_FINAL_RECOMMENDATION, + payload__decision=AdviceType.APPROVE, + ).exists() + ) + self.assertTrue( + LicenceDecision.objects.filter(case=self.standard_case, decision=LicenceDecisionType.ISSUED).exists() ) - self.assertEqual(final_audit_qs.count(), 1) - self.assertEqual(final_audit_qs[0].payload["decision"], AdviceType.APPROVE) self.assertIsNone(self.standard_case.appeal_deadline) send_exporter_notifications_func.assert_called() @@ -99,7 +105,7 @@ def test_finalise_case_without_licence_success(self): self.assertEqual(response.json(), {"case": str(self.standard_case.pk)}) @mock.patch("api.licences.models.notify_exporter_licence_revoked") - @mock.patch("api.cases.views.views.notify_exporter_licence_issued") + @mock.patch("api.cases.notify.notify_exporter_licence_issued") @mock.patch("api.cases.generated_documents.models.GeneratedCaseDocument.send_exporter_notifications") def test_grant_standard_application_licence_and_revoke( self, send_exporter_notifications_func, mock_notify_licence_issue, mock_notify_licence_revoked @@ -142,7 +148,7 @@ def test_grant_standard_application_licence_and_revoke( mock_notify_licence_revoked.assert_called_with(licence) @mock.patch("api.licences.models.notify_exporter_licence_suspended") - @mock.patch("api.cases.views.views.notify_exporter_licence_issued") + @mock.patch("api.cases.notify.notify_exporter_licence_issued") @mock.patch("api.cases.generated_documents.models.GeneratedCaseDocument.send_exporter_notifications") def test_grant_standard_application_licence_and_suspend( self, send_exporter_notifications_func, mock_notify_licence_issue, mock_notify_licence_suspended diff --git a/api/licences/models.py b/api/licences/models.py index 748c54a97f..02738e5134 100644 --- a/api/licences/models.py +++ b/api/licences/models.py @@ -8,7 +8,8 @@ from django.core.exceptions import ImproperlyConfigured from api.applications.models import GoodOnApplication -from api.cases.models import Case +from api.cases.enums import LicenceDecisionType +from api.cases.models import Case, LicenceDecision from api.common.models import TimestampableModel from api.core.helpers import add_months from api.licences.enums import LicenceStatus, licence_status_to_hmrc_integration_action @@ -97,6 +98,11 @@ def suspend(self, user=None): def revoke(self, user=None): self._set_status(LicenceStatus.REVOKED, user=user, send_status_change_to_hmrc=True) + LicenceDecision.objects.create( + case=self.case, + decision=LicenceDecisionType.REVOKED, + licence=self, + ) notify_exporter_licence_revoked(self) def cancel(self, user=None, send_status_change_to_hmrc=True): From 33ffb279bb4170e6d07da31fbdb7705e1654a732 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 8 Nov 2024 11:01:53 +0000 Subject: [PATCH 44/86] Fix merge conflicts related code and failing tests --- api/cases/models.py | 4 +--- api/cases/tests/test_grant_licence.py | 3 --- api/cases/views/views.py | 7 ++----- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/api/cases/models.py b/api/cases/models.py index 0b376edabb..8851f973aa 100644 --- a/api/cases/models.py +++ b/api/cases/models.py @@ -384,8 +384,6 @@ def finalise(self, request, decisions): for advice_type in decisions: decision_actions[advice_type](self) - licence_reference = licence if advice_type == AdviceType.APPROVE else "" - # NLR is not considered as licence decision if advice_type in [AdviceType.APPROVE, AdviceType.REFUSE]: LicenceDecision.objects.create( @@ -394,7 +392,7 @@ def finalise(self, request, decisions): licence=licence, ) - licence_reference = licence.reference_code if advice_type == AdviceType.APPROVE else "" + licence_reference = licence.reference_code if licence and advice_type == AdviceType.APPROVE else "" audit_trail_service.create( actor=request.user, verb=AuditType.CREATED_FINAL_RECOMMENDATION, diff --git a/api/cases/tests/test_grant_licence.py b/api/cases/tests/test_grant_licence.py index 4ae46d6462..0801dab355 100644 --- a/api/cases/tests/test_grant_licence.py +++ b/api/cases/tests/test_grant_licence.py @@ -47,7 +47,6 @@ def test_grant_standard_application_success(self, send_exporter_notifications_fu self.standard_case.refresh_from_db() self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertEqual(response.json()["licence"], str(licence.id)) self.assertEqual( Licence.objects.filter( case=self.standard_case, @@ -122,7 +121,6 @@ def test_grant_standard_application_licence_and_revoke( self.standard_case.refresh_from_db() self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertEqual(response.json()["licence"], str(licence.id)) self.assertEqual( Licence.objects.filter( case=self.standard_case, @@ -165,7 +163,6 @@ def test_grant_standard_application_licence_and_suspend( self.standard_case.refresh_from_db() self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertEqual(response.json()["licence"], str(licence.id)) self.assertEqual( Licence.objects.filter( case=self.standard_case, diff --git a/api/cases/views/views.py b/api/cases/views/views.py index ddd7c4c8b8..dff22f7809 100644 --- a/api/cases/views/views.py +++ b/api/cases/views/views.py @@ -893,13 +893,10 @@ def put(self, request, pk): } ) + # finalises case, grants licence and publishes decision documents case.finalise(request, required_decisions) - licence_id = "" - if AdviceType.APPROVE in required_decisions: - licence_id = Licence.objects.get_active_licence(case).id - - return JsonResponse({"case": pk, "licence": licence_id}, status=status.HTTP_201_CREATED) + return JsonResponse({"case": pk}, status=status.HTTP_201_CREATED) class AdditionalContacts(ListCreateAPIView): From e53ee0db74cbd29117a2bfc578d09be7070ef487 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 8 Nov 2024 11:38:25 +0000 Subject: [PATCH 45/86] Create Case officer user to avoid repeating setup code in tests --- api/cases/tests/test_finalise_advice.py | 16 +++++----------- api/cases/tests/test_grant_licence.py | 19 +++++-------------- test_helpers/clients.py | 13 ++++++++++++- 3 files changed, 22 insertions(+), 26 deletions(-) diff --git a/api/cases/tests/test_finalise_advice.py b/api/cases/tests/test_finalise_advice.py index 2f9a533af1..9df18f578c 100644 --- a/api/cases/tests/test_finalise_advice.py +++ b/api/cases/tests/test_finalise_advice.py @@ -12,7 +12,6 @@ from api.cases.tests.factories import FinalAdviceFactory from api.cases.libraries.get_case import get_case from api.cases.generated_documents.models import GeneratedCaseDocument -from api.core.constants import GovPermissions from api.staticdata.decisions.models import Decision from api.staticdata.statuses.enums import CaseStatusEnum from api.staticdata.statuses.models import CaseStatus @@ -36,10 +35,9 @@ def setUp(self): @mock.patch("api.cases.views.views.notify_exporter_licence_refused") @mock.patch("api.cases.generated_documents.models.GeneratedCaseDocument.send_exporter_notifications") def test_refuse_standard_application_success(self, send_exporter_notifications_func, mock_notify): - self.gov_user.role.permissions.set([GovPermissions.MANAGE_LICENCE_FINAL_ADVICE.name]) self.create_generated_case_document(self.application, self.template, advice_type=AdviceType.REFUSE) - response = self.client.put(self.url, data={}, **self.gov_headers) + response = self.client.put(self.url, data={}, **self.lu_case_officer_headers) self.application.refresh_from_db() self.assertEqual(response.status_code, status.HTTP_201_CREATED) @@ -62,10 +60,9 @@ def test_refuse_standard_application_success(self, send_exporter_notifications_f def test_refuse_standard_application_success_inform_letter_feature_letter_on( self, send_exporter_notifications_func, mock_notify ): - self.gov_user.role.permissions.set([GovPermissions.MANAGE_LICENCE_FINAL_ADVICE.name]) self.create_generated_case_document(self.application, self.template, advice_type=AdviceType.REFUSE) - response = self.client.put(self.url, data={}, **self.gov_headers) + response = self.client.put(self.url, data={}, **self.lu_case_officer_headers) self.application.refresh_from_db() self.assertEqual(response.status_code, status.HTTP_201_CREATED) @@ -104,10 +101,9 @@ def test_no_licence_required_standard_application_success( mock_notify_exporter_no_licence_required, mock_notify_exporter_licence_issued, ): - self.gov_user.role.permissions.set([GovPermissions.MANAGE_LICENCE_FINAL_ADVICE.name]) self.create_generated_case_document(self.application, self.template, advice_type=AdviceType.NO_LICENCE_REQUIRED) - response = self.client.put(self.url, data={}, **self.gov_headers) + response = self.client.put(self.url, data={}, **self.lu_case_officer_headers) self.application.refresh_from_db() self.assertEqual(response.status_code, status.HTTP_201_CREATED) @@ -166,10 +162,9 @@ def test_approve_standard_application_success( send_exporter_notifications_func, mock_notify_exporter_licence_issued, ): - self.gov_user.role.permissions.set([GovPermissions.MANAGE_LICENCE_FINAL_ADVICE.name]) self.create_generated_case_document(self.application, self.template, advice_type=AdviceType.APPROVE) - response = self.client.put(self.url, data={}, **self.gov_headers) + response = self.client.put(self.url, data={}, **self.lu_case_officer_headers) self.application.refresh_from_db() self.assertEqual(response.status_code, status.HTTP_201_CREATED) @@ -189,12 +184,11 @@ def test_finalised_standard_application_with_flags_removed( send_exporter_notifications_func, mock_notify_exporter_licence_issued, ): - self.gov_user.role.permissions.set([GovPermissions.MANAGE_LICENCE_FINAL_ADVICE.name]) self.create_generated_case_document(self.application, self.template, advice_type=AdviceType.APPROVE) self.assertEqual(self.application.flags.count(), 2) - response = self.client.put(self.url, data={}, **self.gov_headers) + response = self.client.put(self.url, data={}, **self.lu_case_officer_headers) self.application.refresh_from_db() self.assertEqual(response.status_code, status.HTTP_201_CREATED) diff --git a/api/cases/tests/test_grant_licence.py b/api/cases/tests/test_grant_licence.py index 9ac100ac9b..0262f065f4 100644 --- a/api/cases/tests/test_grant_licence.py +++ b/api/cases/tests/test_grant_licence.py @@ -34,14 +34,13 @@ def setUp(self): @mock.patch("api.cases.views.views.notify_exporter_licence_issued") @mock.patch("api.cases.generated_documents.models.GeneratedCaseDocument.send_exporter_notifications") def test_grant_standard_application_success(self, send_exporter_notifications_func, mock_notify): - self.gov_user.role.permissions.set([GovPermissions.MANAGE_LICENCE_FINAL_ADVICE.name]) licence = StandardLicenceFactory(case=self.standard_case, status=LicenceStatus.DRAFT) self.create_generated_case_document( self.standard_case, self.template, advice_type=AdviceType.APPROVE, licence=licence ) self.assertIsNone(self.standard_case.appeal_deadline) - response = self.client.put(self.url, data={}, **self.gov_headers) + response = self.client.put(self.url, data={}, **self.lu_case_officer_headers) self.standard_case.refresh_from_db() self.assertEqual(response.status_code, status.HTTP_201_CREATED) @@ -74,19 +73,17 @@ def test_grant_standard_application_wrong_permission_failure(self): self.assertEqual(response.json(), {"errors": {"error": PermissionDeniedError.default_detail}}) def test_missing_advice_document_failure(self): - self.gov_user.role.permissions.set([GovPermissions.MANAGE_LICENCE_FINAL_ADVICE.name]) StandardLicenceFactory(case=self.standard_case, status=LicenceStatus.DRAFT) - response = self.client.put(self.url, data={}, **self.gov_headers) + response = self.client.put(self.url, data={}, **self.lu_case_officer_headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(response.json(), {"errors": {"decision-approve": [Cases.Licence.MISSING_DOCUMENTS]}}) def test_finalise_case_without_licence_success(self): - self.gov_user.role.permissions.set([GovPermissions.MANAGE_LICENCE_FINAL_ADVICE.name]) self.create_generated_case_document(self.standard_case, self.template, advice_type=AdviceType.APPROVE) - response = self.client.put(self.url, data={}, **self.gov_headers) + response = self.client.put(self.url, data={}, **self.lu_case_officer_headers) self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.json(), {"case": str(self.standard_case.pk)}) @@ -97,15 +94,12 @@ def test_finalise_case_without_licence_success(self): def test_grant_standard_application_licence_and_revoke( self, send_exporter_notifications_func, mock_notify_licence_issue, mock_notify_licence_revoked ): - self.gov_user.role.permissions.set( - [GovPermissions.MANAGE_LICENCE_FINAL_ADVICE.name, GovPermissions.REOPEN_CLOSED_CASES.name] - ) licence = StandardLicenceFactory(case=self.standard_case, status=LicenceStatus.DRAFT) self.create_generated_case_document( self.standard_case, self.template, advice_type=AdviceType.APPROVE, licence=licence ) - response = self.client.put(self.url, data={}, **self.gov_headers) + response = self.client.put(self.url, data={}, **self.lu_case_officer_headers) self.standard_case.refresh_from_db() self.assertEqual(response.status_code, status.HTTP_201_CREATED) @@ -140,15 +134,12 @@ def test_grant_standard_application_licence_and_revoke( def test_grant_standard_application_licence_and_suspend( self, send_exporter_notifications_func, mock_notify_licence_issue, mock_notify_licence_suspended ): - self.gov_user.role.permissions.set( - [GovPermissions.MANAGE_LICENCE_FINAL_ADVICE.name, GovPermissions.REOPEN_CLOSED_CASES.name] - ) licence = StandardLicenceFactory(case=self.standard_case, status=LicenceStatus.DRAFT) self.create_generated_case_document( self.standard_case, self.template, advice_type=AdviceType.APPROVE, licence=licence ) - response = self.client.put(self.url, data={}, **self.gov_headers) + response = self.client.put(self.url, data={}, **self.lu_case_officer_headers) self.standard_case.refresh_from_db() self.assertEqual(response.status_code, status.HTTP_201_CREATED) diff --git a/test_helpers/clients.py b/test_helpers/clients.py index 4a41403d0d..9645dc72fc 100644 --- a/test_helpers/clients.py +++ b/test_helpers/clients.py @@ -43,7 +43,7 @@ ) from api.cases.celery_tasks import get_application_target_sla from django.conf import settings -from api.core.constants import Roles +from api.core.constants import GovPermissions, Roles from api.conf.urls import urlpatterns from api.documents.libraries.s3_operations import init_s3_client from api.flags.enums import SystemFlags, FlagStatuses, FlagLevels @@ -139,6 +139,17 @@ def setUp(self): self.gov_user.save() self.gov_headers = {"HTTP_GOV_USER_TOKEN": user_to_token(self.base_user)} + self.lu_case_officer = GovUserFactory( + baseuser_ptr__email="case.officer@lu.gov.uk", + baseuser_ptr__first_name="Case", + baseuser_ptr__last_name="Officer", + team=Team.objects.get(name="Licensing Unit"), + ) + self.lu_case_officer_headers = {"HTTP_GOV_USER_TOKEN": user_to_token(self.lu_case_officer.baseuser_ptr)} + self.lu_case_officer.role.permissions.set( + [GovPermissions.MANAGE_LICENCE_FINAL_ADVICE.name, GovPermissions.REOPEN_CLOSED_CASES.name] + ) + # Exporter User Setup (self.organisation, self.exporter_user) = self.create_organisation_with_exporter_user() (self.hmrc_organisation, self.hmrc_exporter_user) = self.create_organisation_with_exporter_user( From 2ef16c3be0992d02040e05bcc1f30784945799f1 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 8 Nov 2024 12:39:54 +0000 Subject: [PATCH 46/86] Add factories for SIEL licence document --- .../generated_documents/tests/factories.py | 9 ++++ api/cases/tests/test_grant_licence.py | 24 +++------- api/letter_templates/tests/factories.py | 44 +++++++++++++++++++ 3 files changed, 60 insertions(+), 17 deletions(-) create mode 100644 api/letter_templates/tests/factories.py diff --git a/api/cases/generated_documents/tests/factories.py b/api/cases/generated_documents/tests/factories.py index 175e9fe276..c5872ef6b3 100644 --- a/api/cases/generated_documents/tests/factories.py +++ b/api/cases/generated_documents/tests/factories.py @@ -1,7 +1,9 @@ import factory +from api.cases.enums import AdviceType from api.cases.generated_documents.models import GeneratedCaseDocument from api.cases.tests.factories import CaseSIELFactory +from api.letter_templates.tests.factories import SIELLicenceTemplateFactory class GeneratedCaseDocumentFactory(factory.django.DjangoModelFactory): @@ -13,3 +15,10 @@ class GeneratedCaseDocumentFactory(factory.django.DjangoModelFactory): class Meta: model = GeneratedCaseDocument + + +class SIELLicenceDocumentFactory(GeneratedCaseDocumentFactory): + text = factory.Faker("sentence") + template = factory.SubFactory(SIELLicenceTemplateFactory) + licence = None + advice_type = AdviceType.APPROVE diff --git a/api/cases/tests/test_grant_licence.py b/api/cases/tests/test_grant_licence.py index 0262f065f4..51aa642cb1 100644 --- a/api/cases/tests/test_grant_licence.py +++ b/api/cases/tests/test_grant_licence.py @@ -5,8 +5,9 @@ from api.licences.enums import LicenceStatus from api.licences.models import Licence from api.audit_trail.models import Audit -from api.cases.enums import AdviceType, CaseTypeEnum +from api.cases.enums import AdviceType from api.cases.generated_documents.models import GeneratedCaseDocument +from api.cases.generated_documents.tests.factories import SIELLicenceDocumentFactory from api.cases.tests.factories import FinalAdviceFactory from api.core.constants import GovPermissions from api.core.exceptions import PermissionDeniedError @@ -25,19 +26,12 @@ def setUp(self): self.standard_case = self.create_standard_application_case(self.organisation) self.url = reverse("cases:finalise", kwargs={"pk": self.standard_case.id}) FinalAdviceFactory(user=self.gov_user, case=self.standard_case, type=AdviceType.APPROVE) - self.template = self.create_letter_template( - name="Template", - case_types=[CaseTypeEnum.SIEL.id], - decisions=[Decision.objects.get(name=AdviceType.APPROVE)], - ) @mock.patch("api.cases.views.views.notify_exporter_licence_issued") @mock.patch("api.cases.generated_documents.models.GeneratedCaseDocument.send_exporter_notifications") def test_grant_standard_application_success(self, send_exporter_notifications_func, mock_notify): licence = StandardLicenceFactory(case=self.standard_case, status=LicenceStatus.DRAFT) - self.create_generated_case_document( - self.standard_case, self.template, advice_type=AdviceType.APPROVE, licence=licence - ) + SIELLicenceDocumentFactory(case=self.standard_case, licence=licence) self.assertIsNone(self.standard_case.appeal_deadline) response = self.client.put(self.url, data={}, **self.lu_case_officer_headers) @@ -65,7 +59,7 @@ def test_grant_standard_application_success(self, send_exporter_notifications_fu def test_grant_standard_application_wrong_permission_failure(self): self.gov_user.role.permissions.set([GovPermissions.MANAGE_CLEARANCE_FINAL_ADVICE.name]) StandardLicenceFactory(case=self.standard_case, status=LicenceStatus.DRAFT) - self.create_generated_case_document(self.standard_case, self.template, advice_type=AdviceType.APPROVE) + SIELLicenceDocumentFactory(case=self.standard_case) response = self.client.put(self.url, data={}, **self.gov_headers) @@ -81,7 +75,7 @@ def test_missing_advice_document_failure(self): self.assertEqual(response.json(), {"errors": {"decision-approve": [Cases.Licence.MISSING_DOCUMENTS]}}) def test_finalise_case_without_licence_success(self): - self.create_generated_case_document(self.standard_case, self.template, advice_type=AdviceType.APPROVE) + SIELLicenceDocumentFactory(case=self.standard_case) response = self.client.put(self.url, data={}, **self.lu_case_officer_headers) @@ -95,9 +89,7 @@ def test_grant_standard_application_licence_and_revoke( self, send_exporter_notifications_func, mock_notify_licence_issue, mock_notify_licence_revoked ): licence = StandardLicenceFactory(case=self.standard_case, status=LicenceStatus.DRAFT) - self.create_generated_case_document( - self.standard_case, self.template, advice_type=AdviceType.APPROVE, licence=licence - ) + SIELLicenceDocumentFactory(case=self.standard_case, licence=licence) response = self.client.put(self.url, data={}, **self.lu_case_officer_headers) self.standard_case.refresh_from_db() @@ -135,9 +127,7 @@ def test_grant_standard_application_licence_and_suspend( self, send_exporter_notifications_func, mock_notify_licence_issue, mock_notify_licence_suspended ): licence = StandardLicenceFactory(case=self.standard_case, status=LicenceStatus.DRAFT) - self.create_generated_case_document( - self.standard_case, self.template, advice_type=AdviceType.APPROVE, licence=licence - ) + SIELLicenceDocumentFactory(case=self.standard_case, licence=licence) response = self.client.put(self.url, data={}, **self.lu_case_officer_headers) self.standard_case.refresh_from_db() diff --git a/api/letter_templates/tests/factories.py b/api/letter_templates/tests/factories.py new file mode 100644 index 0000000000..3d3b646b0f --- /dev/null +++ b/api/letter_templates/tests/factories.py @@ -0,0 +1,44 @@ +import factory + +from api.cases.enums import CaseTypeEnum + +from api.letter_templates.models import LetterTemplate +from api.staticdata.letter_layouts.models import LetterLayout + + +class LayoutFactory(factory.django.DjangoModelFactory): + name = factory.Faker("word") + filename = factory.Faker("word") + + class Meta: + model = LetterLayout + + +class LetterTemplateFactory(factory.django.DjangoModelFactory): + name = factory.Faker("word") + layout = factory.SubFactory(LayoutFactory) + visible_to_exporter = False + include_digital_signature = False + + @factory.post_generation + def case_types(self, create, extracted, **kwargs): + if not create: + return + + case_types = extracted or [CaseTypeEnum.SIEL.id] + self.case_types.set(case_types) + + @factory.post_generation + def decisions(self, create, extracted, **kwargs): + if not create: + return + + decisions = extracted or [] + self.decisions.set(decisions) + + class Meta: + model = LetterTemplate + + +class SIELLicenceTemplateFactory(LetterTemplateFactory): + layout_id = "00000000-0000-0000-0000-000000000001" From caa4f2fc0689b1f4c0ae2e76be045f5ecc0398b6 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 8 Nov 2024 13:03:39 +0000 Subject: [PATCH 47/86] Return licence_id as per previous code before refactoring --- api/cases/models.py | 20 +++++++++++--------- api/cases/views/views.py | 4 ++-- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/api/cases/models.py b/api/cases/models.py index 8851f973aa..c927d9214f 100644 --- a/api/cases/models.py +++ b/api/cases/models.py @@ -125,15 +125,6 @@ class Case(TimestampableModel): objects = CaseManager() - @classmethod - def get_decision_actions(cls): - return { - AdviceType.APPROVE: cls.approve, - AdviceType.REFUSE: cls.refuse, - AdviceType.NO_LICENCE_REQUIRED: cls.no_licence_required, - AdviceType.INFORM: lambda x: x, - } - def save(self, *args, **kwargs): if CaseStatusEnum.is_terminal(self.status.status): self.case_officer = None @@ -148,6 +139,15 @@ def save(self, *args, **kwargs): super(Case, self).save(*args, **kwargs) + @classmethod + def get_decision_actions(cls): + return { + AdviceType.APPROVE: cls.approve, + AdviceType.REFUSE: cls.refuse, + AdviceType.NO_LICENCE_REQUIRED: cls.no_licence_required, + AdviceType.INFORM: lambda x: x, + } + def _reset_sub_status_on_status_change(self): from api.audit_trail import service as audit_trail_service @@ -410,6 +410,8 @@ def finalise(self, request, decisions): remove_flags_on_finalisation(self) remove_flags_from_audit_trail(self) + return licence.id if licence else "" + def publish_decision_documents(self): from api.cases.generated_documents.models import GeneratedCaseDocument diff --git a/api/cases/views/views.py b/api/cases/views/views.py index dff22f7809..c1f4a1d7bb 100644 --- a/api/cases/views/views.py +++ b/api/cases/views/views.py @@ -894,9 +894,9 @@ def put(self, request, pk): ) # finalises case, grants licence and publishes decision documents - case.finalise(request, required_decisions) + licence_id = case.finalise(request, required_decisions) - return JsonResponse({"case": pk}, status=status.HTTP_201_CREATED) + return JsonResponse({"case": pk, "licence": licence_id}, status=status.HTTP_201_CREATED) class AdditionalContacts(ListCreateAPIView): From 45158e0629b81cf21700d18a0f376a3e4263b32b Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 8 Nov 2024 13:05:37 +0000 Subject: [PATCH 48/86] Remove unused method to avoid coverage issue --- api/cases/enums.py | 4 ---- api/cases/tests/test_grant_licence.py | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/api/cases/enums.py b/api/cases/enums.py index 8113cd8d60..6d21e6407c 100644 --- a/api/cases/enums.py +++ b/api/cases/enums.py @@ -440,7 +440,3 @@ def templates(cls): @classmethod def advice_type_to_decision(cls, advice_type): return cls.decision_map[advice_type] - - @classmethod - def get_template(cls, decision): - return cls.templates()[decision] diff --git a/api/cases/tests/test_grant_licence.py b/api/cases/tests/test_grant_licence.py index 0801dab355..d92760b0c2 100644 --- a/api/cases/tests/test_grant_licence.py +++ b/api/cases/tests/test_grant_licence.py @@ -101,7 +101,7 @@ def test_finalise_case_without_licence_success(self): response = self.client.put(self.url, data={}, **self.gov_headers) self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertEqual(response.json(), {"case": str(self.standard_case.pk)}) + self.assertEqual(response.json(), {"case": str(self.standard_case.pk), "licence": ""}) @mock.patch("api.licences.models.notify_exporter_licence_revoked") @mock.patch("api.cases.notify.notify_exporter_licence_issued") From c0830ad70b0286201ad63caf0d4ba2fc2687dd1c Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 8 Nov 2024 14:57:00 +0000 Subject: [PATCH 49/86] Fix failing test --- api/gov_users/tests/test_roles_and_permissions.py | 6 +++--- api/teams/tests/test_list_user_by_team.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/gov_users/tests/test_roles_and_permissions.py b/api/gov_users/tests/test_roles_and_permissions.py index 9031ad6c5d..a0fedb9d74 100644 --- a/api/gov_users/tests/test_roles_and_permissions.py +++ b/api/gov_users/tests/test_roles_and_permissions.py @@ -129,7 +129,7 @@ def test_only_roles_that_a_user_sees_are_roles_with_a_subset_of_the_permissions_ response_data = response.json()["roles"] self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(len(response_data), 6) + self.assertEqual(len(response_data), 5) self.assertIn(str(Role.objects.get(name="multi permission role").id), str(response_data)) self.assertIn( str(Role.objects.get(name=constants.GovPermissions.MANAGE_TEAM_ADVICE.name).id), str(response_data) @@ -172,7 +172,7 @@ def test_only_roles_that_a_user_sees_are_roles_with_a_subset_of_the_permissions_ response_data = response.json()["roles"] self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(len(response_data), 4) + self.assertEqual(len(response_data), 3) self.assertIn( str(Role.objects.get(name=constants.GovPermissions.MANAGE_TEAM_ADVICE.name).id), str(response_data) ) @@ -207,7 +207,7 @@ def test_only_roles_that_a_user_sees_are_roles_with_a_subset_of_the_permissions_ response_data = response.json()["roles"] self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(len(response_data), 3) + self.assertEqual(len(response_data), 2) self.assertIn( str(Role.objects.get(name=constants.GovPermissions.MANAGE_TEAM_ADVICE.name).id), str(response_data) ) diff --git a/api/teams/tests/test_list_user_by_team.py b/api/teams/tests/test_list_user_by_team.py index f2db411ae0..d22dcae7c4 100644 --- a/api/teams/tests/test_list_user_by_team.py +++ b/api/teams/tests/test_list_user_by_team.py @@ -39,6 +39,6 @@ def test_view_user_by_team(self): response_data = response.json() self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(len(response_data["users"]), self.gov_user_preexisting_count + 1) + self.assertEqual(len(response_data["users"]), self.gov_user_preexisting_count) self.assertContains(response, "test2@mail.com") self.assertNotContains(response, "test3@mail.com") From 1afbfc60992b02a17efd0e2a0726c29c7dd3af0c Mon Sep 17 00:00:00 2001 From: Lawrence <34475808+acodeninja@users.noreply.github.com> Date: Mon, 11 Nov 2024 10:41:50 +0000 Subject: [PATCH 50/86] fix: do not use remote head for submodules --- .copilot/phases/pre_build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.copilot/phases/pre_build.sh b/.copilot/phases/pre_build.sh index 0bc9486520..34bd8bc76e 100644 --- a/.copilot/phases/pre_build.sh +++ b/.copilot/phases/pre_build.sh @@ -22,4 +22,4 @@ path = django_db_anonymiser url = $git_clone_base_url/django-db-anonymiser.git EOF -git submodule update --init --remote --recursive +git submodule update --init --recursive From ea55f89c1edac0edcdbbcc2f9c3fa37258ea710a Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Mon, 11 Nov 2024 12:51:43 +0000 Subject: [PATCH 51/86] Fix merge conflicts with latest dev --- api/cases/tests/test_finalise_advice.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/api/cases/tests/test_finalise_advice.py b/api/cases/tests/test_finalise_advice.py index 870f5c1860..c342705acc 100644 --- a/api/cases/tests/test_finalise_advice.py +++ b/api/cases/tests/test_finalise_advice.py @@ -11,6 +11,7 @@ from api.cases.tests.factories import FinalAdviceFactory from api.cases.libraries.get_case import get_case from api.cases.generated_documents.models import GeneratedCaseDocument +from api.cases.generated_documents.tests.factories import SIELLicenceDocumentFactory from api.flags.models import Flag from api.licences.enums import LicenceStatus from api.licences.tests.factories import StandardLicenceFactory @@ -170,11 +171,6 @@ def setUp(self): self.url = reverse("cases:finalise", kwargs={"pk": self.application.id}) FinalAdviceFactory(user=self.gov_user, case=self.application, type=AdviceType.APPROVE) - self.template = self.create_letter_template( - name="Template", - case_types=[CaseTypeEnum.SIEL.id], - decisions=[Decision.objects.get(name=AdviceType.NO_LICENCE_REQUIRED)], - ) @mock.patch("api.cases.notify.notify_exporter_licence_issued") @mock.patch("api.cases.generated_documents.models.GeneratedCaseDocument.send_exporter_notifications") @@ -184,9 +180,7 @@ def test_approve_standard_application_success( mock_notify_exporter_licence_issued, ): licence = StandardLicenceFactory(case=self.application, status=LicenceStatus.DRAFT) - self.create_generated_case_document( - self.application, self.template, advice_type=AdviceType.APPROVE, licence=licence - ) + SIELLicenceDocumentFactory(case=self.application, licence=licence) response = self.client.put(self.url, data={}, **self.lu_case_officer_headers) self.application.refresh_from_db() @@ -209,9 +203,7 @@ def test_finalised_standard_application_with_flags_removed( mock_notify_exporter_licence_issued, ): licence = StandardLicenceFactory(case=self.application, status=LicenceStatus.DRAFT) - self.create_generated_case_document( - self.application, self.template, advice_type=AdviceType.APPROVE, licence=licence - ) + SIELLicenceDocumentFactory(case=self.application, licence=licence) self.assertEqual(self.application.flags.count(), 2) From 65b8af81191050afdc05e8a7d14db5d6b34ebb92 Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Mon, 11 Nov 2024 12:53:46 +0000 Subject: [PATCH 52/86] Update routing sha --- lite_routing | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lite_routing b/lite_routing index bf87c8492a..9f0385eaef 160000 --- a/lite_routing +++ b/lite_routing @@ -1 +1 @@ -Subproject commit bf87c8492ae0a7dee8b28c577ffb7d1f62db94f4 +Subproject commit 9f0385eaefe6eb6ebff05743f617b89b5691f85a From c43935b52f492cc055821e65ab569935393a9933 Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Tue, 20 Aug 2024 14:18:10 +0100 Subject: [PATCH 53/86] Add endpoint for licence statuses --- api/data_workspace/urls.py | 2 + api/data_workspace/v2/__init__.py | 0 api/data_workspace/v2/serializers.py | 5 ++ api/data_workspace/v2/tests/__init__.py | 0 api/data_workspace/v2/tests/bdd/__init__.py | 0 .../bdd/scenarios/licence_statuses.feature | 13 ++++ .../v2/tests/bdd/test_licence_statuses.py | 65 +++++++++++++++++++ api/data_workspace/v2/urls.py | 11 ++++ api/data_workspace/v2/views.py | 20 ++++++ api/licences/enums.py | 4 ++ 10 files changed, 120 insertions(+) create mode 100644 api/data_workspace/v2/__init__.py create mode 100644 api/data_workspace/v2/serializers.py create mode 100644 api/data_workspace/v2/tests/__init__.py create mode 100644 api/data_workspace/v2/tests/bdd/__init__.py create mode 100644 api/data_workspace/v2/tests/bdd/scenarios/licence_statuses.feature create mode 100644 api/data_workspace/v2/tests/bdd/test_licence_statuses.py create mode 100644 api/data_workspace/v2/urls.py create mode 100644 api/data_workspace/v2/views.py diff --git a/api/data_workspace/urls.py b/api/data_workspace/urls.py index 58bbcadd8e..ac00469713 100644 --- a/api/data_workspace/urls.py +++ b/api/data_workspace/urls.py @@ -5,6 +5,7 @@ from api.data_workspace.v0.urls import router_v0 from api.data_workspace.v1.urls import router_v1 +from api.data_workspace.v2.urls import router_v2 app_name = "data_workspace" @@ -12,4 +13,5 @@ urlpatterns = [ path("v0/", include((router_v0.urls, "data_workspace_v0"), namespace="v0")), path("v1/", include((router_v1.urls, "data_workspace_v1"), namespace="v1")), + path("v2/", include((router_v2.urls, "data_workspace_v2"), namespace="v2")), ] diff --git a/api/data_workspace/v2/__init__.py b/api/data_workspace/v2/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py new file mode 100644 index 0000000000..db93b08821 --- /dev/null +++ b/api/data_workspace/v2/serializers.py @@ -0,0 +1,5 @@ +from rest_framework import serializers + + +class LicenceStatusSerializer(serializers.Serializer): + name = serializers.CharField(source="*") diff --git a/api/data_workspace/v2/tests/__init__.py b/api/data_workspace/v2/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/api/data_workspace/v2/tests/bdd/__init__.py b/api/data_workspace/v2/tests/bdd/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/api/data_workspace/v2/tests/bdd/scenarios/licence_statuses.feature b/api/data_workspace/v2/tests/bdd/scenarios/licence_statuses.feature new file mode 100644 index 0000000000..182c801357 --- /dev/null +++ b/api/data_workspace/v2/tests/bdd/scenarios/licence_statuses.feature @@ -0,0 +1,13 @@ +Scenario: Licence statuses + Given the following licence statuses: + | name | + | cancelled | + | draft | + | exhausted | + | expired | + | issued | + | reinstated | + | revoked | + | surrendered | + | suspended | + Then there are no other licence statuses diff --git a/api/data_workspace/v2/tests/bdd/test_licence_statuses.py b/api/data_workspace/v2/tests/bdd/test_licence_statuses.py new file mode 100644 index 0000000000..b6d593874a --- /dev/null +++ b/api/data_workspace/v2/tests/bdd/test_licence_statuses.py @@ -0,0 +1,65 @@ +import pytest + +from django.urls import reverse +from pytest_bdd import ( + given, + parsers, + then, + scenarios, +) +from rest_framework import status + + +scenarios("./scenarios/licence_statuses.feature") + + +def create_table(data_table): + lines = data_table.strip().split("\n") + + keys = [key.strip() for key in lines[0].split("|") if key] + + parsed_data_table = [] + for line in lines[1:]: + values = [value.strip() for value in line.split("|") if value] + entry = dict(zip(keys, values)) + parsed_data_table.append(entry) + + return parsed_data_table + + +@pytest.fixture() +def unpage_data(client): + def _unpage_data(url): + unpaged_results = [] + while True: + response = client.get(url) + assert response.status_code == status.HTTP_200_OK + unpaged_results += response.data["results"] + if not response.data["next"]: + break + url = response.data["next"] + + return unpaged_results + + return _unpage_data + + +@pytest.fixture() +def licence_status_list_url(): + return reverse("data_workspace:v2:dw-licence-statuses-list") + + +@given( + parsers.parse("the following licence statuses:\n{licence_statuses}"), target_fixture="found_licence_status_names" +) +def the_following_licence_statuses(licence_statuses): + licence_statuses = create_table(licence_statuses) + return [licence_status["name"] for licence_status in licence_statuses] + + +@then("there are no other licence statuses") +def no_other_licence_statuses(found_licence_status_names, unpage_data, licence_status_list_url): + licence_status_data = unpage_data(licence_status_list_url) + assert sorted(found_licence_status_names) == sorted( + [licence_status["name"] for licence_status in licence_status_data] + ) diff --git a/api/data_workspace/v2/urls.py b/api/data_workspace/v2/urls.py new file mode 100644 index 0000000000..0529332841 --- /dev/null +++ b/api/data_workspace/v2/urls.py @@ -0,0 +1,11 @@ +from rest_framework.routers import DefaultRouter + +from api.data_workspace.v2 import views + + +router_v2 = DefaultRouter() +router_v2.register( + "licence-statuses", + views.LicenceStatusesListView, + basename="dw-licence-statuses", +) diff --git a/api/data_workspace/v2/views.py b/api/data_workspace/v2/views.py new file mode 100644 index 0000000000..13a7386122 --- /dev/null +++ b/api/data_workspace/v2/views.py @@ -0,0 +1,20 @@ +from rest_framework import viewsets +from rest_framework.generics import ListAPIView +from rest_framework.pagination import LimitOffsetPagination +from rest_framework.settings import api_settings + +from rest_framework_csv.renderers import PaginatedCSVRenderer + +from api.core.authentication import DataWorkspaceOnlyAuthentication +from api.data_workspace.v2.serializers import LicenceStatusSerializer +from api.licences.enums import LicenceStatus + + +class LicenceStatusesListView(viewsets.GenericViewSet, ListAPIView): + authentication_classes = (DataWorkspaceOnlyAuthentication,) + pagination_class = LimitOffsetPagination + renderer_classes = tuple(api_settings.DEFAULT_RENDERER_CLASSES) + (PaginatedCSVRenderer,) + serializer_class = LicenceStatusSerializer + + def get_queryset(self): + return LicenceStatus.all() diff --git a/api/licences/enums.py b/api/licences/enums.py index 3aa338ea76..d090cd7aaa 100644 --- a/api/licences/enums.py +++ b/api/licences/enums.py @@ -45,6 +45,10 @@ def to_str(cls, status): def can_edit_status(cls, status): return status in cls._can_edit_status + @classmethod + def all(cls): + return [getattr(cls, param) for param in dir(cls) if param.isupper()] + hmrc_integration_action_to_licence_status = { HMRCIntegrationActionEnum.SURRENDER: LicenceStatus.SURRENDERED, From 8f8fb042948230d1cdc63e3770d0312428c5989e Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Tue, 15 Oct 2024 15:29:22 +0100 Subject: [PATCH 54/86] Add endpoint for retrieving SIEL licences list --- api/data_workspace/v2/serializers.py | 13 ++++++++ .../v2/tests/bdd/licences/conftest.py | 31 +++++++++++++++++++ .../{ => licences}/test_licence_statuses.py | 24 +++++++++++++- .../bdd/scenarios/licence_statuses.feature | 5 +++ api/data_workspace/v2/urls.py | 6 ++++ api/data_workspace/v2/views.py | 13 +++++++- 6 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 api/data_workspace/v2/tests/bdd/licences/conftest.py rename api/data_workspace/v2/tests/bdd/{ => licences}/test_licence_statuses.py (70%) diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index db93b08821..4ef762378e 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -1,5 +1,18 @@ from rest_framework import serializers +from api.licences.models import Licence + class LicenceStatusSerializer(serializers.Serializer): name = serializers.CharField(source="*") + + +class SIELLicenceSerializer(serializers.ModelSerializer): + status = serializers.SerializerMethodField() + + class Meta: + model = Licence + fields = ( + "id", + "reference_code", + ) diff --git a/api/data_workspace/v2/tests/bdd/licences/conftest.py b/api/data_workspace/v2/tests/bdd/licences/conftest.py new file mode 100644 index 0000000000..a6f4a208d7 --- /dev/null +++ b/api/data_workspace/v2/tests/bdd/licences/conftest.py @@ -0,0 +1,31 @@ +import pytest + +from api.applications.tests.factories import GoodOnApplicationFactory, StandardApplicationFactory +from api.goods.tests.factories import GoodFactory +from api.licences.enums import LicenceStatus +from api.licences.tests.factories import GoodOnLicenceFactory, StandardLicenceFactory +from api.staticdata.statuses.enums import CaseStatusEnum +from api.staticdata.statuses.models import CaseStatus +from api.staticdata.units.enums import Units + + +@pytest.fixture() +def standard_licence(): + application = StandardApplicationFactory( + status=CaseStatus.objects.get(status=CaseStatusEnum.FINALISED), + ) + good = GoodFactory(organisation=application.organisation) + good_on_application = GoodOnApplicationFactory( + application=application, good=good, quantity=100.0, value=1500, unit=Units.NAR + ) + licence = StandardLicenceFactory(case=application, status=LicenceStatus.DRAFT) + GoodOnLicenceFactory( + good=good_on_application, + quantity=good_on_application.quantity, + usage=0.0, + value=good_on_application.value, + licence=licence, + ) + licence.status = LicenceStatus.ISSUED + licence.save() + return licence diff --git a/api/data_workspace/v2/tests/bdd/test_licence_statuses.py b/api/data_workspace/v2/tests/bdd/licences/test_licence_statuses.py similarity index 70% rename from api/data_workspace/v2/tests/bdd/test_licence_statuses.py rename to api/data_workspace/v2/tests/bdd/licences/test_licence_statuses.py index b6d593874a..7ea1d86752 100644 --- a/api/data_workspace/v2/tests/bdd/test_licence_statuses.py +++ b/api/data_workspace/v2/tests/bdd/licences/test_licence_statuses.py @@ -10,7 +10,7 @@ from rest_framework import status -scenarios("./scenarios/licence_statuses.feature") +scenarios("../scenarios/licence_statuses.feature") def create_table(data_table): @@ -49,6 +49,11 @@ def licence_status_list_url(): return reverse("data_workspace:v2:dw-licence-statuses-list") +@pytest.fixture() +def licences_list_url(): + return reverse("data_workspace:v2:dw-siel-licences-list") + + @given( parsers.parse("the following licence statuses:\n{licence_statuses}"), target_fixture="found_licence_status_names" ) @@ -63,3 +68,20 @@ def no_other_licence_statuses(found_licence_status_names, unpage_data, licence_s assert sorted(found_licence_status_names) == sorted( [licence_status["name"] for licence_status in licence_status_data] ) + + +@given("a standard licence is issued", target_fixture="issued_licence") +def standard_licence_issued(standard_licence): + assert standard_licence.status == "issued" + return standard_licence + + +@then("the issued licence is included in the extract") +def licence_included_in_extract(issued_licence, unpage_data, licences_list_url): + licences = unpage_data(licences_list_url) + + licence = [item for item in licences if item["id"] == str(issued_licence.id)] + assert len(licence) == 1 + licence = licence[0] + + assert licence["status"] == "issued" diff --git a/api/data_workspace/v2/tests/bdd/scenarios/licence_statuses.feature b/api/data_workspace/v2/tests/bdd/scenarios/licence_statuses.feature index 182c801357..e37352c669 100644 --- a/api/data_workspace/v2/tests/bdd/scenarios/licence_statuses.feature +++ b/api/data_workspace/v2/tests/bdd/scenarios/licence_statuses.feature @@ -11,3 +11,8 @@ Scenario: Licence statuses | surrendered | | suspended | Then there are no other licence statuses + + +Scenario: Issued licence is included in the extract + Given a standard licence is issued + Then the issued licence is included in the extract diff --git a/api/data_workspace/v2/urls.py b/api/data_workspace/v2/urls.py index 0529332841..076aa4f652 100644 --- a/api/data_workspace/v2/urls.py +++ b/api/data_workspace/v2/urls.py @@ -9,3 +9,9 @@ views.LicenceStatusesListView, basename="dw-licence-statuses", ) + +router_v2.register( + "siel-licences", + views.SIELLicencesListView, + basename="dw-siel-licences", +) diff --git a/api/data_workspace/v2/views.py b/api/data_workspace/v2/views.py index 13a7386122..16d92956d9 100644 --- a/api/data_workspace/v2/views.py +++ b/api/data_workspace/v2/views.py @@ -6,8 +6,9 @@ from rest_framework_csv.renderers import PaginatedCSVRenderer from api.core.authentication import DataWorkspaceOnlyAuthentication -from api.data_workspace.v2.serializers import LicenceStatusSerializer +from api.data_workspace.v2.serializers import LicenceStatusSerializer, SIELLicenceSerializer from api.licences.enums import LicenceStatus +from api.licences.models import Licence class LicenceStatusesListView(viewsets.GenericViewSet, ListAPIView): @@ -18,3 +19,13 @@ class LicenceStatusesListView(viewsets.GenericViewSet, ListAPIView): def get_queryset(self): return LicenceStatus.all() + + +class SIELLicencesListView(viewsets.ReadOnlyModelViewSet): + authentication_classes = (DataWorkspaceOnlyAuthentication,) + pagination_class = LimitOffsetPagination + renderer_classes = tuple(api_settings.DEFAULT_RENDERER_CLASSES) + (PaginatedCSVRenderer,) + serializer_class = SIELLicenceSerializer + + def get_queryset(self): + return Licence.objects.exclude(status=LicenceStatus.DRAFT) From ab31298ef09a9f401f0e2b1bfea08c6c8dc9aa24 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Tue, 15 Oct 2024 17:12:50 +0100 Subject: [PATCH 55/86] Address review comments - remove licence statuses endpoint for now - make tests work --- api/data_workspace/v2/serializers.py | 7 +- api/data_workspace/v2/tests/bdd/conftest.py | 28 ++++++ .../v2/tests/bdd/licences/conftest.py | 20 +++++ .../bdd/licences/test_licence_statuses.py | 87 ------------------- .../v2/tests/bdd/licences/test_licences.py | 44 ++++++++++ .../bdd/scenarios/licence_statuses.feature | 18 ---- .../v2/tests/bdd/scenarios/licences.feature | 10 +++ api/data_workspace/v2/urls.py | 9 +- api/data_workspace/v2/views.py | 17 +--- 9 files changed, 108 insertions(+), 132 deletions(-) create mode 100644 api/data_workspace/v2/tests/bdd/conftest.py delete mode 100644 api/data_workspace/v2/tests/bdd/licences/test_licence_statuses.py create mode 100644 api/data_workspace/v2/tests/bdd/licences/test_licences.py delete mode 100644 api/data_workspace/v2/tests/bdd/scenarios/licence_statuses.feature create mode 100644 api/data_workspace/v2/tests/bdd/scenarios/licences.feature diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index 4ef762378e..a2ad495b2f 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -3,12 +3,7 @@ from api.licences.models import Licence -class LicenceStatusSerializer(serializers.Serializer): - name = serializers.CharField(source="*") - - -class SIELLicenceSerializer(serializers.ModelSerializer): - status = serializers.SerializerMethodField() +class LicenceSerializer(serializers.ModelSerializer): class Meta: model = Licence diff --git a/api/data_workspace/v2/tests/bdd/conftest.py b/api/data_workspace/v2/tests/bdd/conftest.py new file mode 100644 index 0000000000..dcc6918eb5 --- /dev/null +++ b/api/data_workspace/v2/tests/bdd/conftest.py @@ -0,0 +1,28 @@ +import pytest + +from rest_framework import status + +from api.users.enums import SystemUser +from api.users.tests.factories import BaseUserFactory + + +@pytest.fixture(autouse=True) +def system_user(db): + return BaseUserFactory(id=SystemUser.id) + + +@pytest.fixture() +def unpage_data(client): + def _unpage_data(url): + unpaged_results = [] + while True: + response = client.get(url) + assert response.status_code == status.HTTP_200_OK + unpaged_results += response.data["results"] + if not response.data["next"]: + break + url = response.data["next"] + + return unpaged_results + + return _unpage_data diff --git a/api/data_workspace/v2/tests/bdd/licences/conftest.py b/api/data_workspace/v2/tests/bdd/licences/conftest.py index a6f4a208d7..f0a00c72ca 100644 --- a/api/data_workspace/v2/tests/bdd/licences/conftest.py +++ b/api/data_workspace/v2/tests/bdd/licences/conftest.py @@ -9,6 +9,26 @@ from api.staticdata.units.enums import Units +@pytest.fixture() +def standard_draft_licence(): + application = StandardApplicationFactory( + status=CaseStatus.objects.get(status=CaseStatusEnum.FINALISED), + ) + good = GoodFactory(organisation=application.organisation) + good_on_application = GoodOnApplicationFactory( + application=application, good=good, quantity=100.0, value=1500, unit=Units.NAR + ) + licence = StandardLicenceFactory(case=application, status=LicenceStatus.DRAFT) + GoodOnLicenceFactory( + good=good_on_application, + quantity=good_on_application.quantity, + usage=0.0, + value=good_on_application.value, + licence=licence, + ) + return licence + + @pytest.fixture() def standard_licence(): application = StandardApplicationFactory( diff --git a/api/data_workspace/v2/tests/bdd/licences/test_licence_statuses.py b/api/data_workspace/v2/tests/bdd/licences/test_licence_statuses.py deleted file mode 100644 index 7ea1d86752..0000000000 --- a/api/data_workspace/v2/tests/bdd/licences/test_licence_statuses.py +++ /dev/null @@ -1,87 +0,0 @@ -import pytest - -from django.urls import reverse -from pytest_bdd import ( - given, - parsers, - then, - scenarios, -) -from rest_framework import status - - -scenarios("../scenarios/licence_statuses.feature") - - -def create_table(data_table): - lines = data_table.strip().split("\n") - - keys = [key.strip() for key in lines[0].split("|") if key] - - parsed_data_table = [] - for line in lines[1:]: - values = [value.strip() for value in line.split("|") if value] - entry = dict(zip(keys, values)) - parsed_data_table.append(entry) - - return parsed_data_table - - -@pytest.fixture() -def unpage_data(client): - def _unpage_data(url): - unpaged_results = [] - while True: - response = client.get(url) - assert response.status_code == status.HTTP_200_OK - unpaged_results += response.data["results"] - if not response.data["next"]: - break - url = response.data["next"] - - return unpaged_results - - return _unpage_data - - -@pytest.fixture() -def licence_status_list_url(): - return reverse("data_workspace:v2:dw-licence-statuses-list") - - -@pytest.fixture() -def licences_list_url(): - return reverse("data_workspace:v2:dw-siel-licences-list") - - -@given( - parsers.parse("the following licence statuses:\n{licence_statuses}"), target_fixture="found_licence_status_names" -) -def the_following_licence_statuses(licence_statuses): - licence_statuses = create_table(licence_statuses) - return [licence_status["name"] for licence_status in licence_statuses] - - -@then("there are no other licence statuses") -def no_other_licence_statuses(found_licence_status_names, unpage_data, licence_status_list_url): - licence_status_data = unpage_data(licence_status_list_url) - assert sorted(found_licence_status_names) == sorted( - [licence_status["name"] for licence_status in licence_status_data] - ) - - -@given("a standard licence is issued", target_fixture="issued_licence") -def standard_licence_issued(standard_licence): - assert standard_licence.status == "issued" - return standard_licence - - -@then("the issued licence is included in the extract") -def licence_included_in_extract(issued_licence, unpage_data, licences_list_url): - licences = unpage_data(licences_list_url) - - licence = [item for item in licences if item["id"] == str(issued_licence.id)] - assert len(licence) == 1 - licence = licence[0] - - assert licence["status"] == "issued" diff --git a/api/data_workspace/v2/tests/bdd/licences/test_licences.py b/api/data_workspace/v2/tests/bdd/licences/test_licences.py new file mode 100644 index 0000000000..624c0d15ac --- /dev/null +++ b/api/data_workspace/v2/tests/bdd/licences/test_licences.py @@ -0,0 +1,44 @@ +import pytest + +from django.urls import reverse +from pytest_bdd import ( + given, + then, + scenarios, +) + +from api.licences.enums import LicenceStatus + + +scenarios("../scenarios/licences.feature") + + +@pytest.fixture() +def licences_list_url(): + return reverse("data_workspace:v2:dw-licences-list") + + +@given("a standard draft licence is created", target_fixture="draft_licence") +def standard_draft_licence_created(standard_draft_licence): + assert standard_draft_licence.status == LicenceStatus.DRAFT + return standard_draft_licence + + +@then("the draft licence is not included in the extract") +def draft_licence_not_included_in_extract(draft_licence, unpage_data, licences_list_url): + licences = unpage_data(licences_list_url) + + assert draft_licence.reference_code not in [item["reference_code"] for item in licences] + + +@given("a standard licence is issued", target_fixture="issued_licence") +def standard_licence_issued(standard_licence): + assert standard_licence.status == LicenceStatus.ISSUED + return standard_licence + + +@then("the issued licence is included in the extract") +def licence_included_in_extract(issued_licence, unpage_data, licences_list_url): + licences = unpage_data(licences_list_url) + + assert issued_licence.reference_code in [item["reference_code"] for item in licences] diff --git a/api/data_workspace/v2/tests/bdd/scenarios/licence_statuses.feature b/api/data_workspace/v2/tests/bdd/scenarios/licence_statuses.feature deleted file mode 100644 index e37352c669..0000000000 --- a/api/data_workspace/v2/tests/bdd/scenarios/licence_statuses.feature +++ /dev/null @@ -1,18 +0,0 @@ -Scenario: Licence statuses - Given the following licence statuses: - | name | - | cancelled | - | draft | - | exhausted | - | expired | - | issued | - | reinstated | - | revoked | - | surrendered | - | suspended | - Then there are no other licence statuses - - -Scenario: Issued licence is included in the extract - Given a standard licence is issued - Then the issued licence is included in the extract diff --git a/api/data_workspace/v2/tests/bdd/scenarios/licences.feature b/api/data_workspace/v2/tests/bdd/scenarios/licences.feature new file mode 100644 index 0000000000..cafa9c05fb --- /dev/null +++ b/api/data_workspace/v2/tests/bdd/scenarios/licences.feature @@ -0,0 +1,10 @@ +@db +Feature: Licences + +Scenario: Check that draft licences are not included in the extract + Given a standard draft licence is created + Then the draft licence is not included in the extract + +Scenario: Issued licence is included in the extract + Given a standard licence is issued + Then the issued licence is included in the extract diff --git a/api/data_workspace/v2/urls.py b/api/data_workspace/v2/urls.py index 076aa4f652..9f36efbc4e 100644 --- a/api/data_workspace/v2/urls.py +++ b/api/data_workspace/v2/urls.py @@ -4,14 +4,9 @@ router_v2 = DefaultRouter() -router_v2.register( - "licence-statuses", - views.LicenceStatusesListView, - basename="dw-licence-statuses", -) router_v2.register( "siel-licences", - views.SIELLicencesListView, - basename="dw-siel-licences", + views.LicencesListView, + basename="dw-licences", ) diff --git a/api/data_workspace/v2/views.py b/api/data_workspace/v2/views.py index 16d92956d9..28e85d4fbb 100644 --- a/api/data_workspace/v2/views.py +++ b/api/data_workspace/v2/views.py @@ -1,31 +1,20 @@ from rest_framework import viewsets -from rest_framework.generics import ListAPIView from rest_framework.pagination import LimitOffsetPagination from rest_framework.settings import api_settings from rest_framework_csv.renderers import PaginatedCSVRenderer from api.core.authentication import DataWorkspaceOnlyAuthentication -from api.data_workspace.v2.serializers import LicenceStatusSerializer, SIELLicenceSerializer +from api.data_workspace.v2.serializers import LicenceSerializer from api.licences.enums import LicenceStatus from api.licences.models import Licence -class LicenceStatusesListView(viewsets.GenericViewSet, ListAPIView): +class LicencesListView(viewsets.ReadOnlyModelViewSet): authentication_classes = (DataWorkspaceOnlyAuthentication,) pagination_class = LimitOffsetPagination renderer_classes = tuple(api_settings.DEFAULT_RENDERER_CLASSES) + (PaginatedCSVRenderer,) - serializer_class = LicenceStatusSerializer - - def get_queryset(self): - return LicenceStatus.all() - - -class SIELLicencesListView(viewsets.ReadOnlyModelViewSet): - authentication_classes = (DataWorkspaceOnlyAuthentication,) - pagination_class = LimitOffsetPagination - renderer_classes = tuple(api_settings.DEFAULT_RENDERER_CLASSES) + (PaginatedCSVRenderer,) - serializer_class = SIELLicenceSerializer + serializer_class = LicenceSerializer def get_queryset(self): return Licence.objects.exclude(status=LicenceStatus.DRAFT) From a6bb379b8a97ebec666969ba2c641d635638d47e Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Wed, 16 Oct 2024 17:15:12 +0100 Subject: [PATCH 56/86] Update url name and fix fixture --- api/data_workspace/v2/tests/bdd/conftest.py | 6 +++++- api/data_workspace/v2/urls.py | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/api/data_workspace/v2/tests/bdd/conftest.py b/api/data_workspace/v2/tests/bdd/conftest.py index dcc6918eb5..5ee9cb8c1b 100644 --- a/api/data_workspace/v2/tests/bdd/conftest.py +++ b/api/data_workspace/v2/tests/bdd/conftest.py @@ -3,12 +3,16 @@ from rest_framework import status from api.users.enums import SystemUser +from api.users.models import BaseUser from api.users.tests.factories import BaseUserFactory @pytest.fixture(autouse=True) def system_user(db): - return BaseUserFactory(id=SystemUser.id) + if BaseUser.objects.filter(id=SystemUser.id).exists(): + return BaseUser.objects.get(id=SystemUser.id) + else: + return BaseUserFactory(id=SystemUser.id) @pytest.fixture() diff --git a/api/data_workspace/v2/urls.py b/api/data_workspace/v2/urls.py index 9f36efbc4e..11d4513512 100644 --- a/api/data_workspace/v2/urls.py +++ b/api/data_workspace/v2/urls.py @@ -6,7 +6,7 @@ router_v2 = DefaultRouter() router_v2.register( - "siel-licences", + "licences", views.LicencesListView, basename="dw-licences", ) From 9d3a2fba1c05198d41ef85e7b0243f0aa8a81229 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 18 Oct 2024 11:21:51 +0100 Subject: [PATCH 57/86] Add licence issue date to licences list Licence document generation date is taken for this purpose. --- api/data_workspace/v2/serializers.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index a2ad495b2f..82f2bc28fd 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -1,13 +1,40 @@ from rest_framework import serializers +from api.cases.generated_documents.models import GeneratedCaseDocument +from api.licences.enums import LicenceStatus from api.licences.models import Licence +SIEL_TEMPLATE_ID = "d159b195-9256-4a00-9bc8-1eb2cebfa1d2" + class LicenceSerializer(serializers.ModelSerializer): + status = serializers.SerializerMethodField() + issued_date = serializers.SerializerMethodField() class Meta: model = Licence fields = ( "id", "reference_code", + "status", + "issued_date", + ) + + def get_status(self, licence): + return LicenceStatus.ISSUED + + def get_issued_date(self, licence): + licence_document = GeneratedCaseDocument.objects.filter( + licence=licence, + template_id=SIEL_TEMPLATE_ID, + safe=True, + visible_to_exporter=True, ) + + if not licence_document.exists(): + return "Invalid licence" + + if licence_document.count() > 1: + return "Multiple licence documents" + + return licence_document.first().updated_at From 5af71db33003959051395fb3df26163a0b11dca0 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 18 Oct 2024 11:43:57 +0100 Subject: [PATCH 58/86] Update Licences list view to excludes licences with no goods When all products on the application are NLR then the current code allowed creation of a licence due a bug. This is not fixed yet so exclude these cases as it can skew licence data. --- api/data_workspace/v2/serializers.py | 2 +- api/data_workspace/v2/views.py | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index 82f2bc28fd..f486a34813 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -32,7 +32,7 @@ def get_issued_date(self, licence): ) if not licence_document.exists(): - return "Invalid licence" + return f"Invalid licence ({licence.status})" if licence_document.count() > 1: return "Multiple licence documents" diff --git a/api/data_workspace/v2/views.py b/api/data_workspace/v2/views.py index 28e85d4fbb..6dab95a331 100644 --- a/api/data_workspace/v2/views.py +++ b/api/data_workspace/v2/views.py @@ -1,3 +1,4 @@ +from django.db.models import Count from rest_framework import viewsets from rest_framework.pagination import LimitOffsetPagination from rest_framework.settings import api_settings @@ -17,4 +18,13 @@ class LicencesListView(viewsets.ReadOnlyModelViewSet): serializer_class = LicenceSerializer def get_queryset(self): - return Licence.objects.exclude(status=LicenceStatus.DRAFT) + # When an application with all goods as NLR is finalised then the current code + # creates a licence however the goods on this licence will be empty. This + # will skew licence data hence exclude them + return ( + Licence.objects.prefetch_related("goods") + .annotate(num_licensed_goods=Count("goods")) + .exclude(status=LicenceStatus.DRAFT) + .exclude(num_licensed_goods=0) + .order_by("-reference_code") + ) From 0acb5fa48e5ad2259e24c30ddc6878a44fe3a91f Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 18 Oct 2024 11:49:56 +0100 Subject: [PATCH 59/86] Only consider licences for finalised Cases In some case a licence is issued but subsequently application is marked as withdrawn. Licence also should've been cancelled in this case but we are not handling this atm so filter these cases. --- api/data_workspace/v2/views.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/api/data_workspace/v2/views.py b/api/data_workspace/v2/views.py index 6dab95a331..0c9a13ef89 100644 --- a/api/data_workspace/v2/views.py +++ b/api/data_workspace/v2/views.py @@ -9,6 +9,7 @@ from api.data_workspace.v2.serializers import LicenceSerializer from api.licences.enums import LicenceStatus from api.licences.models import Licence +from api.staticdata.statuses.enums import CaseStatusEnum class LicencesListView(viewsets.ReadOnlyModelViewSet): @@ -26,5 +27,11 @@ def get_queryset(self): .annotate(num_licensed_goods=Count("goods")) .exclude(status=LicenceStatus.DRAFT) .exclude(num_licensed_goods=0) + .filter( + case__status__status__in=[ + CaseStatusEnum.FINALISED, + CaseStatusEnum.SUPERSEDED_BY_EXPORTER_EDIT, + ], + ) .order_by("-reference_code") ) From 752ac12b2696dc481a1058126887c325cb2af42e Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 18 Oct 2024 12:03:13 +0100 Subject: [PATCH 60/86] Ignore cancelled licences As there can be multiple documents in these cases --- api/data_workspace/v2/serializers.py | 3 --- api/data_workspace/v2/views.py | 7 ++++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index f486a34813..7c4fbc5ab8 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -31,9 +31,6 @@ def get_issued_date(self, licence): visible_to_exporter=True, ) - if not licence_document.exists(): - return f"Invalid licence ({licence.status})" - if licence_document.count() > 1: return "Multiple licence documents" diff --git a/api/data_workspace/v2/views.py b/api/data_workspace/v2/views.py index 0c9a13ef89..ec52bea8a2 100644 --- a/api/data_workspace/v2/views.py +++ b/api/data_workspace/v2/views.py @@ -25,7 +25,12 @@ def get_queryset(self): return ( Licence.objects.prefetch_related("goods") .annotate(num_licensed_goods=Count("goods")) - .exclude(status=LicenceStatus.DRAFT) + .exclude( + status__in=[ + LicenceStatus.DRAFT, + LicenceStatus.CANCELLED, + ] + ) .exclude(num_licensed_goods=0) .filter( case__status__status__in=[ From 5f2fc46687d9b112a4c3b664b2f64c6c0ddb130d Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 18 Oct 2024 15:51:07 +0100 Subject: [PATCH 61/86] Rename status to decision as that is what it is --- api/data_workspace/v2/serializers.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index 7c4fbc5ab8..3b7450ca3b 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -8,7 +8,7 @@ class LicenceSerializer(serializers.ModelSerializer): - status = serializers.SerializerMethodField() + decision = serializers.SerializerMethodField() issued_date = serializers.SerializerMethodField() class Meta: @@ -16,11 +16,11 @@ class Meta: fields = ( "id", "reference_code", - "status", + "decision", "issued_date", ) - def get_status(self, licence): + def get_decision(self, licence): return LicenceStatus.ISSUED def get_issued_date(self, licence): From a2788188f1f3ee332689d01a5bdcc0daaa133901 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Mon, 21 Oct 2024 06:15:25 +0100 Subject: [PATCH 62/86] Add more common fixtures --- api/data_workspace/v2/tests/bdd/conftest.py | 34 +++++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/api/data_workspace/v2/tests/bdd/conftest.py b/api/data_workspace/v2/tests/bdd/conftest.py index 5ee9cb8c1b..9ef5c854d1 100644 --- a/api/data_workspace/v2/tests/bdd/conftest.py +++ b/api/data_workspace/v2/tests/bdd/conftest.py @@ -2,9 +2,11 @@ from rest_framework import status -from api.users.enums import SystemUser -from api.users.models import BaseUser -from api.users.tests.factories import BaseUserFactory +from api.core.constants import GovPermissions +from api.users.libraries.user_to_token import user_to_token +from api.users.enums import SystemUser, UserType +from api.users.models import BaseUser, Permission +from api.users.tests.factories import BaseUserFactory, GovUserFactory, RoleFactory @pytest.fixture(autouse=True) @@ -15,6 +17,32 @@ def system_user(db): return BaseUserFactory(id=SystemUser.id) +@pytest.fixture() +def gov_user(): + return GovUserFactory() + + +@pytest.fixture() +def gov_user_permissions(): + for permission in GovPermissions: + Permission.objects.get_or_create(id=permission.name, name=permission.name, type=UserType.INTERNAL) + + +@pytest.fixture() +def lu_case_officer(gov_user, gov_user_permissions): + gov_user.role = RoleFactory(name="Case officer", type=UserType.INTERNAL) + gov_user.role.permissions.set( + [GovPermissions.MANAGE_LICENCE_FINAL_ADVICE.name, GovPermissions.MANAGE_LICENCE_DURATION.name] + ) + gov_user.save() + return gov_user + + +@pytest.fixture() +def gov_headers(gov_user): + return {"HTTP_GOV_USER_TOKEN": user_to_token(gov_user.baseuser_ptr)} + + @pytest.fixture() def unpage_data(client): def _unpage_data(url): From 7698b156f6d9eff0ae44444d149f272250ce61c2 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Mon, 21 Oct 2024 13:22:36 +0100 Subject: [PATCH 63/86] Seed letter layouts and templates --- api/data_workspace/v2/tests/bdd/conftest.py | 31 +++++++++++++++++++ .../bdd/initial_data/letter_layouts.json | 17 ++++++++++ .../bdd/initial_data/letter_templates.json | 23 ++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 api/data_workspace/v2/tests/bdd/initial_data/letter_layouts.json create mode 100644 api/data_workspace/v2/tests/bdd/initial_data/letter_templates.json diff --git a/api/data_workspace/v2/tests/bdd/conftest.py b/api/data_workspace/v2/tests/bdd/conftest.py index 9ef5c854d1..d085eef4d0 100644 --- a/api/data_workspace/v2/tests/bdd/conftest.py +++ b/api/data_workspace/v2/tests/bdd/conftest.py @@ -1,14 +1,45 @@ +import csv +import json import pytest from rest_framework import status +from api.cases.enums import CaseTypeEnum, CaseTypeSubTypeEnum +from api.cases.models import CaseType from api.core.constants import GovPermissions +from api.letter_templates.models import LetterTemplate +from api.staticdata.letter_layouts.models import LetterLayout from api.users.libraries.user_to_token import user_to_token from api.users.enums import SystemUser, UserType from api.users.models import BaseUser, Permission from api.users.tests.factories import BaseUserFactory, GovUserFactory, RoleFactory +def load_json(filename): + with open(filename) as f: + return json.load(f) + + +@pytest.fixture() +def seed_layouts(): + layouts = load_json("api/data_workspace/v2/tests/bdd/initial_data/letter_layouts.json") + for layout in layouts: + LetterLayout.objects.get_or_create(**layout) + + +@pytest.fixture() +def seed_templates(seed_layouts): + templates = load_json("api/data_workspace/v2/tests/bdd/initial_data/letter_templates.json") + for template in templates: + template_instance, _ = LetterTemplate.objects.get_or_create(**template) + template_instance.case_types.add(CaseType.objects.get(id=CaseTypeEnum.SIEL.id)) + + +@pytest.fixture() +def siel_template(seed_templates): + return LetterTemplate.objects.get(layout_id="00000000-0000-0000-0000-000000000001") + + @pytest.fixture(autouse=True) def system_user(db): if BaseUser.objects.filter(id=SystemUser.id).exists(): diff --git a/api/data_workspace/v2/tests/bdd/initial_data/letter_layouts.json b/api/data_workspace/v2/tests/bdd/initial_data/letter_layouts.json new file mode 100644 index 0000000000..357579e083 --- /dev/null +++ b/api/data_workspace/v2/tests/bdd/initial_data/letter_layouts.json @@ -0,0 +1,17 @@ +[ + { + "id": "00000000-0000-0000-0000-000000000001", + "name": "SIEL", + "filename": "siel" + }, + { + "id": "00000000-0000-0000-0000-000000000003", + "name": "No Licence Required Letter", + "filename": "nlr" + }, + { + "id": "00000000-0000-0000-0000-000000000006", + "name": "Refusal Letter", + "filename": "refusal" + } +] \ No newline at end of file diff --git a/api/data_workspace/v2/tests/bdd/initial_data/letter_templates.json b/api/data_workspace/v2/tests/bdd/initial_data/letter_templates.json new file mode 100644 index 0000000000..00cb3c626d --- /dev/null +++ b/api/data_workspace/v2/tests/bdd/initial_data/letter_templates.json @@ -0,0 +1,23 @@ +[ + { + "id": "d159b195-9256-4a00-9bc8-1eb2cebfa1d2", + "name": "SIEL template", + "layout_id": "00000000-0000-0000-0000-000000000001", + "visible_to_exporter": true, + "include_digital_signature": true + }, + { + "id": "074d8a54-ee10-4dca-82ba-650460650342", + "name": "Refusal letter template", + "layout_id": "00000000-0000-0000-0000-000000000006", + "visible_to_exporter": true, + "include_digital_signature": true + }, + { + "id": "d71c3cfc-a127-46b6-96c0-a435cdd63cdb", + "name": "No licence required letter template", + "layout_id": "00000000-0000-0000-0000-000000000003", + "visible_to_exporter": true, + "include_digital_signature": true + } +] \ No newline at end of file From 419277e3bce43b268f66dbc4c5de79a1e44946a0 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Mon, 21 Oct 2024 15:07:06 +0100 Subject: [PATCH 64/86] Update licence test to include steps for generating documents --- .../v2/tests/bdd/licences/conftest.py | 14 ++++ .../v2/tests/bdd/licences/test_licences.py | 84 ++++++++++++++++++- .../v2/tests/bdd/scenarios/licences.feature | 11 ++- 3 files changed, 104 insertions(+), 5 deletions(-) diff --git a/api/data_workspace/v2/tests/bdd/licences/conftest.py b/api/data_workspace/v2/tests/bdd/licences/conftest.py index f0a00c72ca..1344850647 100644 --- a/api/data_workspace/v2/tests/bdd/licences/conftest.py +++ b/api/data_workspace/v2/tests/bdd/licences/conftest.py @@ -1,6 +1,7 @@ import pytest from api.applications.tests.factories import GoodOnApplicationFactory, StandardApplicationFactory +from api.cases.tests.factories import FinalAdviceFactory from api.goods.tests.factories import GoodFactory from api.licences.enums import LicenceStatus from api.licences.tests.factories import GoodOnLicenceFactory, StandardLicenceFactory @@ -49,3 +50,16 @@ def standard_licence(): licence.status = LicenceStatus.ISSUED licence.save() return licence + + +@pytest.fixture() +def standard_case_with_final_advice(lu_case_officer): + case = StandardApplicationFactory( + status=CaseStatus.objects.get(status=CaseStatusEnum.UNDER_FINAL_REVIEW), + ) + good = GoodFactory(organisation=case.organisation) + good_on_application = GoodOnApplicationFactory( + application=case, good=good, quantity=100.0, value=1500, unit=Units.NAR + ) + FinalAdviceFactory(user=lu_case_officer, case=case, good=good_on_application.good) + return case diff --git a/api/data_workspace/v2/tests/bdd/licences/test_licences.py b/api/data_workspace/v2/tests/bdd/licences/test_licences.py index 624c0d15ac..c0860a5de3 100644 --- a/api/data_workspace/v2/tests/bdd/licences/test_licences.py +++ b/api/data_workspace/v2/tests/bdd/licences/test_licences.py @@ -1,13 +1,18 @@ import pytest from django.urls import reverse +from django.utils import timezone from pytest_bdd import ( given, then, + when, scenarios, ) +from api.cases.enums import AdviceType from api.licences.enums import LicenceStatus +from api.licences.models import Licence +from api.staticdata.statuses.enums import CaseStatusEnum scenarios("../scenarios/licences.feature") @@ -31,14 +36,87 @@ def draft_licence_not_included_in_extract(draft_licence, unpage_data, licences_l assert draft_licence.reference_code not in [item["reference_code"] for item in licences] -@given("a standard licence is issued", target_fixture="issued_licence") -def standard_licence_issued(standard_licence): - assert standard_licence.status == LicenceStatus.ISSUED +@given("a standard licence is cancelled", target_fixture="cancelled_licence") +def standard_licence_is_cancelled(standard_licence): + standard_licence.status = LicenceStatus.CANCELLED + standard_licence.save() + return standard_licence +@then("the cancelled licence is not included in the extract") +def cancelled_licence_not_included_in_extract(cancelled_licence, unpage_data, licences_list_url): + licences = unpage_data(licences_list_url) + + assert cancelled_licence.reference_code not in [item["reference_code"] for item in licences] + + @then("the issued licence is included in the extract") def licence_included_in_extract(issued_licence, unpage_data, licences_list_url): licences = unpage_data(licences_list_url) assert issued_licence.reference_code in [item["reference_code"] for item in licences] + + +@given("a case is ready to be finalised", target_fixture="case_with_final_advice") +def case_ready_to_be_finalised(standard_case_with_final_advice): + assert standard_case_with_final_advice.status.status == CaseStatusEnum.UNDER_FINAL_REVIEW + return standard_case_with_final_advice + + +@when("the licence for the case is approved") +def licence_for_case_is_approved(client, gov_headers, case_with_final_advice): + data = {"action": AdviceType.APPROVE, "duration": 24} + for good_on_app in case_with_final_advice.goods.all(): + data[f"quantity-{good_on_app.id}"] = str(good_on_app.quantity) + data[f"value-{good_on_app.id}"] = str(good_on_app.value) + + issue_date = timezone.now() + data.update({"year": issue_date.year, "month": issue_date.month, "day": issue_date.day}) + + url = reverse("applications:finalise", kwargs={"pk": case_with_final_advice.id}) + response = client.put(url, data, content_type="application/json", **gov_headers) + assert response.status_code == 200 + response = response.json() + + assert response["reference_code"] is not None + licence = Licence.objects.get(reference_code=response["reference_code"]) + assert licence.status == LicenceStatus.DRAFT + + +@when("case officer generates licence documents") +def licence_for_case_is_approved(client, siel_template, gov_headers, case_with_final_advice): + data = { + "template": str(siel_template.id), + "text": "", + "visible_to_exporter": False, + "advice_type": AdviceType.APPROVE, + } + url = reverse( + "cases:generated_documents:generated_documents", + kwargs={"pk": str(case_with_final_advice.pk)}, + ) + response = client.post(url, data, content_type="application/json", **gov_headers) + assert response.status_code == 201 + + +@when("case officer issues licence for this case", target_fixture="issued_licence") +def licence_for_case_is_approved(client, gov_headers, case_with_final_advice): + url = reverse( + "cases:finalise", + kwargs={"pk": str(case_with_final_advice.pk)}, + ) + response = client.put(url, {}, content_type="application/json", **gov_headers) + assert response.status_code == 201 + + case_with_final_advice.refresh_from_db() + assert case_with_final_advice.status.status == CaseStatusEnum.FINALISED + assert case_with_final_advice.sub_status.name == "Approved" + + response = response.json() + assert response["licence"] is not None + + licence = Licence.objects.get(id=response["licence"]) + assert licence.status == LicenceStatus.ISSUED + + return licence diff --git a/api/data_workspace/v2/tests/bdd/scenarios/licences.feature b/api/data_workspace/v2/tests/bdd/scenarios/licences.feature index cafa9c05fb..f9e5d80069 100644 --- a/api/data_workspace/v2/tests/bdd/scenarios/licences.feature +++ b/api/data_workspace/v2/tests/bdd/scenarios/licences.feature @@ -5,6 +5,13 @@ Scenario: Check that draft licences are not included in the extract Given a standard draft licence is created Then the draft licence is not included in the extract -Scenario: Issued licence is included in the extract - Given a standard licence is issued +Scenario: Check that cancelled licences are not included in the extract + Given a standard licence is cancelled + Then the cancelled licence is not included in the extract + +Scenario: Licence document is generated when licence is issued + Given a case is ready to be finalised + When the licence for the case is approved + And case officer generates licence documents + And case officer issues licence for this case Then the issued licence is included in the extract From 7ad35f848bcf6447f02172626887d57959d36f40 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Tue, 22 Oct 2024 16:58:01 +0100 Subject: [PATCH 65/86] Use Case as base object the get licences list Use Case as base object and use it to filter on the licence documents. This avoids filtering of various case statuses, NLR products etc --- api/data_workspace/v2/serializers.py | 31 ++++++++++-------------- api/data_workspace/v2/views.py | 35 ++++++++++------------------ 2 files changed, 24 insertions(+), 42 deletions(-) diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index 3b7450ca3b..c91bcc0132 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -1,18 +1,16 @@ +from django.db.models import F from rest_framework import serializers from api.cases.generated_documents.models import GeneratedCaseDocument -from api.licences.enums import LicenceStatus -from api.licences.models import Licence +from api.cases.models import Case -SIEL_TEMPLATE_ID = "d159b195-9256-4a00-9bc8-1eb2cebfa1d2" - -class LicenceSerializer(serializers.ModelSerializer): +class CaseLicenceSerializer(serializers.ModelSerializer): decision = serializers.SerializerMethodField() issued_date = serializers.SerializerMethodField() class Meta: - model = Licence + model = Case fields = ( "id", "reference_code", @@ -20,18 +18,13 @@ class Meta: "issued_date", ) - def get_decision(self, licence): - return LicenceStatus.ISSUED + def get_decision(self, case): + return "issued" - def get_issued_date(self, licence): - licence_document = GeneratedCaseDocument.objects.filter( - licence=licence, - template_id=SIEL_TEMPLATE_ID, - safe=True, - visible_to_exporter=True, + def get_issued_date(self, case): + return ( + case.licences.all() + .annotate(issued_at=F("generatedcasedocument__created_at")) + .earliest("issued_at") + .issued_at ) - - if licence_document.count() > 1: - return "Multiple licence documents" - - return licence_document.first().updated_at diff --git a/api/data_workspace/v2/views.py b/api/data_workspace/v2/views.py index ec52bea8a2..d719d879a5 100644 --- a/api/data_workspace/v2/views.py +++ b/api/data_workspace/v2/views.py @@ -1,42 +1,31 @@ -from django.db.models import Count from rest_framework import viewsets from rest_framework.pagination import LimitOffsetPagination from rest_framework.settings import api_settings from rest_framework_csv.renderers import PaginatedCSVRenderer +from api.cases.models import Case +from api.cases.generated_documents.models import GeneratedCaseDocument from api.core.authentication import DataWorkspaceOnlyAuthentication -from api.data_workspace.v2.serializers import LicenceSerializer -from api.licences.enums import LicenceStatus -from api.licences.models import Licence -from api.staticdata.statuses.enums import CaseStatusEnum +from api.data_workspace.v2.serializers import CaseLicenceSerializer + +SIEL_TEMPLATE_ID = "d159b195-9256-4a00-9bc8-1eb2cebfa1d2" class LicencesListView(viewsets.ReadOnlyModelViewSet): authentication_classes = (DataWorkspaceOnlyAuthentication,) pagination_class = LimitOffsetPagination renderer_classes = tuple(api_settings.DEFAULT_RENDERER_CLASSES) + (PaginatedCSVRenderer,) - serializer_class = LicenceSerializer + serializer_class = CaseLicenceSerializer def get_queryset(self): - # When an application with all goods as NLR is finalised then the current code - # creates a licence however the goods on this licence will be empty. This - # will skew licence data hence exclude them + licence_documents = GeneratedCaseDocument.objects.filter( + template_id=SIEL_TEMPLATE_ID, visible_to_exporter=True, safe=True + ) return ( - Licence.objects.prefetch_related("goods") - .annotate(num_licensed_goods=Count("goods")) - .exclude( - status__in=[ - LicenceStatus.DRAFT, - LicenceStatus.CANCELLED, - ] - ) - .exclude(num_licensed_goods=0) - .filter( - case__status__status__in=[ - CaseStatusEnum.FINALISED, - CaseStatusEnum.SUPERSEDED_BY_EXPORTER_EDIT, - ], + Case.objects.filter( + licences__generatedcasedocument__in=licence_documents, ) + .distinct() .order_by("-reference_code") ) From d400d7b2daf6954b6ff9bf22ba21b99f9c4ece30 Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Tue, 22 Oct 2024 19:01:34 +0100 Subject: [PATCH 66/86] Update licence list API view to be called licence decision --- api/data_workspace/v2/serializers.py | 26 ++++++++++++------------- api/data_workspace/v2/urls.py | 6 +++--- api/data_workspace/v2/views.py | 29 +++++++++++++--------------- 3 files changed, 29 insertions(+), 32 deletions(-) diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index c91bcc0132..97e1634d24 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -1,13 +1,18 @@ +from enum import Enum + from django.db.models import F from rest_framework import serializers -from api.cases.generated_documents.models import GeneratedCaseDocument from api.cases.models import Case -class CaseLicenceSerializer(serializers.ModelSerializer): +class LicenceDecisionType(str, Enum): + ISSUED = "issued" + + +class LicenceDecisionSerializer(serializers.ModelSerializer): decision = serializers.SerializerMethodField() - issued_date = serializers.SerializerMethodField() + decision_made_at = serializers.SerializerMethodField() class Meta: model = Case @@ -15,16 +20,11 @@ class Meta: "id", "reference_code", "decision", - "issued_date", + "decision_made_at", ) def get_decision(self, case): - return "issued" - - def get_issued_date(self, case): - return ( - case.licences.all() - .annotate(issued_at=F("generatedcasedocument__created_at")) - .earliest("issued_at") - .issued_at - ) + return LicenceDecisionType.ISSUED + + def get_decision_made_at(self, case): + return case.licences.annotate(issued_at=F("generatedcasedocument__created_at")).earliest("issued_at").issued_at diff --git a/api/data_workspace/v2/urls.py b/api/data_workspace/v2/urls.py index 11d4513512..27b94da8ee 100644 --- a/api/data_workspace/v2/urls.py +++ b/api/data_workspace/v2/urls.py @@ -6,7 +6,7 @@ router_v2 = DefaultRouter() router_v2.register( - "licences", - views.LicencesListView, - basename="dw-licences", + "licence-decisions", + views.LicenceDecisionListView, + basename="dw-licence-decisions", ) diff --git a/api/data_workspace/v2/views.py b/api/data_workspace/v2/views.py index d719d879a5..f9cd7eeac3 100644 --- a/api/data_workspace/v2/views.py +++ b/api/data_workspace/v2/views.py @@ -5,27 +5,24 @@ from rest_framework_csv.renderers import PaginatedCSVRenderer from api.cases.models import Case -from api.cases.generated_documents.models import GeneratedCaseDocument from api.core.authentication import DataWorkspaceOnlyAuthentication -from api.data_workspace.v2.serializers import CaseLicenceSerializer +from api.data_workspace.v2.serializers import LicenceDecisionSerializer + SIEL_TEMPLATE_ID = "d159b195-9256-4a00-9bc8-1eb2cebfa1d2" -class LicencesListView(viewsets.ReadOnlyModelViewSet): +class LicenceDecisionListView(viewsets.ReadOnlyModelViewSet): authentication_classes = (DataWorkspaceOnlyAuthentication,) pagination_class = LimitOffsetPagination - renderer_classes = tuple(api_settings.DEFAULT_RENDERER_CLASSES) + (PaginatedCSVRenderer,) - serializer_class = CaseLicenceSerializer - - def get_queryset(self): - licence_documents = GeneratedCaseDocument.objects.filter( - template_id=SIEL_TEMPLATE_ID, visible_to_exporter=True, safe=True - ) - return ( - Case.objects.filter( - licences__generatedcasedocument__in=licence_documents, - ) - .distinct() - .order_by("-reference_code") + queryset = ( + Case.objects.filter( + licences__generatedcasedocument__template_id=SIEL_TEMPLATE_ID, + licences__generatedcasedocument__visible_to_exporter=True, + licences__generatedcasedocument__safe=True, ) + .distinct() + .order_by("-reference_code") + ) + renderer_classes = tuple(api_settings.DEFAULT_RENDERER_CLASSES) + (PaginatedCSVRenderer,) + serializer_class = LicenceDecisionSerializer From b8ff494c5a10f5b9482dd7cdcacdf5e5af75cf29 Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Tue, 22 Oct 2024 19:31:09 +0100 Subject: [PATCH 67/86] Allow pagination to be disabled for licence decisions --- api/data_workspace/v2/urls.py | 2 +- api/data_workspace/v2/views.py | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/api/data_workspace/v2/urls.py b/api/data_workspace/v2/urls.py index 27b94da8ee..a8f6055a1a 100644 --- a/api/data_workspace/v2/urls.py +++ b/api/data_workspace/v2/urls.py @@ -7,6 +7,6 @@ router_v2.register( "licence-decisions", - views.LicenceDecisionListView, + views.LicenceDecisionViewSet, basename="dw-licence-decisions", ) diff --git a/api/data_workspace/v2/views.py b/api/data_workspace/v2/views.py index f9cd7eeac3..216e6f64b5 100644 --- a/api/data_workspace/v2/views.py +++ b/api/data_workspace/v2/views.py @@ -6,15 +6,24 @@ from api.cases.models import Case from api.core.authentication import DataWorkspaceOnlyAuthentication +from api.core.helpers import str_to_bool from api.data_workspace.v2.serializers import LicenceDecisionSerializer SIEL_TEMPLATE_ID = "d159b195-9256-4a00-9bc8-1eb2cebfa1d2" -class LicenceDecisionListView(viewsets.ReadOnlyModelViewSet): +class DisableableLimitOffsetPagination(LimitOffsetPagination): + def paginate_queryset(self, queryset, request, view=None): + if str_to_bool(request.GET.get("disable_pagination", False)): + return + + return super().paginate_queryset(queryset, request, view) + + +class LicenceDecisionViewSet(viewsets.ReadOnlyModelViewSet): authentication_classes = (DataWorkspaceOnlyAuthentication,) - pagination_class = LimitOffsetPagination + pagination_class = DisableableLimitOffsetPagination queryset = ( Case.objects.filter( licences__generatedcasedocument__template_id=SIEL_TEMPLATE_ID, From b99111188b5bc9917ef69cb6ace962bd0fb9518f Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Mon, 28 Oct 2024 12:20:08 +0000 Subject: [PATCH 68/86] Include refused cases in the extract Use the refusal letter generated date as the decision date --- api/data_workspace/v2/serializers.py | 13 ++++- api/data_workspace/v2/tests/bdd/conftest.py | 8 ++- .../v2/tests/bdd/licences/conftest.py | 8 +++ .../v2/tests/bdd/licences/test_licences.py | 56 ++++++++++++++++++- .../v2/tests/bdd/scenarios/licences.feature | 8 +++ api/data_workspace/v2/views.py | 29 ++++++---- 6 files changed, 106 insertions(+), 16 deletions(-) diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index 97e1634d24..bbd7bbd681 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -4,10 +4,15 @@ from rest_framework import serializers from api.cases.models import Case +from api.cases.generated_documents.models import GeneratedCaseDocument + +SIEL_TEMPLATE_ID = "d159b195-9256-4a00-9bc8-1eb2cebfa1d2" +SIEL_REFUSAL_TEMPLATE_ID = "074d8a54-ee10-4dca-82ba-650460650342" class LicenceDecisionType(str, Enum): ISSUED = "issued" + REFUSED = "refused" class LicenceDecisionSerializer(serializers.ModelSerializer): @@ -24,7 +29,13 @@ class Meta: ) def get_decision(self, case): - return LicenceDecisionType.ISSUED + if case.licences.count(): + return LicenceDecisionType.ISSUED + else: + return LicenceDecisionType.REFUSED def get_decision_made_at(self, case): + if not case.licences.count(): + return GeneratedCaseDocument.objects.get(case=case, template_id=SIEL_REFUSAL_TEMPLATE_ID).created_at + return case.licences.annotate(issued_at=F("generatedcasedocument__created_at")).earliest("issued_at").issued_at diff --git a/api/data_workspace/v2/tests/bdd/conftest.py b/api/data_workspace/v2/tests/bdd/conftest.py index d085eef4d0..83d021fada 100644 --- a/api/data_workspace/v2/tests/bdd/conftest.py +++ b/api/data_workspace/v2/tests/bdd/conftest.py @@ -1,10 +1,9 @@ -import csv import json import pytest from rest_framework import status -from api.cases.enums import CaseTypeEnum, CaseTypeSubTypeEnum +from api.cases.enums import CaseTypeEnum from api.cases.models import CaseType from api.core.constants import GovPermissions from api.letter_templates.models import LetterTemplate @@ -40,6 +39,11 @@ def siel_template(seed_templates): return LetterTemplate.objects.get(layout_id="00000000-0000-0000-0000-000000000001") +@pytest.fixture() +def siel_refusal_template(seed_templates): + return LetterTemplate.objects.get(layout_id="00000000-0000-0000-0000-000000000006") + + @pytest.fixture(autouse=True) def system_user(db): if BaseUser.objects.filter(id=SystemUser.id).exists(): diff --git a/api/data_workspace/v2/tests/bdd/licences/conftest.py b/api/data_workspace/v2/tests/bdd/licences/conftest.py index 1344850647..9473169247 100644 --- a/api/data_workspace/v2/tests/bdd/licences/conftest.py +++ b/api/data_workspace/v2/tests/bdd/licences/conftest.py @@ -1,6 +1,7 @@ import pytest from api.applications.tests.factories import GoodOnApplicationFactory, StandardApplicationFactory +from api.cases.enums import AdviceType from api.cases.tests.factories import FinalAdviceFactory from api.goods.tests.factories import GoodFactory from api.licences.enums import LicenceStatus @@ -63,3 +64,10 @@ def standard_case_with_final_advice(lu_case_officer): ) FinalAdviceFactory(user=lu_case_officer, case=case, good=good_on_application.good) return case + + + +@pytest.fixture() +def standard_case_with_refused_advice(lu_case_officer, standard_case_with_final_advice): + standard_case_with_final_advice.advice.update(type=AdviceType.REFUSE) + return standard_case_with_final_advice diff --git a/api/data_workspace/v2/tests/bdd/licences/test_licences.py b/api/data_workspace/v2/tests/bdd/licences/test_licences.py index c0860a5de3..455365301d 100644 --- a/api/data_workspace/v2/tests/bdd/licences/test_licences.py +++ b/api/data_workspace/v2/tests/bdd/licences/test_licences.py @@ -20,7 +20,7 @@ @pytest.fixture() def licences_list_url(): - return reverse("data_workspace:v2:dw-licences-list") + return reverse("data_workspace:v2:dw-licence-decisions-list") @given("a standard draft licence is created", target_fixture="draft_licence") @@ -58,12 +58,25 @@ def licence_included_in_extract(issued_licence, unpage_data, licences_list_url): assert issued_licence.reference_code in [item["reference_code"] for item in licences] +@then("the refused case is included in the extract") +def refused_case_included_in_extract(refused_case, unpage_data, licences_list_url): + licences = unpage_data(licences_list_url) + + assert refused_case.reference_code in [item["reference_code"] for item in licences] + + @given("a case is ready to be finalised", target_fixture="case_with_final_advice") def case_ready_to_be_finalised(standard_case_with_final_advice): assert standard_case_with_final_advice.status.status == CaseStatusEnum.UNDER_FINAL_REVIEW return standard_case_with_final_advice +@given("a case is ready to be refused", target_fixture="case_with_refused_advice") +def case_ready_to_be_refused(standard_case_with_refused_advice): + assert standard_case_with_refused_advice.status.status == CaseStatusEnum.UNDER_FINAL_REVIEW + return standard_case_with_refused_advice + + @when("the licence for the case is approved") def licence_for_case_is_approved(client, gov_headers, case_with_final_advice): data = {"action": AdviceType.APPROVE, "duration": 24} @@ -120,3 +133,44 @@ def licence_for_case_is_approved(client, gov_headers, case_with_final_advice): assert licence.status == LicenceStatus.ISSUED return licence + + +@when("the licence for the case is refused") +def licence_for_case_is_refused(client, gov_headers, case_with_refused_advice): + data = {"action": AdviceType.REFUSE} + + url = reverse("applications:finalise", kwargs={"pk": case_with_refused_advice.id}) + response = client.put(url, data, content_type="application/json", **gov_headers) + assert response.status_code == 200 + + +@when("case officer generates refusal documents") +def generate_refusal_documents(client, siel_refusal_template, gov_headers, case_with_refused_advice): + data = { + "template": str(siel_refusal_template.id), + "text": "", + "visible_to_exporter": False, + "advice_type": AdviceType.REFUSE, + } + url = reverse( + "cases:generated_documents:generated_documents", + kwargs={"pk": str(case_with_refused_advice.pk)}, + ) + response = client.post(url, data, content_type="application/json", **gov_headers) + assert response.status_code == 201 + + +@when("case officer refuses licence for this case", target_fixture="refused_case") +def licence_for_case_is_refused(client, gov_headers, case_with_refused_advice): + url = reverse( + "cases:finalise", + kwargs={"pk": str(case_with_refused_advice.pk)}, + ) + response = client.put(url, {}, content_type="application/json", **gov_headers) + assert response.status_code == 201 + + case_with_refused_advice.refresh_from_db() + assert case_with_refused_advice.status.status == CaseStatusEnum.FINALISED + assert case_with_refused_advice.sub_status.name == "Refused" + + return case_with_refused_advice diff --git a/api/data_workspace/v2/tests/bdd/scenarios/licences.feature b/api/data_workspace/v2/tests/bdd/scenarios/licences.feature index f9e5d80069..eff790c6e9 100644 --- a/api/data_workspace/v2/tests/bdd/scenarios/licences.feature +++ b/api/data_workspace/v2/tests/bdd/scenarios/licences.feature @@ -15,3 +15,11 @@ Scenario: Licence document is generated when licence is issued And case officer generates licence documents And case officer issues licence for this case Then the issued licence is included in the extract + +@refusal +Scenario: Refusal letter is generated when licence is refused + Given a case is ready to be refused + When the licence for the case is refused + And case officer generates refusal documents + And case officer refuses licence for this case + Then the refused case is included in the extract diff --git a/api/data_workspace/v2/views.py b/api/data_workspace/v2/views.py index 216e6f64b5..ae7d4857ac 100644 --- a/api/data_workspace/v2/views.py +++ b/api/data_workspace/v2/views.py @@ -4,13 +4,11 @@ from rest_framework_csv.renderers import PaginatedCSVRenderer +from api.cases.generated_documents.models import GeneratedCaseDocument from api.cases.models import Case from api.core.authentication import DataWorkspaceOnlyAuthentication from api.core.helpers import str_to_bool -from api.data_workspace.v2.serializers import LicenceDecisionSerializer - - -SIEL_TEMPLATE_ID = "d159b195-9256-4a00-9bc8-1eb2cebfa1d2" +from api.data_workspace.v2.serializers import SIEL_TEMPLATE_ID, SIEL_REFUSAL_TEMPLATE_ID, LicenceDecisionSerializer class DisableableLimitOffsetPagination(LimitOffsetPagination): @@ -24,14 +22,21 @@ def paginate_queryset(self, queryset, request, view=None): class LicenceDecisionViewSet(viewsets.ReadOnlyModelViewSet): authentication_classes = (DataWorkspaceOnlyAuthentication,) pagination_class = DisableableLimitOffsetPagination - queryset = ( - Case.objects.filter( - licences__generatedcasedocument__template_id=SIEL_TEMPLATE_ID, - licences__generatedcasedocument__visible_to_exporter=True, - licences__generatedcasedocument__safe=True, - ) - .distinct() - .order_by("-reference_code") + + issued_qs = Case.objects.filter( + licences__generatedcasedocument__template_id=SIEL_TEMPLATE_ID, + licences__generatedcasedocument__visible_to_exporter=True, + licences__generatedcasedocument__safe=True, ) + refused_qs = Case.objects.filter( + id__in=GeneratedCaseDocument.objects.filter( + template_id=SIEL_REFUSAL_TEMPLATE_ID, + visible_to_exporter=True, + safe=True, + ).values_list("case", flat=True) + ) + + queryset = (issued_qs | refused_qs).distinct().order_by("-reference_code") + renderer_classes = tuple(api_settings.DEFAULT_RENDERER_CLASSES) + (PaginatedCSVRenderer,) serializer_class = LicenceDecisionSerializer From 8eaaba38bcc64ba6f679174c4eacd66b9a730c1d Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Mon, 28 Oct 2024 14:33:02 +0000 Subject: [PATCH 69/86] Simplify query for getting cases with case documents --- api/data_workspace/v2/views.py | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/api/data_workspace/v2/views.py b/api/data_workspace/v2/views.py index ae7d4857ac..44540fb917 100644 --- a/api/data_workspace/v2/views.py +++ b/api/data_workspace/v2/views.py @@ -4,7 +4,6 @@ from rest_framework_csv.renderers import PaginatedCSVRenderer -from api.cases.generated_documents.models import GeneratedCaseDocument from api.cases.models import Case from api.core.authentication import DataWorkspaceOnlyAuthentication from api.core.helpers import str_to_bool @@ -23,20 +22,15 @@ class LicenceDecisionViewSet(viewsets.ReadOnlyModelViewSet): authentication_classes = (DataWorkspaceOnlyAuthentication,) pagination_class = DisableableLimitOffsetPagination - issued_qs = Case.objects.filter( - licences__generatedcasedocument__template_id=SIEL_TEMPLATE_ID, - licences__generatedcasedocument__visible_to_exporter=True, - licences__generatedcasedocument__safe=True, + queryset = ( + Case.objects.filter( + casedocument__generatedcasedocument__template_id__in=[SIEL_TEMPLATE_ID, SIEL_REFUSAL_TEMPLATE_ID], + casedocument__visible_to_exporter=True, + casedocument__safe=True, + ) + .distinct() + .order_by("-reference_code") ) - refused_qs = Case.objects.filter( - id__in=GeneratedCaseDocument.objects.filter( - template_id=SIEL_REFUSAL_TEMPLATE_ID, - visible_to_exporter=True, - safe=True, - ).values_list("case", flat=True) - ) - - queryset = (issued_qs | refused_qs).distinct().order_by("-reference_code") renderer_classes = tuple(api_settings.DEFAULT_RENDERER_CLASSES) + (PaginatedCSVRenderer,) serializer_class = LicenceDecisionSerializer From 14f8c3530cf2d689eee8b0d2df5d492de8ea22fe Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Mon, 28 Oct 2024 15:26:56 +0000 Subject: [PATCH 70/86] Determine issued and refused in queryset --- api/data_workspace/v2/serializers.py | 14 ++++++++------ api/data_workspace/v2/views.py | 22 ++++++++++++++++++++++ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index bbd7bbd681..6217b1f10a 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -29,13 +29,15 @@ class Meta: ) def get_decision(self, case): - if case.licences.count(): - return LicenceDecisionType.ISSUED - else: - return LicenceDecisionType.REFUSED + return case.decision def get_decision_made_at(self, case): - if not case.licences.count(): + if case.decision == "issued": + return ( + case.licences.annotate(issued_at=F("generatedcasedocument__created_at")).earliest("issued_at").issued_at + ) + + if case.decision == "refused": return GeneratedCaseDocument.objects.get(case=case, template_id=SIEL_REFUSAL_TEMPLATE_ID).created_at - return case.licences.annotate(issued_at=F("generatedcasedocument__created_at")).earliest("issued_at").issued_at + raise Exception("No decision found") diff --git a/api/data_workspace/v2/views.py b/api/data_workspace/v2/views.py index 44540fb917..7e5173830f 100644 --- a/api/data_workspace/v2/views.py +++ b/api/data_workspace/v2/views.py @@ -4,6 +4,16 @@ from rest_framework_csv.renderers import PaginatedCSVRenderer +from django.contrib.postgres.aggregates import ArrayAgg +from django.db.models import ( + Case as DBCase, + Q, + TextField, + Value, + When, +) +from django.db.models.functions import Cast + from api.cases.models import Case from api.core.authentication import DataWorkspaceOnlyAuthentication from api.core.helpers import str_to_bool @@ -28,6 +38,18 @@ class LicenceDecisionViewSet(viewsets.ReadOnlyModelViewSet): casedocument__visible_to_exporter=True, casedocument__safe=True, ) + .annotate( + template_ids=ArrayAgg( + Cast("casedocument__generatedcasedocument__template_id", output_field=TextField()), distinct=True + ) + ) + .filter(Q(template_ids=[SIEL_TEMPLATE_ID]) | Q(template_ids=[SIEL_REFUSAL_TEMPLATE_ID])) + .annotate( + decision=DBCase( + When(template_ids=[SIEL_TEMPLATE_ID], then=Value("issued")), + When(template_ids=[SIEL_REFUSAL_TEMPLATE_ID], then=Value("refused")), + ) + ) .distinct() .order_by("-reference_code") ) From af6786a15292a1df337039f1e40da39bc32c2dd9 Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Mon, 28 Oct 2024 19:58:45 +0000 Subject: [PATCH 71/86] Condense down logic for finding decision made at --- api/data_workspace/v2/serializers.py | 27 +++++++++++++++++---------- api/data_workspace/v2/views.py | 23 ++++++++++++++++++----- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index 6217b1f10a..a9d7ca379c 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -1,10 +1,8 @@ from enum import Enum -from django.db.models import F from rest_framework import serializers from api.cases.models import Case -from api.cases.generated_documents.models import GeneratedCaseDocument SIEL_TEMPLATE_ID = "d159b195-9256-4a00-9bc8-1eb2cebfa1d2" SIEL_REFUSAL_TEMPLATE_ID = "074d8a54-ee10-4dca-82ba-650460650342" @@ -14,6 +12,17 @@ class LicenceDecisionType(str, Enum): ISSUED = "issued" REFUSED = "refused" + @classmethod + def templates(cls): + return { + cls.ISSUED: SIEL_TEMPLATE_ID, + cls.REFUSED: SIEL_REFUSAL_TEMPLATE_ID, + } + + @classmethod + def get_template(cls, decision): + return cls.templates()[cls(decision)] + class LicenceDecisionSerializer(serializers.ModelSerializer): decision = serializers.SerializerMethodField() @@ -32,12 +41,10 @@ def get_decision(self, case): return case.decision def get_decision_made_at(self, case): - if case.decision == "issued": - return ( - case.licences.annotate(issued_at=F("generatedcasedocument__created_at")).earliest("issued_at").issued_at - ) - - if case.decision == "refused": - return GeneratedCaseDocument.objects.get(case=case, template_id=SIEL_REFUSAL_TEMPLATE_ID).created_at + documents = case.casedocument_set.filter( + generatedcasedocument__template_id=LicenceDecisionType.get_template(case.decision), + safe=True, + visible_to_exporter=True, + ) - raise Exception("No decision found") + return documents.earliest("created_at").created_at diff --git a/api/data_workspace/v2/views.py b/api/data_workspace/v2/views.py index 7e5173830f..0a3aa7dbf3 100644 --- a/api/data_workspace/v2/views.py +++ b/api/data_workspace/v2/views.py @@ -1,3 +1,6 @@ +import functools +import operator + from rest_framework import viewsets from rest_framework.pagination import LimitOffsetPagination from rest_framework.settings import api_settings @@ -17,7 +20,10 @@ from api.cases.models import Case from api.core.authentication import DataWorkspaceOnlyAuthentication from api.core.helpers import str_to_bool -from api.data_workspace.v2.serializers import SIEL_TEMPLATE_ID, SIEL_REFUSAL_TEMPLATE_ID, LicenceDecisionSerializer +from api.data_workspace.v2.serializers import ( + LicenceDecisionSerializer, + LicenceDecisionType, +) class DisableableLimitOffsetPagination(LimitOffsetPagination): @@ -34,7 +40,7 @@ class LicenceDecisionViewSet(viewsets.ReadOnlyModelViewSet): queryset = ( Case.objects.filter( - casedocument__generatedcasedocument__template_id__in=[SIEL_TEMPLATE_ID, SIEL_REFUSAL_TEMPLATE_ID], + casedocument__generatedcasedocument__template_id__in=LicenceDecisionType.templates().values(), casedocument__visible_to_exporter=True, casedocument__safe=True, ) @@ -43,11 +49,18 @@ class LicenceDecisionViewSet(viewsets.ReadOnlyModelViewSet): Cast("casedocument__generatedcasedocument__template_id", output_field=TextField()), distinct=True ) ) - .filter(Q(template_ids=[SIEL_TEMPLATE_ID]) | Q(template_ids=[SIEL_REFUSAL_TEMPLATE_ID])) + .filter( + functools.reduce( + operator.or_, + [Q(template_ids=[template_id]) for template_id in LicenceDecisionType.templates().values()], + ) + ) .annotate( decision=DBCase( - When(template_ids=[SIEL_TEMPLATE_ID], then=Value("issued")), - When(template_ids=[SIEL_REFUSAL_TEMPLATE_ID], then=Value("refused")), + *[ + When(template_ids=[template_id], then=Value(decision.value)) + for decision, template_id in LicenceDecisionType.templates().items() + ] ) ) .distinct() From 4606e7dfe043baf58fe02b9df720591952c25047 Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Tue, 29 Oct 2024 11:41:55 +0000 Subject: [PATCH 72/86] Temporarily skip hawk authentication --- api/core/authentication.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api/core/authentication.py b/api/core/authentication.py index 6f95857ed9..009f7ba6ba 100644 --- a/api/core/authentication.py +++ b/api/core/authentication.py @@ -180,6 +180,8 @@ def authenticate(self, request): Only approve HAWK Signed requests from the Data workspace """ + return AnonymousUser(), _ + try: hawk_receiver = _authenticate(request, _lookup_credentials_data_workspace_access) except HawkFail as e: From ad272b2a4e180cb1fccf80e4ef52896452f1c26b Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Tue, 29 Oct 2024 11:54:43 +0000 Subject: [PATCH 73/86] Fix DW authentication --- api/core/authentication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/core/authentication.py b/api/core/authentication.py index 009f7ba6ba..f9b95c8195 100644 --- a/api/core/authentication.py +++ b/api/core/authentication.py @@ -180,7 +180,7 @@ def authenticate(self, request): Only approve HAWK Signed requests from the Data workspace """ - return AnonymousUser(), _ + return AnonymousUser(), None try: hawk_receiver = _authenticate(request, _lookup_credentials_data_workspace_access) From bd525fb8c8e53c80f2f7378a194c685c4d54d287 Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Tue, 29 Oct 2024 14:04:06 +0000 Subject: [PATCH 74/86] Add revoked as a licence decision --- api/data_workspace/v2/serializers.py | 26 +++++++++--- api/data_workspace/v2/views.py | 62 ++++++++++++++++++---------- 2 files changed, 61 insertions(+), 27 deletions(-) diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index a9d7ca379c..812df52f1d 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -2,7 +2,10 @@ from rest_framework import serializers +from api.audit_trail.enums import AuditType +from api.audit_trail.models import Audit from api.cases.models import Case +from api.licences.enums import LicenceStatus SIEL_TEMPLATE_ID = "d159b195-9256-4a00-9bc8-1eb2cebfa1d2" SIEL_REFUSAL_TEMPLATE_ID = "074d8a54-ee10-4dca-82ba-650460650342" @@ -41,10 +44,21 @@ def get_decision(self, case): return case.decision def get_decision_made_at(self, case): - documents = case.casedocument_set.filter( - generatedcasedocument__template_id=LicenceDecisionType.get_template(case.decision), - safe=True, - visible_to_exporter=True, - ) + if case.decision in list(LicenceDecisionType): + documents = case.casedocument_set.filter( + generatedcasedocument__template_id=LicenceDecisionType.get_template(case.decision), + safe=True, + visible_to_exporter=True, + ) + return documents.earliest("created_at").created_at + + if case.decision == "revoked": + audits = Audit.objects.filter( + target_object_id=case.pk, + payload__status=LicenceStatus.REVOKED, + verb=AuditType.LICENCE_UPDATED_STATUS, + ) + + return audits.earliest("created_at").created_at - return documents.earliest("created_at").created_at + raise ValueError(f"Unknown decision type `{case.decision}`") diff --git a/api/data_workspace/v2/views.py b/api/data_workspace/v2/views.py index 0a3aa7dbf3..cc3fbc350c 100644 --- a/api/data_workspace/v2/views.py +++ b/api/data_workspace/v2/views.py @@ -8,6 +8,7 @@ from rest_framework_csv.renderers import PaginatedCSVRenderer from django.contrib.postgres.aggregates import ArrayAgg +from django.contrib.postgres.fields import ArrayField from django.db.models import ( Case as DBCase, Q, @@ -17,6 +18,8 @@ ) from django.db.models.functions import Cast +from api.audit_trail.enums import AuditType +from api.audit_trail.models import Audit from api.cases.models import Case from api.core.authentication import DataWorkspaceOnlyAuthentication from api.core.helpers import str_to_bool @@ -24,6 +27,7 @@ LicenceDecisionSerializer, LicenceDecisionType, ) +from api.licences.enums import LicenceStatus class DisableableLimitOffsetPagination(LimitOffsetPagination): @@ -39,31 +43,47 @@ class LicenceDecisionViewSet(viewsets.ReadOnlyModelViewSet): pagination_class = DisableableLimitOffsetPagination queryset = ( - Case.objects.filter( - casedocument__generatedcasedocument__template_id__in=LicenceDecisionType.templates().values(), - casedocument__visible_to_exporter=True, - casedocument__safe=True, - ) - .annotate( - template_ids=ArrayAgg( - Cast("casedocument__generatedcasedocument__template_id", output_field=TextField()), distinct=True + ( + Case.objects.filter( + casedocument__generatedcasedocument__template_id__in=LicenceDecisionType.templates().values(), + casedocument__visible_to_exporter=True, + casedocument__safe=True, ) - ) - .filter( - functools.reduce( - operator.or_, - [Q(template_ids=[template_id]) for template_id in LicenceDecisionType.templates().values()], + .annotate( + template_ids=ArrayAgg( + Cast("casedocument__generatedcasedocument__template_id", output_field=TextField()), distinct=True + ) ) - ) - .annotate( - decision=DBCase( - *[ - When(template_ids=[template_id], then=Value(decision.value)) - for decision, template_id in LicenceDecisionType.templates().items() - ] + .filter( + functools.reduce( + operator.or_, + [Q(template_ids=[template_id]) for template_id in LicenceDecisionType.templates().values()], + ) ) + .annotate( + decision=DBCase( + *[ + When(template_ids=[template_id], then=Value(decision.value)) + for decision, template_id in LicenceDecisionType.templates().items() + ] + ) + ) + .distinct() + ) + .union( + Case.objects.filter( + pk__in=list( + Audit.objects.filter( + payload__status=LicenceStatus.REVOKED, + verb=AuditType.LICENCE_UPDATED_STATUS, + ).values_list("target_object_id", flat=True) + ) + ).annotate( + template_ids=Value([], output_field=ArrayField(TextField())), + decision=Value("revoked", output_field=TextField()), + ), + all=True, ) - .distinct() .order_by("-reference_code") ) From 57b79cf22142b0443665875bae2b65626ddc091b Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Tue, 29 Oct 2024 16:38:14 +0000 Subject: [PATCH 75/86] Move into queryset --- api/data_workspace/v2/views.py | 86 +++++++++++++++++----------------- 1 file changed, 44 insertions(+), 42 deletions(-) diff --git a/api/data_workspace/v2/views.py b/api/data_workspace/v2/views.py index cc3fbc350c..3d6af863c2 100644 --- a/api/data_workspace/v2/views.py +++ b/api/data_workspace/v2/views.py @@ -41,51 +41,53 @@ def paginate_queryset(self, queryset, request, view=None): class LicenceDecisionViewSet(viewsets.ReadOnlyModelViewSet): authentication_classes = (DataWorkspaceOnlyAuthentication,) pagination_class = DisableableLimitOffsetPagination + renderer_classes = tuple(api_settings.DEFAULT_RENDERER_CLASSES) + (PaginatedCSVRenderer,) + serializer_class = LicenceDecisionSerializer - queryset = ( - ( - Case.objects.filter( - casedocument__generatedcasedocument__template_id__in=LicenceDecisionType.templates().values(), - casedocument__visible_to_exporter=True, - casedocument__safe=True, - ) - .annotate( - template_ids=ArrayAgg( - Cast("casedocument__generatedcasedocument__template_id", output_field=TextField()), distinct=True + def get_queryset(self): + queryset = ( + ( + Case.objects.filter( + casedocument__generatedcasedocument__template_id__in=LicenceDecisionType.templates().values(), + casedocument__visible_to_exporter=True, + casedocument__safe=True, ) - ) - .filter( - functools.reduce( - operator.or_, - [Q(template_ids=[template_id]) for template_id in LicenceDecisionType.templates().values()], + .annotate( + template_ids=ArrayAgg( + Cast("casedocument__generatedcasedocument__template_id", output_field=TextField()), + distinct=True, + ) ) - ) - .annotate( - decision=DBCase( - *[ - When(template_ids=[template_id], then=Value(decision.value)) - for decision, template_id in LicenceDecisionType.templates().items() - ] + .filter( + functools.reduce( + operator.or_, + [Q(template_ids=[template_id]) for template_id in LicenceDecisionType.templates().values()], + ) ) - ) - .distinct() - ) - .union( - Case.objects.filter( - pk__in=list( - Audit.objects.filter( - payload__status=LicenceStatus.REVOKED, - verb=AuditType.LICENCE_UPDATED_STATUS, - ).values_list("target_object_id", flat=True) + .annotate( + decision=DBCase( + *[ + When(template_ids=[template_id], then=Value(decision.value)) + for decision, template_id in LicenceDecisionType.templates().items() + ] + ) ) - ).annotate( - template_ids=Value([], output_field=ArrayField(TextField())), - decision=Value("revoked", output_field=TextField()), - ), - all=True, + .distinct() + ) + .union( + Case.objects.filter( + pk__in=list( + Audit.objects.filter( + payload__status=LicenceStatus.REVOKED, + verb=AuditType.LICENCE_UPDATED_STATUS, + ).values_list("target_object_id", flat=True) + ) + ).annotate( + template_ids=Value([], output_field=ArrayField(TextField())), + decision=Value("revoked", output_field=TextField()), + ), + all=True, + ) + .order_by("-reference_code") ) - .order_by("-reference_code") - ) - - renderer_classes = tuple(api_settings.DEFAULT_RENDERER_CLASSES) + (PaginatedCSVRenderer,) - serializer_class = LicenceDecisionSerializer + return queryset From d44063d7ad5e68463d0f04aad9dcae4f6217b45f Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Thu, 31 Oct 2024 12:57:46 +0000 Subject: [PATCH 76/86] Add new endpoint to export licence decisions from the model --- api/cases/enums.py | 4 +++ api/data_workspace/v2/serializers.py | 50 +++++++++++++++++----------- api/data_workspace/v2/urls.py | 6 ++++ api/data_workspace/v2/views.py | 40 ++++++++++++++++++++-- 4 files changed, 79 insertions(+), 21 deletions(-) diff --git a/api/cases/enums.py b/api/cases/enums.py index 6d21e6407c..40915d77b9 100644 --- a/api/cases/enums.py +++ b/api/cases/enums.py @@ -429,6 +429,10 @@ class LicenceDecisionType: AdviceType.REFUSE: REFUSED, } + @classmethod + def decisions(cls): + return [d[0] for d in cls.choices] + @classmethod def templates(cls): return { diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index 812df52f1d..eaa910b656 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -1,9 +1,8 @@ -from enum import Enum - from rest_framework import serializers from api.audit_trail.enums import AuditType from api.audit_trail.models import Audit +from api.cases.enums import LicenceDecisionType from api.cases.models import Case from api.licences.enums import LicenceStatus @@ -11,23 +10,7 @@ SIEL_REFUSAL_TEMPLATE_ID = "074d8a54-ee10-4dca-82ba-650460650342" -class LicenceDecisionType(str, Enum): - ISSUED = "issued" - REFUSED = "refused" - - @classmethod - def templates(cls): - return { - cls.ISSUED: SIEL_TEMPLATE_ID, - cls.REFUSED: SIEL_REFUSAL_TEMPLATE_ID, - } - - @classmethod - def get_template(cls, decision): - return cls.templates()[cls(decision)] - - -class LicenceDecisionSerializer(serializers.ModelSerializer): +class LicenceDecisionDerivedSerializer(serializers.ModelSerializer): decision = serializers.SerializerMethodField() decision_made_at = serializers.SerializerMethodField() @@ -62,3 +45,32 @@ def get_decision_made_at(self, case): return audits.earliest("created_at").created_at raise ValueError(f"Unknown decision type `{case.decision}`") + + +class LicenceDecisionSerializer(serializers.ModelSerializer): + decision = serializers.SerializerMethodField() + decision_made_at = serializers.SerializerMethodField() + + class Meta: + model = Case + fields = ( + "id", + "reference_code", + "decision", + "decision_made_at", + ) + + def get_decision(self, case): + return case.decision + + def get_decision_made_at(self, case): + if case.decision not in LicenceDecisionType.decisions(): + raise ValueError(f"Unknown decision type `{case.decision}`") + + return ( + case.licence_decisions.filter( + decision=case.decision, + ) + .earliest("created_at") + .created_at + ) diff --git a/api/data_workspace/v2/urls.py b/api/data_workspace/v2/urls.py index a8f6055a1a..f42c204588 100644 --- a/api/data_workspace/v2/urls.py +++ b/api/data_workspace/v2/urls.py @@ -5,6 +5,12 @@ router_v2 = DefaultRouter() +router_v2.register( + "licence-decisions-derived", + views.LicenceDecisionDerivedViewSet, + basename="dw-licence-decisions-derived", +) + router_v2.register( "licence-decisions", views.LicenceDecisionViewSet, diff --git a/api/data_workspace/v2/views.py b/api/data_workspace/v2/views.py index 3d6af863c2..8ea2394b3d 100644 --- a/api/data_workspace/v2/views.py +++ b/api/data_workspace/v2/views.py @@ -11,6 +11,7 @@ from django.contrib.postgres.fields import ArrayField from django.db.models import ( Case as DBCase, + F, Q, TextField, Value, @@ -24,6 +25,7 @@ from api.core.authentication import DataWorkspaceOnlyAuthentication from api.core.helpers import str_to_bool from api.data_workspace.v2.serializers import ( + LicenceDecisionDerivedSerializer, LicenceDecisionSerializer, LicenceDecisionType, ) @@ -38,11 +40,11 @@ def paginate_queryset(self, queryset, request, view=None): return super().paginate_queryset(queryset, request, view) -class LicenceDecisionViewSet(viewsets.ReadOnlyModelViewSet): +class LicenceDecisionDerivedViewSet(viewsets.ReadOnlyModelViewSet): authentication_classes = (DataWorkspaceOnlyAuthentication,) pagination_class = DisableableLimitOffsetPagination renderer_classes = tuple(api_settings.DEFAULT_RENDERER_CLASSES) + (PaginatedCSVRenderer,) - serializer_class = LicenceDecisionSerializer + serializer_class = LicenceDecisionDerivedSerializer def get_queryset(self): queryset = ( @@ -91,3 +93,37 @@ def get_queryset(self): .order_by("-reference_code") ) return queryset + + +class LicenceDecisionViewSet(viewsets.ReadOnlyModelViewSet): + authentication_classes = (DataWorkspaceOnlyAuthentication,) + pagination_class = DisableableLimitOffsetPagination + renderer_classes = tuple(api_settings.DEFAULT_RENDERER_CLASSES) + (PaginatedCSVRenderer,) + serializer_class = LicenceDecisionSerializer + + def get_queryset(self): + queryset = ( + ( + Case.objects.filter( + licence_decisions__decision__in=[LicenceDecisionType.ISSUED, LicenceDecisionType.REFUSED], + ) + .annotate( + unique_decisions=ArrayAgg("licence_decisions__decision", distinct=True), + ) + .filter(unique_decisions__len=1) + .annotate(decision=F("unique_decisions__0")) + ) + .union( + Case.objects.filter( + licence_decisions__decision__in=[LicenceDecisionType.REVOKED], + ) + .annotate( + unique_decisions=ArrayAgg("licence_decisions__decision", distinct=True), + ) + .filter(unique_decisions__len=1) + .annotate(decision=F("unique_decisions__0")), + all=True, + ) + .order_by("-reference_code") + ) + return queryset From 362111da7d3f38357cb920f8d2178354bcf58654 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Thu, 7 Nov 2024 16:07:02 +0000 Subject: [PATCH 77/86] Remove unused licence decisions endpoint We now have LicenceDecision model so we can generate the extract using those instances instead of deriving from other models. --- api/data_workspace/v2/serializers.py | 43 ---------------- api/data_workspace/v2/urls.py | 6 --- api/data_workspace/v2/views.py | 74 +--------------------------- 3 files changed, 1 insertion(+), 122 deletions(-) diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index eaa910b656..182111247d 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -1,50 +1,7 @@ from rest_framework import serializers -from api.audit_trail.enums import AuditType -from api.audit_trail.models import Audit from api.cases.enums import LicenceDecisionType from api.cases.models import Case -from api.licences.enums import LicenceStatus - -SIEL_TEMPLATE_ID = "d159b195-9256-4a00-9bc8-1eb2cebfa1d2" -SIEL_REFUSAL_TEMPLATE_ID = "074d8a54-ee10-4dca-82ba-650460650342" - - -class LicenceDecisionDerivedSerializer(serializers.ModelSerializer): - decision = serializers.SerializerMethodField() - decision_made_at = serializers.SerializerMethodField() - - class Meta: - model = Case - fields = ( - "id", - "reference_code", - "decision", - "decision_made_at", - ) - - def get_decision(self, case): - return case.decision - - def get_decision_made_at(self, case): - if case.decision in list(LicenceDecisionType): - documents = case.casedocument_set.filter( - generatedcasedocument__template_id=LicenceDecisionType.get_template(case.decision), - safe=True, - visible_to_exporter=True, - ) - return documents.earliest("created_at").created_at - - if case.decision == "revoked": - audits = Audit.objects.filter( - target_object_id=case.pk, - payload__status=LicenceStatus.REVOKED, - verb=AuditType.LICENCE_UPDATED_STATUS, - ) - - return audits.earliest("created_at").created_at - - raise ValueError(f"Unknown decision type `{case.decision}`") class LicenceDecisionSerializer(serializers.ModelSerializer): diff --git a/api/data_workspace/v2/urls.py b/api/data_workspace/v2/urls.py index f42c204588..a8f6055a1a 100644 --- a/api/data_workspace/v2/urls.py +++ b/api/data_workspace/v2/urls.py @@ -5,12 +5,6 @@ router_v2 = DefaultRouter() -router_v2.register( - "licence-decisions-derived", - views.LicenceDecisionDerivedViewSet, - basename="dw-licence-decisions-derived", -) - router_v2.register( "licence-decisions", views.LicenceDecisionViewSet, diff --git a/api/data_workspace/v2/views.py b/api/data_workspace/v2/views.py index 8ea2394b3d..8a4973a97b 100644 --- a/api/data_workspace/v2/views.py +++ b/api/data_workspace/v2/views.py @@ -1,6 +1,3 @@ -import functools -import operator - from rest_framework import viewsets from rest_framework.pagination import LimitOffsetPagination from rest_framework.settings import api_settings @@ -8,28 +5,14 @@ from rest_framework_csv.renderers import PaginatedCSVRenderer from django.contrib.postgres.aggregates import ArrayAgg -from django.contrib.postgres.fields import ArrayField -from django.db.models import ( - Case as DBCase, - F, - Q, - TextField, - Value, - When, -) -from django.db.models.functions import Cast - -from api.audit_trail.enums import AuditType -from api.audit_trail.models import Audit +from django.db.models import F from api.cases.models import Case from api.core.authentication import DataWorkspaceOnlyAuthentication from api.core.helpers import str_to_bool from api.data_workspace.v2.serializers import ( - LicenceDecisionDerivedSerializer, LicenceDecisionSerializer, LicenceDecisionType, ) -from api.licences.enums import LicenceStatus class DisableableLimitOffsetPagination(LimitOffsetPagination): @@ -40,61 +23,6 @@ def paginate_queryset(self, queryset, request, view=None): return super().paginate_queryset(queryset, request, view) -class LicenceDecisionDerivedViewSet(viewsets.ReadOnlyModelViewSet): - authentication_classes = (DataWorkspaceOnlyAuthentication,) - pagination_class = DisableableLimitOffsetPagination - renderer_classes = tuple(api_settings.DEFAULT_RENDERER_CLASSES) + (PaginatedCSVRenderer,) - serializer_class = LicenceDecisionDerivedSerializer - - def get_queryset(self): - queryset = ( - ( - Case.objects.filter( - casedocument__generatedcasedocument__template_id__in=LicenceDecisionType.templates().values(), - casedocument__visible_to_exporter=True, - casedocument__safe=True, - ) - .annotate( - template_ids=ArrayAgg( - Cast("casedocument__generatedcasedocument__template_id", output_field=TextField()), - distinct=True, - ) - ) - .filter( - functools.reduce( - operator.or_, - [Q(template_ids=[template_id]) for template_id in LicenceDecisionType.templates().values()], - ) - ) - .annotate( - decision=DBCase( - *[ - When(template_ids=[template_id], then=Value(decision.value)) - for decision, template_id in LicenceDecisionType.templates().items() - ] - ) - ) - .distinct() - ) - .union( - Case.objects.filter( - pk__in=list( - Audit.objects.filter( - payload__status=LicenceStatus.REVOKED, - verb=AuditType.LICENCE_UPDATED_STATUS, - ).values_list("target_object_id", flat=True) - ) - ).annotate( - template_ids=Value([], output_field=ArrayField(TextField())), - decision=Value("revoked", output_field=TextField()), - ), - all=True, - ) - .order_by("-reference_code") - ) - return queryset - - class LicenceDecisionViewSet(viewsets.ReadOnlyModelViewSet): authentication_classes = (DataWorkspaceOnlyAuthentication,) pagination_class = DisableableLimitOffsetPagination From 5b48596e3a72b77b0a0569f63a48f859b7d86b49 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Mon, 11 Nov 2024 22:30:10 +0000 Subject: [PATCH 78/86] Update DW bdd tests to check for revoked licence decision --- api/data_workspace/v2/tests/bdd/conftest.py | 24 +++++- ..._licences.py => test_licence_decisions.py} | 74 +++++++++++++++---- .../bdd/scenarios/licence_decisions.feature | 36 +++++++++ .../v2/tests/bdd/scenarios/licences.feature | 25 ------- 4 files changed, 118 insertions(+), 41 deletions(-) rename api/data_workspace/v2/tests/bdd/licences/{test_licences.py => test_licence_decisions.py} (71%) create mode 100644 api/data_workspace/v2/tests/bdd/scenarios/licence_decisions.feature delete mode 100644 api/data_workspace/v2/tests/bdd/scenarios/licences.feature diff --git a/api/data_workspace/v2/tests/bdd/conftest.py b/api/data_workspace/v2/tests/bdd/conftest.py index 83d021fada..4fc9d92b02 100644 --- a/api/data_workspace/v2/tests/bdd/conftest.py +++ b/api/data_workspace/v2/tests/bdd/conftest.py @@ -5,7 +5,7 @@ from api.cases.enums import CaseTypeEnum from api.cases.models import CaseType -from api.core.constants import GovPermissions +from api.core.constants import GovPermissions, Roles from api.letter_templates.models import LetterTemplate from api.staticdata.letter_layouts.models import LetterLayout from api.users.libraries.user_to_token import user_to_token @@ -57,6 +57,11 @@ def gov_user(): return GovUserFactory() +@pytest.fixture() +def lu_user(): + return GovUserFactory() + + @pytest.fixture() def gov_user_permissions(): for permission in GovPermissions: @@ -73,11 +78,28 @@ def lu_case_officer(gov_user, gov_user_permissions): return gov_user +@pytest.fixture() +def lu_senior_manager(lu_user, gov_user_permissions): + lu_user.role = RoleFactory( + id=Roles.INTERNAL_LU_SENIOR_MANAGER_ROLE_ID, name="LU Senior Manager", type=UserType.INTERNAL + ) + lu_user.role.permissions.set( + [GovPermissions.MANAGE_LICENCE_FINAL_ADVICE.name, GovPermissions.MANAGE_LICENCE_DURATION.name] + ) + lu_user.save() + return lu_user + + @pytest.fixture() def gov_headers(gov_user): return {"HTTP_GOV_USER_TOKEN": user_to_token(gov_user.baseuser_ptr)} +@pytest.fixture() +def lu_sr_manager_headers(lu_senior_manager): + return {"HTTP_GOV_USER_TOKEN": user_to_token(lu_senior_manager.baseuser_ptr)} + + @pytest.fixture() def unpage_data(client): def _unpage_data(url): diff --git a/api/data_workspace/v2/tests/bdd/licences/test_licences.py b/api/data_workspace/v2/tests/bdd/licences/test_licence_decisions.py similarity index 71% rename from api/data_workspace/v2/tests/bdd/licences/test_licences.py rename to api/data_workspace/v2/tests/bdd/licences/test_licence_decisions.py index 455365301d..827feefe40 100644 --- a/api/data_workspace/v2/tests/bdd/licences/test_licences.py +++ b/api/data_workspace/v2/tests/bdd/licences/test_licence_decisions.py @@ -9,20 +9,26 @@ scenarios, ) -from api.cases.enums import AdviceType +from api.cases.enums import AdviceType, LicenceDecisionType +from api.cases.models import LicenceDecision from api.licences.enums import LicenceStatus from api.licences.models import Licence from api.staticdata.statuses.enums import CaseStatusEnum -scenarios("../scenarios/licences.feature") +scenarios("../scenarios/licence_decisions.feature") @pytest.fixture() -def licences_list_url(): +def licence_decisions_list_url(): return reverse("data_workspace:v2:dw-licence-decisions-list") +@when("I fetch all licence decisions", target_fixture="licence_decisions") +def fetch_licence_decisions(licence_decisions_list_url, unpage_data): + return unpage_data(licence_decisions_list_url) + + @given("a standard draft licence is created", target_fixture="draft_licence") def standard_draft_licence_created(standard_draft_licence): assert standard_draft_licence.status == LicenceStatus.DRAFT @@ -30,8 +36,8 @@ def standard_draft_licence_created(standard_draft_licence): @then("the draft licence is not included in the extract") -def draft_licence_not_included_in_extract(draft_licence, unpage_data, licences_list_url): - licences = unpage_data(licences_list_url) +def draft_licence_not_included_in_extract(draft_licence, unpage_data, licence_decisions_list_url): + licences = unpage_data(licence_decisions_list_url) assert draft_licence.reference_code not in [item["reference_code"] for item in licences] @@ -45,22 +51,22 @@ def standard_licence_is_cancelled(standard_licence): @then("the cancelled licence is not included in the extract") -def cancelled_licence_not_included_in_extract(cancelled_licence, unpage_data, licences_list_url): - licences = unpage_data(licences_list_url) +def cancelled_licence_not_included_in_extract(cancelled_licence, unpage_data, licence_decisions_list_url): + licences = unpage_data(licence_decisions_list_url) assert cancelled_licence.reference_code not in [item["reference_code"] for item in licences] -@then("the issued licence is included in the extract") -def licence_included_in_extract(issued_licence, unpage_data, licences_list_url): - licences = unpage_data(licences_list_url) +@then("I see issued licence is included in the extract") +def licence_included_in_extract(issued_licence, unpage_data, licence_decisions_list_url): + licences = unpage_data(licence_decisions_list_url) assert issued_licence.reference_code in [item["reference_code"] for item in licences] -@then("the refused case is included in the extract") -def refused_case_included_in_extract(refused_case, unpage_data, licences_list_url): - licences = unpage_data(licences_list_url) +@then("I see refused case is included in the extract") +def refused_case_included_in_extract(refused_case, unpage_data, licence_decisions_list_url): + licences = unpage_data(licence_decisions_list_url) assert refused_case.reference_code in [item["reference_code"] for item in licences] @@ -98,7 +104,7 @@ def licence_for_case_is_approved(client, gov_headers, case_with_final_advice): @when("case officer generates licence documents") -def licence_for_case_is_approved(client, siel_template, gov_headers, case_with_final_advice): +def case_officer_generates_licence_documents(client, siel_template, gov_headers, case_with_final_advice): data = { "template": str(siel_template.id), "text": "", @@ -114,7 +120,7 @@ def licence_for_case_is_approved(client, siel_template, gov_headers, case_with_f @when("case officer issues licence for this case", target_fixture="issued_licence") -def licence_for_case_is_approved(client, gov_headers, case_with_final_advice): +def case_officer_issues_licence(client, gov_headers, case_with_final_advice): url = reverse( "cases:finalise", kwargs={"pk": str(case_with_final_advice.pk)}, @@ -132,6 +138,11 @@ def licence_for_case_is_approved(client, gov_headers, case_with_final_advice): licence = Licence.objects.get(id=response["licence"]) assert licence.status == LicenceStatus.ISSUED + assert LicenceDecision.objects.filter( + case=case_with_final_advice, + decision=LicenceDecisionType.ISSUED, + ).exists() + return licence @@ -173,4 +184,37 @@ def licence_for_case_is_refused(client, gov_headers, case_with_refused_advice): assert case_with_refused_advice.status.status == CaseStatusEnum.FINALISED assert case_with_refused_advice.sub_status.name == "Refused" + assert LicenceDecision.objects.filter( + case=case_with_refused_advice, + decision=LicenceDecisionType.REFUSED, + ).exists() + return case_with_refused_advice + + +@when("case officer revokes issued licence", target_fixture="revoked_licence") +def case_officer_revokes_licence(client, lu_sr_manager_headers, issued_licence): + url = reverse( + "licences:licence_details", + kwargs={"pk": str(issued_licence.pk)} + ) + response = client.patch( + url, {"status": LicenceStatus.REVOKED}, content_type="application/json", **lu_sr_manager_headers + ) + assert response.status_code == 200 + + assert LicenceDecision.objects.filter( + case=issued_licence.case, + decision=LicenceDecisionType.REVOKED, + ).exists() + + issued_licence.refresh_from_db() + return issued_licence + + +@then("I see revoked licence is included in the extract") +def revoked_licence_decision_included_in_extract(licence_decisions, revoked_licence): + + all_revoked_licences = [item for item in licence_decisions if item["decision"] == "revoked"] + + assert revoked_licence.case.reference_code in [item["reference_code"] for item in all_revoked_licences] diff --git a/api/data_workspace/v2/tests/bdd/scenarios/licence_decisions.feature b/api/data_workspace/v2/tests/bdd/scenarios/licence_decisions.feature new file mode 100644 index 0000000000..a283968a30 --- /dev/null +++ b/api/data_workspace/v2/tests/bdd/scenarios/licence_decisions.feature @@ -0,0 +1,36 @@ +@db +Feature: Licence Decisions + +Scenario: Check that draft licences are not included in the extract + Given a standard draft licence is created + Then the draft licence is not included in the extract + +Scenario: Check that cancelled licences are not included in the extract + Given a standard licence is cancelled + Then the cancelled licence is not included in the extract + +Scenario: Issued licence decision is created when licence is issued + Given a case is ready to be finalised + When the licence for the case is approved + And case officer generates licence documents + And case officer issues licence for this case + When I fetch all licence decisions + Then I see issued licence is included in the extract + +Scenario: Refused licence decision is created when licence is refused + Given a case is ready to be refused + When the licence for the case is refused + And case officer generates refusal documents + And case officer refuses licence for this case + When I fetch all licence decisions + Then I see refused case is included in the extract + +Scenario: Revoked licence decision is created when licence is revoked + Given a case is ready to be finalised + When the licence for the case is approved + And case officer generates licence documents + And case officer issues licence for this case + Then I see issued licence is included in the extract + When case officer revokes issued licence + And I fetch all licence decisions + Then I see revoked licence is included in the extract diff --git a/api/data_workspace/v2/tests/bdd/scenarios/licences.feature b/api/data_workspace/v2/tests/bdd/scenarios/licences.feature deleted file mode 100644 index eff790c6e9..0000000000 --- a/api/data_workspace/v2/tests/bdd/scenarios/licences.feature +++ /dev/null @@ -1,25 +0,0 @@ -@db -Feature: Licences - -Scenario: Check that draft licences are not included in the extract - Given a standard draft licence is created - Then the draft licence is not included in the extract - -Scenario: Check that cancelled licences are not included in the extract - Given a standard licence is cancelled - Then the cancelled licence is not included in the extract - -Scenario: Licence document is generated when licence is issued - Given a case is ready to be finalised - When the licence for the case is approved - And case officer generates licence documents - And case officer issues licence for this case - Then the issued licence is included in the extract - -@refusal -Scenario: Refusal letter is generated when licence is refused - Given a case is ready to be refused - When the licence for the case is refused - And case officer generates refusal documents - And case officer refuses licence for this case - Then the refused case is included in the extract From 65799776cbef9de8560e5626b512026951da251a Mon Sep 17 00:00:00 2001 From: "mark.j0hnst0n" Date: Tue, 12 Nov 2024 09:18:18 +0000 Subject: [PATCH 79/86] change to account for csv adding extra backslash on new address when saving --- .../management/commands/update_party_address.py | 2 +- api/applications/tests/test_update_parties_address.py | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/api/applications/management/commands/update_party_address.py b/api/applications/management/commands/update_party_address.py index 0f76a978a9..8ac041decc 100644 --- a/api/applications/management/commands/update_party_address.py +++ b/api/applications/management/commands/update_party_address.py @@ -20,7 +20,7 @@ def handle(self, *args, **kwargs): for row in reader: party_id = row["party_id"] address = row["address"].replace("\\r\\n", "\r\n") - new_address = row["new_address"] + new_address = row["new_address"].replace("\\r\\n", "\r\n") additional_text = row["additional_text"] self.update_field_on_party(party_id, address, new_address, additional_text, audit_log) diff --git a/api/applications/tests/test_update_parties_address.py b/api/applications/tests/test_update_parties_address.py index e29a5e60ab..5d74dc1381 100644 --- a/api/applications/tests/test_update_parties_address.py +++ b/api/applications/tests/test_update_parties_address.py @@ -14,8 +14,9 @@ def setUp(self): def test_update_field_on_party_from_csv(self): - new_address = "56 Heathwood Road Broadstairs Kent" + new_address = "56 Heathwood Road\\r\\n Broadstairs Kent" old_address = self.standard_application.end_user.party.address + result = "56 Heathwood Road\r\n Broadstairs Kent" party_id = self.standard_application.end_user.party.id with NamedTemporaryFile(suffix=".csv", delete=True) as tmp_file: @@ -28,7 +29,7 @@ def test_update_field_on_party_from_csv(self): call_command("update_party_address", tmp_file.name) self.standard_application.refresh_from_db() - self.assertEqual(self.standard_application.end_user.party.address, new_address) + self.assertEqual(self.standard_application.end_user.party.address, result) audit = Audit.objects.get() @@ -38,7 +39,7 @@ def test_update_field_on_party_from_csv(self): self.assertEqual( audit.payload, { - "address": {"new": new_address, "old": old_address}, + "address": {"new": result, "old": old_address}, "additional_text": "added by John Smith as per LTD-XXX", }, ) From fa5295a9465e55cf45097a3ceabc3a7995912dbf Mon Sep 17 00:00:00 2001 From: "mark.j0hnst0n" Date: Tue, 12 Nov 2024 09:18:35 +0000 Subject: [PATCH 80/86] change to account for csv adding extra backslash on new name when saving --- api/applications/management/commands/update_party_name.py | 2 +- api/applications/tests/test_update_party_name.py | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/api/applications/management/commands/update_party_name.py b/api/applications/management/commands/update_party_name.py index 99b178dfc6..53af606612 100644 --- a/api/applications/management/commands/update_party_name.py +++ b/api/applications/management/commands/update_party_name.py @@ -21,7 +21,7 @@ def handle(self, *args, **kwargs): for row in reader: party_id = row["party_id"] name = row["name"].replace("\\r\\n", "\r\n") - new_name = row["new_name"] + new_name = row["new_name"].replace("\\r\\n", "\r\n") additional_text = row["additional_text"] self.update_field_on_party(party_id, name, new_name, additional_text) diff --git a/api/applications/tests/test_update_party_name.py b/api/applications/tests/test_update_party_name.py index 4e050a300f..f1b35b426d 100644 --- a/api/applications/tests/test_update_party_name.py +++ b/api/applications/tests/test_update_party_name.py @@ -14,9 +14,10 @@ def setUp(self): def test_update_field_on_party_from_csv(self): - new_name = "Bangarang 3000" + new_name = "Bangarang 3000\\r\\n Skrilly" old_name = self.standard_application.end_user.party.name party_id = self.standard_application.end_user.party.id + result = "Bangarang 3000\r\n Skrilly" with NamedTemporaryFile(suffix=".csv", delete=True) as tmp_file: rows = [ @@ -28,7 +29,7 @@ def test_update_field_on_party_from_csv(self): call_command("update_party_name", tmp_file.name) self.standard_application.refresh_from_db() - self.assertEqual(self.standard_application.end_user.party.name, new_name) + self.assertEqual(self.standard_application.end_user.party.name, result) audit = Audit.objects.get() @@ -38,7 +39,7 @@ def test_update_field_on_party_from_csv(self): self.assertEqual( audit.payload, { - "name": {"new": new_name, "old": old_name}, + "name": {"new": result, "old": old_name}, "additional_text": "added by John Smith as per LTD-XXX", }, ) From daf4508e950d4dc4f242582f958a8dd1b711e929 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Tue, 12 Nov 2024 12:02:47 +0000 Subject: [PATCH 81/86] Fix linter error and failing tests --- api/core/authentication.py | 2 -- api/data_workspace/v2/tests/bdd/conftest.py | 6 +++++- api/data_workspace/v2/tests/bdd/licences/conftest.py | 1 - .../v2/tests/bdd/licences/test_licence_decisions.py | 5 +---- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/api/core/authentication.py b/api/core/authentication.py index f9b95c8195..6f95857ed9 100644 --- a/api/core/authentication.py +++ b/api/core/authentication.py @@ -180,8 +180,6 @@ def authenticate(self, request): Only approve HAWK Signed requests from the Data workspace """ - return AnonymousUser(), None - try: hawk_receiver = _authenticate(request, _lookup_credentials_data_workspace_access) except HawkFail as e: diff --git a/api/data_workspace/v2/tests/bdd/conftest.py b/api/data_workspace/v2/tests/bdd/conftest.py index 4fc9d92b02..2e255702de 100644 --- a/api/data_workspace/v2/tests/bdd/conftest.py +++ b/api/data_workspace/v2/tests/bdd/conftest.py @@ -28,6 +28,10 @@ def seed_layouts(): @pytest.fixture() def seed_templates(seed_layouts): + # if this template exists the seed command is executed and all templates are seeded + if LetterTemplate.objects.filter(name="SIEL template").exists(): + return + templates = load_json("api/data_workspace/v2/tests/bdd/initial_data/letter_templates.json") for template in templates: template_instance, _ = LetterTemplate.objects.get_or_create(**template) @@ -65,7 +69,7 @@ def lu_user(): @pytest.fixture() def gov_user_permissions(): for permission in GovPermissions: - Permission.objects.get_or_create(id=permission.name, name=permission.name, type=UserType.INTERNAL) + Permission.objects.get_or_create(id=permission.name, name=permission.value, type=UserType.INTERNAL.value) @pytest.fixture() diff --git a/api/data_workspace/v2/tests/bdd/licences/conftest.py b/api/data_workspace/v2/tests/bdd/licences/conftest.py index 9473169247..91fa28de4c 100644 --- a/api/data_workspace/v2/tests/bdd/licences/conftest.py +++ b/api/data_workspace/v2/tests/bdd/licences/conftest.py @@ -66,7 +66,6 @@ def standard_case_with_final_advice(lu_case_officer): return case - @pytest.fixture() def standard_case_with_refused_advice(lu_case_officer, standard_case_with_final_advice): standard_case_with_final_advice.advice.update(type=AdviceType.REFUSE) diff --git a/api/data_workspace/v2/tests/bdd/licences/test_licence_decisions.py b/api/data_workspace/v2/tests/bdd/licences/test_licence_decisions.py index 827feefe40..03dbee8993 100644 --- a/api/data_workspace/v2/tests/bdd/licences/test_licence_decisions.py +++ b/api/data_workspace/v2/tests/bdd/licences/test_licence_decisions.py @@ -194,10 +194,7 @@ def licence_for_case_is_refused(client, gov_headers, case_with_refused_advice): @when("case officer revokes issued licence", target_fixture="revoked_licence") def case_officer_revokes_licence(client, lu_sr_manager_headers, issued_licence): - url = reverse( - "licences:licence_details", - kwargs={"pk": str(issued_licence.pk)} - ) + url = reverse("licences:licence_details", kwargs={"pk": str(issued_licence.pk)}) response = client.patch( url, {"status": LicenceStatus.REVOKED}, content_type="application/json", **lu_sr_manager_headers ) From 4d0dd9b4e4f4faa7d91f08e539dc936ce6b1bcb1 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Tue, 12 Nov 2024 22:52:54 +0000 Subject: [PATCH 82/86] Mock s3 upload function when decision documents are generated in bdd tests --- .../v2/tests/bdd/licences/test_licence_decisions.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/api/data_workspace/v2/tests/bdd/licences/test_licence_decisions.py b/api/data_workspace/v2/tests/bdd/licences/test_licence_decisions.py index 03dbee8993..f6630fa078 100644 --- a/api/data_workspace/v2/tests/bdd/licences/test_licence_decisions.py +++ b/api/data_workspace/v2/tests/bdd/licences/test_licence_decisions.py @@ -8,6 +8,7 @@ when, scenarios, ) +from unittest import mock from api.cases.enums import AdviceType, LicenceDecisionType from api.cases.models import LicenceDecision @@ -115,8 +116,9 @@ def case_officer_generates_licence_documents(client, siel_template, gov_headers, "cases:generated_documents:generated_documents", kwargs={"pk": str(case_with_final_advice.pk)}, ) - response = client.post(url, data, content_type="application/json", **gov_headers) - assert response.status_code == 201 + with mock.patch("api.cases.generated_documents.views.s3_operations.upload_bytes_file", return_value=None): + response = client.post(url, data, content_type="application/json", **gov_headers) + assert response.status_code == 201 @when("case officer issues licence for this case", target_fixture="issued_licence") @@ -167,8 +169,9 @@ def generate_refusal_documents(client, siel_refusal_template, gov_headers, case_ "cases:generated_documents:generated_documents", kwargs={"pk": str(case_with_refused_advice.pk)}, ) - response = client.post(url, data, content_type="application/json", **gov_headers) - assert response.status_code == 201 + with mock.patch("api.cases.generated_documents.views.s3_operations.upload_bytes_file", return_value=None): + response = client.post(url, data, content_type="application/json", **gov_headers) + assert response.status_code == 201 @when("case officer refuses licence for this case", target_fixture="refused_case") From 4668aa15be8f220f9c237d949c940b62a1a7f209 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Wed, 13 Nov 2024 10:37:53 +0000 Subject: [PATCH 83/86] Skip coverage for unreachable lines We can probably delete these once all changes are productionised. --- api/data_workspace/v2/serializers.py | 2 +- api/data_workspace/v2/views.py | 2 +- api/licences/enums.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index 182111247d..d5f48f94cc 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -22,7 +22,7 @@ def get_decision(self, case): def get_decision_made_at(self, case): if case.decision not in LicenceDecisionType.decisions(): - raise ValueError(f"Unknown decision type `{case.decision}`") + raise ValueError(f"Unknown decision type `{case.decision}`") # pragma: no cover return ( case.licence_decisions.filter( diff --git a/api/data_workspace/v2/views.py b/api/data_workspace/v2/views.py index 8a4973a97b..ce28e0dd81 100644 --- a/api/data_workspace/v2/views.py +++ b/api/data_workspace/v2/views.py @@ -18,7 +18,7 @@ class DisableableLimitOffsetPagination(LimitOffsetPagination): def paginate_queryset(self, queryset, request, view=None): if str_to_bool(request.GET.get("disable_pagination", False)): - return + return # pragma: no cover return super().paginate_queryset(queryset, request, view) diff --git a/api/licences/enums.py b/api/licences/enums.py index d090cd7aaa..2458571c31 100644 --- a/api/licences/enums.py +++ b/api/licences/enums.py @@ -47,7 +47,7 @@ def can_edit_status(cls, status): @classmethod def all(cls): - return [getattr(cls, param) for param in dir(cls) if param.isupper()] + return [getattr(cls, param) for param in dir(cls) if param.isupper()] # pragma: no cover hmrc_integration_action_to_licence_status = { From 8237f8688b2b327d7ed500cececefcc0d9a8887b Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Wed, 13 Nov 2024 10:47:03 +0000 Subject: [PATCH 84/86] Address review comments --- .../v2/tests/bdd/licences/test_licence_decisions.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/api/data_workspace/v2/tests/bdd/licences/test_licence_decisions.py b/api/data_workspace/v2/tests/bdd/licences/test_licence_decisions.py index f6630fa078..887aa903cc 100644 --- a/api/data_workspace/v2/tests/bdd/licences/test_licence_decisions.py +++ b/api/data_workspace/v2/tests/bdd/licences/test_licence_decisions.py @@ -208,8 +208,11 @@ def case_officer_revokes_licence(client, lu_sr_manager_headers, issued_licence): decision=LicenceDecisionType.REVOKED, ).exists() - issued_licence.refresh_from_db() - return issued_licence + revoked_licence = LicenceDecision.objects.get( + case=issued_licence.case, decision=LicenceDecisionType.REVOKED + ).licence + + return revoked_licence @then("I see revoked licence is included in the extract") From 9a0eb7b7b832c5782630a57d39d82ca15d44f756 Mon Sep 17 00:00:00 2001 From: Brendan Smith Date: Thu, 14 Nov 2024 10:22:12 +0000 Subject: [PATCH 85/86] Bump lite-routing sha to revert change --- lite_routing | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lite_routing b/lite_routing index 9f0385eaef..64038d673c 160000 --- a/lite_routing +++ b/lite_routing @@ -1 +1 @@ -Subproject commit 9f0385eaefe6eb6ebff05743f617b89b5691f85a +Subproject commit 64038d673c677a772884ff6fe3b49115c096809f From 361894c84b7c38145e2566b168b8de11f7aa9a5c Mon Sep 17 00:00:00 2001 From: "mark.j0hnst0n" Date: Fri, 15 Nov 2024 12:28:11 +0000 Subject: [PATCH 86/86] change coverage to most recent passing version --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1cc35d65c5..588ea63ef7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -520,7 +520,7 @@ jobs: - git_checkout - attach_workspace: at: ~/lite-api/tmp - - run: pip install coverage diff_cover + - run: pip install coverage==7.6.4 diff_cover - run: coverage combine tmp - run: coverage xml - run: coverage html