diff --git a/.devcontainer/.dev_config.yaml b/.devcontainer/.dev_config.yaml index 27745f3..9b525e4 100644 --- a/.devcontainer/.dev_config.yaml +++ b/.devcontainer/.dev_config.yaml @@ -11,3 +11,5 @@ notification_event_type: notification notification_event_topic: notification_events file_registered_event_topic: internal_file_registry file_registered_event_type: file_registered +iva_events_topic: ivas +iva_state_changed_event_type: iva_state_changed diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4ac77e2..f631e9e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -45,7 +45,7 @@ repos: - id: no-commit-to-branch args: [--branch, dev, --branch, int, --branch, main] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.4.2 + rev: v0.4.3 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/README.md b/README.md index 32623bd..39b1ec7 100644 --- a/README.md +++ b/README.md @@ -151,6 +151,26 @@ The service requires the following configuration parameters: ``` +- **`iva_events_topic`** *(string)*: The name of the topic containing IVA events. + + + Examples: + + ```json + "ivas" + ``` + + +- **`iva_state_changed_event_type`** *(string)*: The type to use for iva state changed events. + + + Examples: + + ```json + "iva_state_changed" + ``` + + - **`service_name`** *(string)*: The Notification Orchestration Service controls the creation of notification events. Default: `"nos"`. - **`service_instance_id`** *(string)*: A string that uniquely identifies this instance across all instances of this service. This is included in log messages. diff --git a/config_schema.json b/config_schema.json index 64b2348..88056cf 100644 --- a/config_schema.json +++ b/config_schema.json @@ -84,6 +84,22 @@ "title": "File Registered Event Type", "type": "string" }, + "iva_events_topic": { + "description": "The name of the topic containing IVA events.", + "examples": [ + "ivas" + ], + "title": "Iva Events Topic", + "type": "string" + }, + "iva_state_changed_event_type": { + "description": "The type to use for iva state changed events.", + "examples": [ + "iva_state_changed" + ], + "title": "Iva State Changed Event Type", + "type": "string" + }, "service_name": { "default": "nos", "description": "The Notification Orchestration Service controls the creation of notification events.", @@ -205,6 +221,8 @@ "access_request_denied_event_type", "file_registered_event_topic", "file_registered_event_type", + "iva_events_topic", + "iva_state_changed_event_type", "service_instance_id", "kafka_servers", "central_data_stewardship_email" diff --git a/example_config.yaml b/example_config.yaml index dfa7181..00082ca 100644 --- a/example_config.yaml +++ b/example_config.yaml @@ -8,6 +8,8 @@ db_name: users file_registered_event_topic: internal_file_registry file_registered_event_type: file_registered generate_correlation_id: true +iva_events_topic: ivas +iva_state_changed_event_type: iva_state_changed kafka_security_protocol: PLAINTEXT kafka_servers: - kafka:9092 diff --git a/lock/requirements-dev.txt b/lock/requirements-dev.txt index de822c0..7ff211d 100644 --- a/lock/requirements-dev.txt +++ b/lock/requirements-dev.txt @@ -52,13 +52,13 @@ attrs==23.2.0 \ # via # jsonschema # referencing -boto3==1.34.94 \ - --hash=sha256:22f65b3c9b7a419f8f39c2dddc421e14fab8cbb3bd8a9d467e874237d39f59b1 \ - --hash=sha256:bbb87d641c73462e53b1777083b55c8f13921618ad08757478a8122985c56c13 +boto3==1.34.98 \ + --hash=sha256:030e43b8efe22b4cf10b9f3ef9e30cd4cf9ef9784b26efe9a4583339f2b2bcec \ + --hash=sha256:28c10956033fa79e64529f48c3b62db86d5e4b77024a7343764b6bde6b553543 # via hexkit -botocore==1.34.94 \ - --hash=sha256:99b11be9a28f9051af4c96fa121e9c3f22a86d499abd773c9e868b2a38961bae \ - --hash=sha256:f00a79002e0cb9d6895ecd0919c506402850177d7b6c4d2634fa2da362d95bcb +botocore==1.34.98 \ + --hash=sha256:4cee65df02f4b0be08ad1401965cc89efafebc50ef0727d2d17083c7f1ed2831 \ + --hash=sha256:631c0031d8ce922b5752ab395ead896a0281b0dc74745a754d0351a27c5d83de # via # boto3 # hexkit @@ -172,59 +172,59 @@ click==8.1.7 \ # via # typer # uvicorn -coverage==7.5.0 \ - --hash=sha256:075299460948cd12722a970c7eae43d25d37989da682997687b34ae6b87c0ef0 \ - --hash=sha256:07dfdd492d645eea1bd70fb1d6febdcf47db178b0d99161d8e4eed18e7f62fe7 \ - --hash=sha256:0cbdf2cae14a06827bec50bd58e49249452d211d9caddd8bd80e35b53cb04631 \ - --hash=sha256:2055c4fb9a6ff624253d432aa471a37202cd8f458c033d6d989be4499aed037b \ - --hash=sha256:262fffc1f6c1a26125d5d573e1ec379285a3723363f3bd9c83923c9593a2ac25 \ - --hash=sha256:280132aada3bc2f0fac939a5771db4fbb84f245cb35b94fae4994d4c1f80dae7 \ - --hash=sha256:2b57780b51084d5223eee7b59f0d4911c31c16ee5aa12737c7a02455829ff067 \ - --hash=sha256:2bd7065249703cbeb6d4ce679c734bef0ee69baa7bff9724361ada04a15b7e3b \ - --hash=sha256:3235d7c781232e525b0761730e052388a01548bd7f67d0067a253887c6e8df46 \ - --hash=sha256:33c020d3322662e74bc507fb11488773a96894aa82a622c35a5a28673c0c26f5 \ - --hash=sha256:357754dcdfd811462a725e7501a9b4556388e8ecf66e79df6f4b988fa3d0b39a \ - --hash=sha256:39793731182c4be939b4be0cdecde074b833f6171313cf53481f869937129ed3 \ - --hash=sha256:3c2b77f295edb9fcdb6a250f83e6481c679335ca7e6e4a955e4290350f2d22a4 \ - --hash=sha256:41327143c5b1d715f5f98a397608f90ab9ebba606ae4e6f3389c2145410c52b1 \ - --hash=sha256:427e1e627b0963ac02d7c8730ca6d935df10280d230508c0ba059505e9233475 \ - --hash=sha256:432949a32c3e3f820af808db1833d6d1631664d53dd3ce487aa25d574e18ad1c \ - --hash=sha256:4ba01d9ba112b55bfa4b24808ec431197bb34f09f66f7cb4fd0258ff9d3711b1 \ - --hash=sha256:4d0e206259b73af35c4ec1319fd04003776e11e859936658cb6ceffdeba0f5be \ - --hash=sha256:51431d0abbed3a868e967f8257c5faf283d41ec882f58413cf295a389bb22e58 \ - --hash=sha256:565b2e82d0968c977e0b0f7cbf25fd06d78d4856289abc79694c8edcce6eb2de \ - --hash=sha256:6782cd6216fab5a83216cc39f13ebe30adfac2fa72688c5a4d8d180cd52e8f6a \ - --hash=sha256:6afd2e84e7da40fe23ca588379f815fb6dbbb1b757c883935ed11647205111cb \ - --hash=sha256:710c62b6e35a9a766b99b15cdc56d5aeda0914edae8bb467e9c355f75d14ee95 \ - --hash=sha256:84921b10aeb2dd453247fd10de22907984eaf80901b578a5cf0bb1e279a587cb \ - --hash=sha256:85a5dbe1ba1bf38d6c63b6d2c42132d45cbee6d9f0c51b52c59aa4afba057517 \ - --hash=sha256:9c6384cc90e37cfb60435bbbe0488444e54b98700f727f16f64d8bfda0b84656 \ - --hash=sha256:9dd88fce54abbdbf4c42fb1fea0e498973d07816f24c0e27a1ecaf91883ce69e \ - --hash=sha256:a81eb64feded34f40c8986869a2f764f0fe2db58c0530d3a4afbcde50f314880 \ - --hash=sha256:a898c11dca8f8c97b467138004a30133974aacd572818c383596f8d5b2eb04a9 \ - --hash=sha256:a9960dd1891b2ddf13a7fe45339cd59ecee3abb6b8326d8b932d0c5da208104f \ - --hash=sha256:a9a7ef30a1b02547c1b23fa9a5564f03c9982fc71eb2ecb7f98c96d7a0db5cf2 \ - --hash=sha256:ad97ec0da94b378e593ef532b980c15e377df9b9608c7c6da3506953182398af \ - --hash=sha256:adf032b6c105881f9d77fa17d9eebe0ad1f9bfb2ad25777811f97c5362aa07f2 \ - --hash=sha256:bbfe6389c5522b99768a93d89aca52ef92310a96b99782973b9d11e80511f932 \ - --hash=sha256:bd4bacd62aa2f1a1627352fe68885d6ee694bdaebb16038b6e680f2924a9b2cc \ - --hash=sha256:bf0b4b8d9caa8d64df838e0f8dcf68fb570c5733b726d1494b87f3da85db3a2d \ - --hash=sha256:c379cdd3efc0658e652a14112d51a7668f6bfca7445c5a10dee7eabecabba19d \ - --hash=sha256:c58536f6892559e030e6924896a44098bc1290663ea12532c78cef71d0df8493 \ - --hash=sha256:cbe6581fcff7c8e262eb574244f81f5faaea539e712a058e6707a9d272fe5b64 \ - --hash=sha256:ced268e82af993d7801a9db2dbc1d2322e786c5dc76295d8e89473d46c6b84d4 \ - --hash=sha256:cf3539007202ebfe03923128fedfdd245db5860a36810136ad95a564a2fdffff \ - --hash=sha256:cf62d17310f34084c59c01e027259076479128d11e4661bb6c9acb38c5e19bb8 \ - --hash=sha256:d0194d654e360b3e6cc9b774e83235bae6b9b2cac3be09040880bb0e8a88f4a1 \ - --hash=sha256:d3d117890b6eee85887b1eed41eefe2e598ad6e40523d9f94c4c4b213258e4a4 \ - --hash=sha256:db2de4e546f0ec4b2787d625e0b16b78e99c3e21bc1722b4977c0dddf11ca84e \ - --hash=sha256:e768d870801f68c74c2b669fc909839660180c366501d4cc4b87efd6b0eee375 \ - --hash=sha256:e7c211f25777746d468d76f11719e64acb40eed410d81c26cefac641975beb88 \ - --hash=sha256:eed462b4541c540d63ab57b3fc69e7d8c84d5957668854ee4e408b50e92ce26a \ - --hash=sha256:f0bfe42523893c188e9616d853c47685e1c575fe25f737adf473d0405dcfa7eb \ - --hash=sha256:f609ebcb0242d84b7adeee2b06c11a2ddaec5464d21888b2c8255f5fd6a98ae4 \ - --hash=sha256:fea9d3ca80bcf17edb2c08a4704259dadac196fe5e9274067e7a20511fad1743 \ - --hash=sha256:fed7a72d54bd52f4aeb6c6e951f363903bd7d70bc1cad64dd1f087980d309ab9 +coverage==7.5.1 \ + --hash=sha256:0646599e9b139988b63704d704af8e8df7fa4cbc4a1f33df69d97f36cb0a38de \ + --hash=sha256:0cdcbc320b14c3e5877ee79e649677cb7d89ef588852e9583e6b24c2e5072661 \ + --hash=sha256:0d0a0f5e06881ecedfe6f3dd2f56dcb057b6dbeb3327fd32d4b12854df36bf26 \ + --hash=sha256:1434e088b41594baa71188a17533083eabf5609e8e72f16ce8c186001e6b8c41 \ + --hash=sha256:16db7f26000a07efcf6aea00316f6ac57e7d9a96501e990a36f40c965ec7a95d \ + --hash=sha256:1cc0fe9b0b3a8364093c53b0b4c0c2dd4bb23acbec4c9240b5f284095ccf7981 \ + --hash=sha256:1fc81d5878cd6274ce971e0a3a18a8803c3fe25457165314271cf78e3aae3aa2 \ + --hash=sha256:2ec92012fefebee89a6b9c79bc39051a6cb3891d562b9270ab10ecfdadbc0c34 \ + --hash=sha256:39afcd3d4339329c5f58de48a52f6e4e50f6578dd6099961cf22228feb25f38f \ + --hash=sha256:4a7b0ceee8147444347da6a66be737c9d78f3353b0681715b668b72e79203e4a \ + --hash=sha256:4a9ca3f2fae0088c3c71d743d85404cec8df9be818a005ea065495bedc33da35 \ + --hash=sha256:4bf0655ab60d754491004a5efd7f9cccefcc1081a74c9ef2da4735d6ee4a6223 \ + --hash=sha256:4cc37def103a2725bc672f84bd939a6fe4522310503207aae4d56351644682f1 \ + --hash=sha256:4fc84a37bfd98db31beae3c2748811a3fa72bf2007ff7902f68746d9757f3746 \ + --hash=sha256:5037f8fcc2a95b1f0e80585bd9d1ec31068a9bcb157d9750a172836e98bc7a90 \ + --hash=sha256:54de9ef3a9da981f7af93eafde4ede199e0846cd819eb27c88e2b712aae9708c \ + --hash=sha256:556cf1a7cbc8028cb60e1ff0be806be2eded2daf8129b8811c63e2b9a6c43bca \ + --hash=sha256:57e0204b5b745594e5bc14b9b50006da722827f0b8c776949f1135677e88d0b8 \ + --hash=sha256:5a5740d1fb60ddf268a3811bcd353de34eb56dc24e8f52a7f05ee513b2d4f596 \ + --hash=sha256:5c3721c2c9e4c4953a41a26c14f4cef64330392a6d2d675c8b1db3b645e31f0e \ + --hash=sha256:5fa567e99765fe98f4e7d7394ce623e794d7cabb170f2ca2ac5a4174437e90dd \ + --hash=sha256:5fd215c0c7d7aab005221608a3c2b46f58c0285a819565887ee0b718c052aa4e \ + --hash=sha256:6175d1a0559986c6ee3f7fccfc4a90ecd12ba0a383dcc2da30c2b9918d67d8a3 \ + --hash=sha256:61c4bf1ba021817de12b813338c9be9f0ad5b1e781b9b340a6d29fc13e7c1b5e \ + --hash=sha256:6537e7c10cc47c595828b8a8be04c72144725c383c4702703ff4e42e44577312 \ + --hash=sha256:68f962d9b72ce69ea8621f57551b2fa9c70509af757ee3b8105d4f51b92b41a7 \ + --hash=sha256:7352b9161b33fd0b643ccd1f21f3a3908daaddf414f1c6cb9d3a2fd618bf2572 \ + --hash=sha256:796a79f63eca8814ca3317a1ea443645c9ff0d18b188de470ed7ccd45ae79428 \ + --hash=sha256:79afb6197e2f7f60c4824dd4b2d4c2ec5801ceb6ba9ce5d2c3080e5660d51a4f \ + --hash=sha256:7a588d39e0925f6a2bff87154752481273cdb1736270642aeb3635cb9b4cad07 \ + --hash=sha256:8748731ad392d736cc9ccac03c9845b13bb07d020a33423fa5b3a36521ac6e4e \ + --hash=sha256:8fe7502616b67b234482c3ce276ff26f39ffe88adca2acf0261df4b8454668b4 \ + --hash=sha256:9314d5678dcc665330df5b69c1e726a0e49b27df0461c08ca12674bcc19ef136 \ + --hash=sha256:9735317685ba6ec7e3754798c8871c2f49aa5e687cc794a0b1d284b2389d1bd5 \ + --hash=sha256:9981706d300c18d8b220995ad22627647be11a4276721c10911e0e9fa44c83e8 \ + --hash=sha256:9e78295f4144f9dacfed4f92935fbe1780021247c2fabf73a819b17f0ccfff8d \ + --hash=sha256:b016ea6b959d3b9556cb401c55a37547135a587db0115635a443b2ce8f1c7228 \ + --hash=sha256:b6cf3764c030e5338e7f61f95bd21147963cf6aa16e09d2f74f1fa52013c1206 \ + --hash=sha256:beccf7b8a10b09c4ae543582c1319c6df47d78fd732f854ac68d518ee1fb97fa \ + --hash=sha256:c0884920835a033b78d1c73b6d3bbcda8161a900f38a488829a83982925f6c2e \ + --hash=sha256:c3e757949f268364b96ca894b4c342b41dc6f8f8b66c37878aacef5930db61be \ + --hash=sha256:ca498687ca46a62ae590253fba634a1fe9836bc56f626852fb2720f334c9e4e5 \ + --hash=sha256:d1d0d98d95dd18fe29dc66808e1accf59f037d5716f86a501fc0256455219668 \ + --hash=sha256:d21918e9ef11edf36764b93101e2ae8cc82aa5efdc7c5a4e9c6c35a48496d601 \ + --hash=sha256:d7fed867ee50edf1a0b4a11e8e5d0895150e572af1cd6d315d557758bfa9c057 \ + --hash=sha256:db66fc317a046556a96b453a58eced5024af4582a8dbdc0c23ca4dbc0d5b3146 \ + --hash=sha256:dde0070c40ea8bb3641e811c1cfbf18e265d024deff6de52c5950677a8fb1e0f \ + --hash=sha256:df4e745a81c110e7446b1cc8131bf986157770fa405fe90e15e850aaf7619bc8 \ + --hash=sha256:e2213def81a50519d7cc56ed643c9e93e0247f5bbe0d1247d15fa520814a7cd7 \ + --hash=sha256:ef48e2707fb320c8f139424a596f5b69955a85b178f15af261bab871873bb987 \ + --hash=sha256:f152cbf5b88aaeb836127d920dd0f5e7edff5a66f10c079157306c4343d86c19 \ + --hash=sha256:fc0b4d8bfeabd25ea75e94632f5b6e047eef8adaed0c2161ada1e922e7f7cece # via pytest-cov distlib==0.3.8 \ --hash=sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784 \ @@ -252,9 +252,9 @@ filelock==3.14.0 \ --hash=sha256:43339835842f110ca7ae60f1e1c160714c5a6afd15a2873419ab185334975c0f \ --hash=sha256:6ea72da3be9b8c82afd3edcf99f2fffbb5076335a5ae4d03248bb5b6c3eae78a # via virtualenv -ghga-event-schemas==3.1.0 \ - --hash=sha256:87706784895376314124d30a0ba77dd7cfebdbfbcbb98e88d2a836486f11c385 \ - --hash=sha256:fa0048eda36002e7a79bc9084d2acdcc9eb9d38bcf263d6f68ad6fc453cae130 +ghga-event-schemas==3.2.0 \ + --hash=sha256:66ccf599967722163b06a98a665a9393de012e4db92059e8fd5a312785f21071 \ + --hash=sha256:d6f9ad7a9132f5aaff2003e3db07d2a9a223b27270d0afb256d698a639fd6f2c ghga-service-commons==3.1.3 \ --hash=sha256:4f7c2b56ae24594dd60cb28719f040351056c06d59b2d8f74f46eb9005b770f2 \ --hash=sha256:8b2e255506ac11cfafba3a18f58c0471a0b1b0c89893f6489a8a2f9af4dd6c0b @@ -336,9 +336,9 @@ jmespath==1.0.1 \ # via # boto3 # botocore -jsonschema==4.21.1 \ - --hash=sha256:7996507afae316306f9e2290407761157c6f78002dcf7419acb99822143d1c6f \ - --hash=sha256:85727c00279f5fa6bedbe6238d2aa6403bedd8b4864ab11207d07df3cc1b2ee5 +jsonschema==4.22.0 \ + --hash=sha256:5b22d434a45935119af990552c862e5d6d564e8f6601206b305a61fdf661a2b7 \ + --hash=sha256:ff4cfd6b1367a40e7bc6411caec72effadd3db0bbe5017de188f2d6108335802 # via # ghga-event-schemas # hexkit @@ -512,71 +512,71 @@ pydantic-settings==2.2.1 \ --hash=sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed \ --hash=sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091 # via hexkit -pygments==2.17.2 \ - --hash=sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c \ - --hash=sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367 +pygments==2.18.0 \ + --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \ + --hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a # via rich -pymongo==4.7.0 \ - --hash=sha256:030dba8b3e1cb29f874739247e1eba1d01118a11583c62145c707a6e725d416a \ - --hash=sha256:07265c14aa40259771255dbf59f9160a3690e82522ed02ab07e0e5c3045bad5b \ - --hash=sha256:0ad32bb7e5f889fc5994001f7bb8bf945b52e10e428a563dfce0661961eae224 \ - --hash=sha256:0dc2e365b14cb768898429e4331c58587be7143ad230858d19e8dd032f0adadc \ - --hash=sha256:12db8e8768bd0d4a433eea3463f05648c3f65f262776c777a0e19e7c55f27a73 \ - --hash=sha256:16d7fc4891f5482e42c35be6931e9cf6b635d7d95056ff45b56bae5f0384830f \ - --hash=sha256:1864f224b1793ef8698f779a7808e2b8c4a8f26bd0612c578412f62d6e99be46 \ - --hash=sha256:2161278182f3163d15afc3c578097ec20c844ac7180e41134a2a2b5c9ae77b9d \ - --hash=sha256:2545c2be5ed25b1e9419cde4269d6a744076f80eaf86695d2dd888bddac29dd7 \ - --hash=sha256:2bfaf7a7eb6a91dfe58f384be16fd895e040d17236ee82217d1be9fc56869dc8 \ - --hash=sha256:2f1a2ee91a97904cd21bddfce58d1868b6ea67b99bdd81dfe9cebfe35d0d751b \ - --hash=sha256:31ed6426fc68d500e2f27346e4ce3cc4fd3438adc99a3aaae41578c8a3b1f467 \ - --hash=sha256:36536a41f08180adc647a21ca12dba859a23d841d28ca8fd3976c8781ed8290b \ - --hash=sha256:36d05d1ff861dda7c9e84d9848ea6f2b5d2245ae1093865d14597de29ba95b37 \ - --hash=sha256:3f1d57edc2a4bd96ae5741e4d83d3d54695174fd9068c88c89e12f7262be4de4 \ - --hash=sha256:41d647fdaedba2f5b5c92299575814c164af44696fed3a4fc0d0df4f29eabcb2 \ - --hash=sha256:431093ef808944a14698b2a719b739fa7721778769e80c08423568991aa29c42 \ - --hash=sha256:44eb2a3adaa0916f2fb6812d4d805956fd376b7fceae3b62f5dfae5e29330786 \ - --hash=sha256:4b2b49670b32df8cf6650133cf439593f0291228ce971094c62c3a478024c7d1 \ - --hash=sha256:4c82105c91cf95821039aca48350630435e7be18989496b6292aaa8779fa5fb6 \ - --hash=sha256:50865177882df0badc879c5b20f20cdc9c73494f0e2b19a40534af9c90018b4e \ - --hash=sha256:52facf98dcba501b2ae337d21f065cc30ceb25b97ce8f17878c1ae9d781f7f26 \ - --hash=sha256:5307bfda4f39d9f1b3df9ab96b22d44bca458e44286ce806d716a2ffed2c46da \ - --hash=sha256:5366f28b2115120611536914540b0d247a89b09bb80bbc78893f246a584165b9 \ - --hash=sha256:5c4b0d8393fb991b3dd934e891e064ae804e9267fce9d01d2f16b25e20564e3d \ - --hash=sha256:6673daf8fc23a96934cbb7a3626dcfa3ae21510492047e6003dfe3f26e62886b \ - --hash=sha256:66b490775aa4542e0585ffdff1d0c6c4279536c852334f34a6a9a5c882beafd4 \ - --hash=sha256:69865d5739822c277d075a50601077767706e9f0862562e116ef13969d09fc9e \ - --hash=sha256:6c993fff4c110f6de4d76b76af97733efecae83b688cb27d1a3c5431415e3803 \ - --hash=sha256:7214b7599a9f2e4ed01ecdc034cbe8f2926954bfdad9277390dd1bccf9fd6553 \ - --hash=sha256:7530ea1da6fe0bb1960390ba6523483dfdb2a6239d0e8058b1505cc2a79c75f8 \ - --hash=sha256:78b0ba6d60c7f2ac779909ac53383c83584826a304206559599c46a33366622a \ - --hash=sha256:7a3c9218c5bc4384fa079f41b744473ada6a5f549fc11a4ae0fe7287746acc04 \ - --hash=sha256:7be2e57df38fa9b1b6f9ebe5bedd38118b511d3bdf0d9e77158c476542c9153d \ - --hash=sha256:8449b6af19cac09cce9d0834c196b29b72b29e05724f4ea208b3f602fdd47086 \ - --hash=sha256:8885f825203fa14ce863b462effcd93e07bfc6e582b3b93cfcde5ae42ccc9923 \ - --hash=sha256:8af3de7fea21b1ced0770766ec37a5900a62b45fe4b8f1dfa521226d591dbf66 \ - --hash=sha256:8fc34b4d92d5d8671be6b728076f275ccfe8495c7e6b74750b634190e17ede68 \ - --hash=sha256:9584be3d20ee26b53c0b1e25ba38196b7f65f594f48211b5ab3fa12b428ec6a9 \ - --hash=sha256:97ccb53d9310d5963df1a4543f1cfabdfd914638a5c8438234f6ed70d9303222 \ - --hash=sha256:98cb932ab936d702e28cf8da1982dcf5e7cfc35736b7516c0df7aaa46c63e0e2 \ - --hash=sha256:9f53cf5bf65dda3fc1b5ec5f760233a41b282db3157d135e9272101f0492825f \ - --hash=sha256:a292ee4babdd632531effaac95da5f211caafa6a039c097a1b18a4dc0d52488b \ - --hash=sha256:aebd99aaea95c48fba24bc3d7b72e7bf70e06df4c647de938c4d3dce2fd25a1c \ - --hash=sha256:b3784063fa43a0019b6a73e1e63b7fcbff4ded4d0ec5442202aa3caa12be9ef8 \ - --hash=sha256:b3a49be20a403d86eb1c559350fb56f28a859041756159eeb00e89f59b6e1288 \ - --hash=sha256:b7b8bd94c63cef8f5bfbb29568934213d9730381db94f467f979c9e5aaa27130 \ - --hash=sha256:bd514420eb09bba897016b7f1a2c17f9f3f1a7bc320c0505c59c3225e024b51c \ - --hash=sha256:c85f9824a7e90bf49aeed953e63942bff499116312e555ccb51bd3bf7ebe9342 \ - --hash=sha256:c8ff95728965e633591862bfc197018d25bc349b5cd8da080acb52a2d17a6e95 \ - --hash=sha256:cb809ff53ab3110ebc43a5e47aa945bb97e4ed9bc9beb07f935f5c83d9077e67 \ - --hash=sha256:cefa4e9be8bffa80de1bd70ae5ee79973e5db10befabcb25289fb52231a0dcff \ - --hash=sha256:cf4187bc91bd10e29857775651101d0ec26e580d6b46a8c5cbf93928358ac3c3 \ - --hash=sha256:d4d584b249c79acae86729d216a5185d833a90477d566f094b47d39620493870 \ - --hash=sha256:db2885773af0c10420e6bb86e84ee780bc3817d45a29ef24d8f6376ae2351eec \ - --hash=sha256:e7a00cee5b7a4160eed9cb43a2539037f572f01ed7261c2d1b4f7217060dba61 \ - --hash=sha256:eb00787bed1939ef21ffcb09b3034b193c3c6e9838724e2c05ef881cb2b03a33 \ - --hash=sha256:f807dadc8030a5b55915f78fac25393af47bee8ccb62b5a6c5c622274ff4adf1 \ - --hash=sha256:f8c4cbe5a1258b9f3a49f83781c8b2fb58f39a682779a3c81dc444a609cb15ba \ - --hash=sha256:fbad9290b32ff1fc38bcac42699b8ea6a7c49cab081ba54761f3109bc5703248 +pymongo==4.7.1 \ + --hash=sha256:11f74dafde63ad2dc30c01f40b4c69d9af157f8ba5224b0c9d4de7158537266f \ + --hash=sha256:13fc201e073644acd77860d9e91ccfc27addf510563e07381cadc9a55ac3a894 \ + --hash=sha256:1bd1eef70c1eda838b26397ef75c9580d7a97fd94b6324971d7f3d2ad3552e9a \ + --hash=sha256:24c8f1dd545360ec1b79007a3ba6573af565df6fde49f6dfc53813f3f475a751 \ + --hash=sha256:253ed8fd6e7f4b2a1caa89e6b287b9e04f42613319ee1e1240c2db2afe1637e7 \ + --hash=sha256:263c169302df636f9086b584994a51d0adfc8738fe27d7b8e2aacf46fd68b6cb \ + --hash=sha256:297cdc87c4b4168782b571c8643540e9b0ad1d09266b43d2f5954f8632280835 \ + --hash=sha256:2ccc8dd4fe9aac18dde27c33a53271c6c90159b74c43fbdab1d33d5efc36c2f5 \ + --hash=sha256:30a9d891631d7e847b24f551b1d89ff2033539e7cd8e9af29714b4d0db7abb06 \ + --hash=sha256:31ed8ba3da0366346264604b3a443f5a4232cab5ed45f520bead6184cf0851a1 \ + --hash=sha256:337d99f88d32a5f8056d6d2bc365ccf09d09583f3942882c50cf11b459e8fbc0 \ + --hash=sha256:3ef32a7cfe748c0c72fdad9e51459de5e0c6b16c5288b39f863abfff23503847 \ + --hash=sha256:455f9d603ed0990a787773d5718e871300bddf585ce543baf129c9f5ca3adb02 \ + --hash=sha256:45ac46f0d6bdc2baac34ced60aae27b2083170d77397330eff0ac5689ea29d38 \ + --hash=sha256:4c7e05454cdc5aa4702e03cad0df4205daccd6fd631bbbf0a85bbe598129a6cc \ + --hash=sha256:4d227555be35078b53f506f6b58bd0b0e8fd4513e89e6f29e83a97efab439250 \ + --hash=sha256:4dd998e9f0f7694032c1648c7f57fccaa78903df6329b8f8ae20cfa7c4ceca34 \ + --hash=sha256:5119c66af8c4197c8757b4b7d98c443e5b127c224ac92fb657dbe2b512ae2713 \ + --hash=sha256:57b5b485ef89270ed2e603814f43f0fdd9b8ba5d4039124d90878cdc2327000c \ + --hash=sha256:58989bcb94233233a71645236b972835d4f87a6bb1b7e818d38a7e6e6d4630de \ + --hash=sha256:5a58b6cd7c423ba49db10d8445756062c931ad2246ba0da1e705bf22962fd9e9 \ + --hash=sha256:5ae1aeeb405c29885266666dc7115792d647ed68cfdb6ed02e2e211d12f2e1c8 \ + --hash=sha256:5bc87db2e9563295c4e45602ab978a2fcbaba3ab89e745503b24f895cddeb755 \ + --hash=sha256:5ff6d56ca1f0cd3687a13ce90a32a8efb3cc3a53728e5ac160c4c30d10385a72 \ + --hash=sha256:615c7573d7a9c4837332a673fdc5a5f214b474dd52d846bcf4cc3d011550bee1 \ + --hash=sha256:64b69b9cd8a6d23881a80490d575e92918f9afca43096a7d6c1013d6b3e5c75c \ + --hash=sha256:65c45682d5ed8c6618bde22cd6716b47a197f4ef800a025213b28d13a59e5fca \ + --hash=sha256:67cbee427c263a4483e3249fef480788ccc16edb1a4fc330c4c6cb0cb9db94a8 \ + --hash=sha256:7247c1dc7d8eed4e24eb1dd92c4c58ebf1e5159500015652552acfdebdeed256 \ + --hash=sha256:73bf96ece4999b0bbab7169cb2b9c60918b434487009e48be4bd47eeb2aa7b14 \ + --hash=sha256:7b10603ba64af08f5af7eb9a69d6b24e3c69d91fdd48c54b95e284686c1c582d \ + --hash=sha256:811a07bba9d35f1e34159ede632ac71dbc429b372a20004e32d6578af872db1a \ + --hash=sha256:811c41c6227b7548afcb53e1b996c25262d837b5e5f519e2ddc2c7e59d8728a5 \ + --hash=sha256:85b8dd3756b73993b1e3ab6b1cba826b9e4987a094a5d5b6d37313776458cd94 \ + --hash=sha256:887d043ecc0c7d5591925bbc7abb67caf21c94d6e6e5d442cb49eb5d9d8ee76b \ + --hash=sha256:8cee62188127a126f59ea45d3981868a5e35343be4ef4ad8712eaf42be37a00b \ + --hash=sha256:9e0a30a022ac8a9164ee5a4b761e13dbb3d10a21845f7258011e3415151fb645 \ + --hash=sha256:9e99dac3c7c2cb498937cc1767361851099da38861e921113318c87d71e3d127 \ + --hash=sha256:a46c08ef0b273c415b1e8933f6739596be264ae700a4927f84e0b84e70fdf0eb \ + --hash=sha256:a848249d5b4763497add62f7dd7bd0ce1538129bf42f4cb132a76d24c61bf98d \ + --hash=sha256:aa354933a158e57494c98b592f46d5d24d1b109e6ba05a05179cde719d9f7fd3 \ + --hash=sha256:ad360630c221aee7c0841a51851496a3ca6fdea87007098a982c1aa26e34083a \ + --hash=sha256:b897b60b2d55c26f3efea0effc11b655db68125c3731274bc3953375e9ccab73 \ + --hash=sha256:b8b95e2163b73d03a913efa89b0f7c5012be82efd4e9dbce8aa62010a75a277c \ + --hash=sha256:bfd5c7e5bb87171a5296fa32205adb50b27704a612036ec4395c3cd316fc0e91 \ + --hash=sha256:c808098f2cdb87d4035144e536ba5fa7709d0420c17b68e6ace5da18c38ded5f \ + --hash=sha256:d1829a7db720ff586aaf59c806e89e0a388548063aa844d21a570a231ad8ca87 \ + --hash=sha256:d50969de00d3522b2c394f7e59b843871e2be4b525af92066da7f3bd02799fdc \ + --hash=sha256:d63f38454a2e23c117d3ceab3b661568f2418536825787256ad24e5baaedfd27 \ + --hash=sha256:d804eaf19a65211cc2c8c5db75be685c3f31c64cdab639794f66f13f8e258ba6 \ + --hash=sha256:daf35ab13b86aba7cc8c4b019882f1fa8d287a26f586ef5eaf60a5233d3eaa52 \ + --hash=sha256:dbc32217c81d87750401fa1c2bc9450e854b23e6e30243c82d3514b8e58f39e3 \ + --hash=sha256:e175d74c52b6c8414a4b4504a2dd42b0202d101b2eb9508a34c137357683864e \ + --hash=sha256:e4a63ba6813a2168ebd35ea5369f6c33f7787525986cd77668b7956acc3d2a38 \ + --hash=sha256:e935712b17e7a42831022353bac91a346a792658a54e12bec907ec11695cc899 \ + --hash=sha256:ec94d29103317aa920dae59ed385de9604cb0ef840b5b7137b5eaa7a2042580a \ + --hash=sha256:ed6b3a0740efe98bb03ccf054578e9788ebcd06d021d548b8217ab2c82e45975 \ + --hash=sha256:f2a720e787c9b9b912db5bb4c3e7123ccff1352d6c3ac0cb2c7ee392cdc95c00 \ + --hash=sha256:f8822614975038e0cece47d12e7634a79c2ee590a0ae78ae64c37b9c6610a14c \ + --hash=sha256:fb1a884b1c6aeac5ffeb8ccb696fbc242a7ae1bba36f2328c01f76fab7221b94 # via motor pytest==8.2.0 \ --hash=sha256:1733f0620f6cda4095bbf0d9ff8022486e91892245bb9e7d5542c018f612f233 \ @@ -661,9 +661,9 @@ pyyaml==6.0.1 \ # jsonschema2md # pre-commit # uvicorn -referencing==0.35.0 \ - --hash=sha256:191e936b0c696d0af17ad7430a3dc68e88bc11be6514f4757dc890f04ab05889 \ - --hash=sha256:8080727b30e364e5783152903672df9b6b091c926a146a759080b62ca3126cd6 +referencing==0.35.1 \ + --hash=sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c \ + --hash=sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de # via # jsonschema # jsonschema-specifications @@ -778,24 +778,24 @@ rpds-py==0.18.0 \ # via # jsonschema # referencing -ruff==0.4.2 \ - --hash=sha256:0e2e06459042ac841ed510196c350ba35a9b24a643e23db60d79b2db92af0c2b \ - --hash=sha256:1f32cadf44c2020e75e0c56c3408ed1d32c024766bd41aedef92aa3ca28eef68 \ - --hash=sha256:22e306bf15e09af45ca812bc42fa59b628646fa7c26072555f278994890bc7ac \ - --hash=sha256:24016ed18db3dc9786af103ff49c03bdf408ea253f3cb9e3638f39ac9cf2d483 \ - --hash=sha256:33bcc160aee2520664bc0859cfeaebc84bb7323becff3f303b8f1f2d81cb4edc \ - --hash=sha256:3afabaf7ba8e9c485a14ad8f4122feff6b2b93cc53cd4dad2fd24ae35112d5c5 \ - --hash=sha256:5ec481661fb2fd88a5d6cf1f83403d388ec90f9daaa36e40e2c003de66751798 \ - --hash=sha256:652e4ba553e421a6dc2a6d4868bc3b3881311702633eb3672f9f244ded8908cd \ - --hash=sha256:6a2243f8f434e487c2a010c7252150b1fdf019035130f41b77626f5655c9ca22 \ - --hash=sha256:6ab165ef5d72392b4ebb85a8b0fbd321f69832a632e07a74794c0e598e7a8376 \ - --hash=sha256:7891ee376770ac094da3ad40c116258a381b86c7352552788377c6eb16d784fe \ - --hash=sha256:799eb468ea6bc54b95527143a4ceaf970d5aa3613050c6cff54c85fda3fde480 \ - --hash=sha256:82986bb77ad83a1719c90b9528a9dd663c9206f7c0ab69282af8223566a0c34e \ - --hash=sha256:8772130a063f3eebdf7095da00c0b9898bd1774c43b336272c3e98667d4fb8fa \ - --hash=sha256:8d14dc8953f8af7e003a485ef560bbefa5f8cc1ad994eebb5b12136049bbccc5 \ - --hash=sha256:cbd1e87c71bca14792948c4ccb51ee61c3296e164019d2d484f3eaa2d360dfaf \ - --hash=sha256:ec4ba9436a51527fb6931a8839af4c36a5481f8c19e8f5e42c2f7ad3a49f5069 +ruff==0.4.3 \ + --hash=sha256:08a0d6a22918ab2552ace96adeaca308833873a4d7d1d587bb1d37bae8728eb3 \ + --hash=sha256:0bfc9e955e6dc6359eb6f82ea150c4f4e82b660e5b58d9a20a0e42ec3bb6342b \ + --hash=sha256:18b00e0bcccf0fc8d7186ed21e311dffd19761cb632241a6e4fe4477cc80ef6e \ + --hash=sha256:25cacda2155778beb0d064e0ec5a3944dcca9c12715f7c4634fd9d93ac33fd30 \ + --hash=sha256:262f5635e2c74d80b7507fbc2fac28fe0d4fef26373bbc62039526f7722bca1b \ + --hash=sha256:29efff25bf9ee685c2c8390563a5b5c006a3fee5230d28ea39f4f75f9d0b6f2f \ + --hash=sha256:510a67d232d2ebe983fddea324dbf9d69b71c4d2dfeb8a862f4a127536dd4cfb \ + --hash=sha256:71ca5f8ccf1121b95a59649482470c5601c60a416bf189d553955b0338e34614 \ + --hash=sha256:7363691198719c26459e08cc17c6a3dac6f592e9ea3d2fa772f4e561b5fe82a3 \ + --hash=sha256:7a1c3a450bc6539ef00da6c819fb1b76b6b065dec585f91456e7c0d6a0bbc725 \ + --hash=sha256:819fb06d535cc76dfddbfe8d3068ff602ddeb40e3eacbc90e0d1272bb8d97113 \ + --hash=sha256:927b11c1e4d0727ce1a729eace61cee88a334623ec424c0b1c8fe3e5f9d3c865 \ + --hash=sha256:b70800c290f14ae6fcbb41bbe201cf62dfca024d124a1f373e76371a007454ce \ + --hash=sha256:dc9ff11cd9a092ee7680a56d21f302bdda14327772cd870d806610a3503d001f \ + --hash=sha256:eba1f14df3c758dd7de5b55fbae7e1c8af238597961e5fb628f3de446c3c40c5 \ + --hash=sha256:eeb039f8428fcb6725bb63cbae92ad67b0559e68b5d80f840f11914afd8ddf7f \ + --hash=sha256:ff0a3ef2e3c4b6d133fbedcf9586abfbe38d076041f2dc18ffb2c7e0485d5a07 s3transfer==0.10.1 \ --hash=sha256:5683916b4c724f799e600f41dd9e10a9ff19871bf87623cc8f491cb4f5fa0a19 \ --hash=sha256:ceb252b11bcf87080fb7850a224fb6e05c8a776bab8f2b64b7f25b969464839d diff --git a/lock/requirements.txt b/lock/requirements.txt index 777e8ae..8eec6b1 100644 --- a/lock/requirements.txt +++ b/lock/requirements.txt @@ -51,13 +51,13 @@ attrs==23.2.0 \ # via # jsonschema # referencing -boto3==1.34.94 \ - --hash=sha256:22f65b3c9b7a419f8f39c2dddc421e14fab8cbb3bd8a9d467e874237d39f59b1 \ - --hash=sha256:bbb87d641c73462e53b1777083b55c8f13921618ad08757478a8122985c56c13 +boto3==1.34.98 \ + --hash=sha256:030e43b8efe22b4cf10b9f3ef9e30cd4cf9ef9784b26efe9a4583339f2b2bcec \ + --hash=sha256:28c10956033fa79e64529f48c3b62db86d5e4b77024a7343764b6bde6b553543 # via hexkit -botocore==1.34.94 \ - --hash=sha256:99b11be9a28f9051af4c96fa121e9c3f22a86d499abd773c9e868b2a38961bae \ - --hash=sha256:f00a79002e0cb9d6895ecd0919c506402850177d7b6c4d2634fa2da362d95bcb +botocore==1.34.98 \ + --hash=sha256:4cee65df02f4b0be08ad1401965cc89efafebc50ef0727d2d17083c7f1ed2831 \ + --hash=sha256:631c0031d8ce922b5752ab395ead896a0281b0dc74745a754d0351a27c5d83de # via # boto3 # hexkit @@ -82,9 +82,9 @@ fastapi==0.110.3 \ --hash=sha256:555700b0159379e94fdbfc6bb66a0f1c43f4cf7060f25239af3d84b63a656626 \ --hash=sha256:fd7600612f755e4050beb74001310b5a7e1796d149c2ee363124abdfa0289d32 # via ghga-service-commons -ghga-event-schemas==3.1.0 \ - --hash=sha256:87706784895376314124d30a0ba77dd7cfebdbfbcbb98e88d2a836486f11c385 \ - --hash=sha256:fa0048eda36002e7a79bc9084d2acdcc9eb9d38bcf263d6f68ad6fc453cae130 +ghga-event-schemas==3.2.0 \ + --hash=sha256:66ccf599967722163b06a98a665a9393de012e4db92059e8fd5a312785f21071 \ + --hash=sha256:d6f9ad7a9132f5aaff2003e3db07d2a9a223b27270d0afb256d698a639fd6f2c ghga-service-commons==3.1.3 \ --hash=sha256:4f7c2b56ae24594dd60cb28719f040351056c06d59b2d8f74f46eb9005b770f2 \ --hash=sha256:8b2e255506ac11cfafba3a18f58c0471a0b1b0c89893f6489a8a2f9af4dd6c0b @@ -146,9 +146,9 @@ jmespath==1.0.1 \ # via # boto3 # botocore -jsonschema==4.21.1 \ - --hash=sha256:7996507afae316306f9e2290407761157c6f78002dcf7419acb99822143d1c6f \ - --hash=sha256:85727c00279f5fa6bedbe6238d2aa6403bedd8b4864ab11207d07df3cc1b2ee5 +jsonschema==4.22.0 \ + --hash=sha256:5b22d434a45935119af990552c862e5d6d564e8f6601206b305a61fdf661a2b7 \ + --hash=sha256:ff4cfd6b1367a40e7bc6411caec72effadd3db0bbe5017de188f2d6108335802 # via # ghga-event-schemas # hexkit @@ -266,71 +266,71 @@ pydantic-settings==2.2.1 \ --hash=sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed \ --hash=sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091 # via hexkit -pygments==2.17.2 \ - --hash=sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c \ - --hash=sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367 +pygments==2.18.0 \ + --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \ + --hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a # via rich -pymongo==4.7.0 \ - --hash=sha256:030dba8b3e1cb29f874739247e1eba1d01118a11583c62145c707a6e725d416a \ - --hash=sha256:07265c14aa40259771255dbf59f9160a3690e82522ed02ab07e0e5c3045bad5b \ - --hash=sha256:0ad32bb7e5f889fc5994001f7bb8bf945b52e10e428a563dfce0661961eae224 \ - --hash=sha256:0dc2e365b14cb768898429e4331c58587be7143ad230858d19e8dd032f0adadc \ - --hash=sha256:12db8e8768bd0d4a433eea3463f05648c3f65f262776c777a0e19e7c55f27a73 \ - --hash=sha256:16d7fc4891f5482e42c35be6931e9cf6b635d7d95056ff45b56bae5f0384830f \ - --hash=sha256:1864f224b1793ef8698f779a7808e2b8c4a8f26bd0612c578412f62d6e99be46 \ - --hash=sha256:2161278182f3163d15afc3c578097ec20c844ac7180e41134a2a2b5c9ae77b9d \ - --hash=sha256:2545c2be5ed25b1e9419cde4269d6a744076f80eaf86695d2dd888bddac29dd7 \ - --hash=sha256:2bfaf7a7eb6a91dfe58f384be16fd895e040d17236ee82217d1be9fc56869dc8 \ - --hash=sha256:2f1a2ee91a97904cd21bddfce58d1868b6ea67b99bdd81dfe9cebfe35d0d751b \ - --hash=sha256:31ed6426fc68d500e2f27346e4ce3cc4fd3438adc99a3aaae41578c8a3b1f467 \ - --hash=sha256:36536a41f08180adc647a21ca12dba859a23d841d28ca8fd3976c8781ed8290b \ - --hash=sha256:36d05d1ff861dda7c9e84d9848ea6f2b5d2245ae1093865d14597de29ba95b37 \ - --hash=sha256:3f1d57edc2a4bd96ae5741e4d83d3d54695174fd9068c88c89e12f7262be4de4 \ - --hash=sha256:41d647fdaedba2f5b5c92299575814c164af44696fed3a4fc0d0df4f29eabcb2 \ - --hash=sha256:431093ef808944a14698b2a719b739fa7721778769e80c08423568991aa29c42 \ - --hash=sha256:44eb2a3adaa0916f2fb6812d4d805956fd376b7fceae3b62f5dfae5e29330786 \ - --hash=sha256:4b2b49670b32df8cf6650133cf439593f0291228ce971094c62c3a478024c7d1 \ - --hash=sha256:4c82105c91cf95821039aca48350630435e7be18989496b6292aaa8779fa5fb6 \ - --hash=sha256:50865177882df0badc879c5b20f20cdc9c73494f0e2b19a40534af9c90018b4e \ - --hash=sha256:52facf98dcba501b2ae337d21f065cc30ceb25b97ce8f17878c1ae9d781f7f26 \ - --hash=sha256:5307bfda4f39d9f1b3df9ab96b22d44bca458e44286ce806d716a2ffed2c46da \ - --hash=sha256:5366f28b2115120611536914540b0d247a89b09bb80bbc78893f246a584165b9 \ - --hash=sha256:5c4b0d8393fb991b3dd934e891e064ae804e9267fce9d01d2f16b25e20564e3d \ - --hash=sha256:6673daf8fc23a96934cbb7a3626dcfa3ae21510492047e6003dfe3f26e62886b \ - --hash=sha256:66b490775aa4542e0585ffdff1d0c6c4279536c852334f34a6a9a5c882beafd4 \ - --hash=sha256:69865d5739822c277d075a50601077767706e9f0862562e116ef13969d09fc9e \ - --hash=sha256:6c993fff4c110f6de4d76b76af97733efecae83b688cb27d1a3c5431415e3803 \ - --hash=sha256:7214b7599a9f2e4ed01ecdc034cbe8f2926954bfdad9277390dd1bccf9fd6553 \ - --hash=sha256:7530ea1da6fe0bb1960390ba6523483dfdb2a6239d0e8058b1505cc2a79c75f8 \ - --hash=sha256:78b0ba6d60c7f2ac779909ac53383c83584826a304206559599c46a33366622a \ - --hash=sha256:7a3c9218c5bc4384fa079f41b744473ada6a5f549fc11a4ae0fe7287746acc04 \ - --hash=sha256:7be2e57df38fa9b1b6f9ebe5bedd38118b511d3bdf0d9e77158c476542c9153d \ - --hash=sha256:8449b6af19cac09cce9d0834c196b29b72b29e05724f4ea208b3f602fdd47086 \ - --hash=sha256:8885f825203fa14ce863b462effcd93e07bfc6e582b3b93cfcde5ae42ccc9923 \ - --hash=sha256:8af3de7fea21b1ced0770766ec37a5900a62b45fe4b8f1dfa521226d591dbf66 \ - --hash=sha256:8fc34b4d92d5d8671be6b728076f275ccfe8495c7e6b74750b634190e17ede68 \ - --hash=sha256:9584be3d20ee26b53c0b1e25ba38196b7f65f594f48211b5ab3fa12b428ec6a9 \ - --hash=sha256:97ccb53d9310d5963df1a4543f1cfabdfd914638a5c8438234f6ed70d9303222 \ - --hash=sha256:98cb932ab936d702e28cf8da1982dcf5e7cfc35736b7516c0df7aaa46c63e0e2 \ - --hash=sha256:9f53cf5bf65dda3fc1b5ec5f760233a41b282db3157d135e9272101f0492825f \ - --hash=sha256:a292ee4babdd632531effaac95da5f211caafa6a039c097a1b18a4dc0d52488b \ - --hash=sha256:aebd99aaea95c48fba24bc3d7b72e7bf70e06df4c647de938c4d3dce2fd25a1c \ - --hash=sha256:b3784063fa43a0019b6a73e1e63b7fcbff4ded4d0ec5442202aa3caa12be9ef8 \ - --hash=sha256:b3a49be20a403d86eb1c559350fb56f28a859041756159eeb00e89f59b6e1288 \ - --hash=sha256:b7b8bd94c63cef8f5bfbb29568934213d9730381db94f467f979c9e5aaa27130 \ - --hash=sha256:bd514420eb09bba897016b7f1a2c17f9f3f1a7bc320c0505c59c3225e024b51c \ - --hash=sha256:c85f9824a7e90bf49aeed953e63942bff499116312e555ccb51bd3bf7ebe9342 \ - --hash=sha256:c8ff95728965e633591862bfc197018d25bc349b5cd8da080acb52a2d17a6e95 \ - --hash=sha256:cb809ff53ab3110ebc43a5e47aa945bb97e4ed9bc9beb07f935f5c83d9077e67 \ - --hash=sha256:cefa4e9be8bffa80de1bd70ae5ee79973e5db10befabcb25289fb52231a0dcff \ - --hash=sha256:cf4187bc91bd10e29857775651101d0ec26e580d6b46a8c5cbf93928358ac3c3 \ - --hash=sha256:d4d584b249c79acae86729d216a5185d833a90477d566f094b47d39620493870 \ - --hash=sha256:db2885773af0c10420e6bb86e84ee780bc3817d45a29ef24d8f6376ae2351eec \ - --hash=sha256:e7a00cee5b7a4160eed9cb43a2539037f572f01ed7261c2d1b4f7217060dba61 \ - --hash=sha256:eb00787bed1939ef21ffcb09b3034b193c3c6e9838724e2c05ef881cb2b03a33 \ - --hash=sha256:f807dadc8030a5b55915f78fac25393af47bee8ccb62b5a6c5c622274ff4adf1 \ - --hash=sha256:f8c4cbe5a1258b9f3a49f83781c8b2fb58f39a682779a3c81dc444a609cb15ba \ - --hash=sha256:fbad9290b32ff1fc38bcac42699b8ea6a7c49cab081ba54761f3109bc5703248 +pymongo==4.7.1 \ + --hash=sha256:11f74dafde63ad2dc30c01f40b4c69d9af157f8ba5224b0c9d4de7158537266f \ + --hash=sha256:13fc201e073644acd77860d9e91ccfc27addf510563e07381cadc9a55ac3a894 \ + --hash=sha256:1bd1eef70c1eda838b26397ef75c9580d7a97fd94b6324971d7f3d2ad3552e9a \ + --hash=sha256:24c8f1dd545360ec1b79007a3ba6573af565df6fde49f6dfc53813f3f475a751 \ + --hash=sha256:253ed8fd6e7f4b2a1caa89e6b287b9e04f42613319ee1e1240c2db2afe1637e7 \ + --hash=sha256:263c169302df636f9086b584994a51d0adfc8738fe27d7b8e2aacf46fd68b6cb \ + --hash=sha256:297cdc87c4b4168782b571c8643540e9b0ad1d09266b43d2f5954f8632280835 \ + --hash=sha256:2ccc8dd4fe9aac18dde27c33a53271c6c90159b74c43fbdab1d33d5efc36c2f5 \ + --hash=sha256:30a9d891631d7e847b24f551b1d89ff2033539e7cd8e9af29714b4d0db7abb06 \ + --hash=sha256:31ed8ba3da0366346264604b3a443f5a4232cab5ed45f520bead6184cf0851a1 \ + --hash=sha256:337d99f88d32a5f8056d6d2bc365ccf09d09583f3942882c50cf11b459e8fbc0 \ + --hash=sha256:3ef32a7cfe748c0c72fdad9e51459de5e0c6b16c5288b39f863abfff23503847 \ + --hash=sha256:455f9d603ed0990a787773d5718e871300bddf585ce543baf129c9f5ca3adb02 \ + --hash=sha256:45ac46f0d6bdc2baac34ced60aae27b2083170d77397330eff0ac5689ea29d38 \ + --hash=sha256:4c7e05454cdc5aa4702e03cad0df4205daccd6fd631bbbf0a85bbe598129a6cc \ + --hash=sha256:4d227555be35078b53f506f6b58bd0b0e8fd4513e89e6f29e83a97efab439250 \ + --hash=sha256:4dd998e9f0f7694032c1648c7f57fccaa78903df6329b8f8ae20cfa7c4ceca34 \ + --hash=sha256:5119c66af8c4197c8757b4b7d98c443e5b127c224ac92fb657dbe2b512ae2713 \ + --hash=sha256:57b5b485ef89270ed2e603814f43f0fdd9b8ba5d4039124d90878cdc2327000c \ + --hash=sha256:58989bcb94233233a71645236b972835d4f87a6bb1b7e818d38a7e6e6d4630de \ + --hash=sha256:5a58b6cd7c423ba49db10d8445756062c931ad2246ba0da1e705bf22962fd9e9 \ + --hash=sha256:5ae1aeeb405c29885266666dc7115792d647ed68cfdb6ed02e2e211d12f2e1c8 \ + --hash=sha256:5bc87db2e9563295c4e45602ab978a2fcbaba3ab89e745503b24f895cddeb755 \ + --hash=sha256:5ff6d56ca1f0cd3687a13ce90a32a8efb3cc3a53728e5ac160c4c30d10385a72 \ + --hash=sha256:615c7573d7a9c4837332a673fdc5a5f214b474dd52d846bcf4cc3d011550bee1 \ + --hash=sha256:64b69b9cd8a6d23881a80490d575e92918f9afca43096a7d6c1013d6b3e5c75c \ + --hash=sha256:65c45682d5ed8c6618bde22cd6716b47a197f4ef800a025213b28d13a59e5fca \ + --hash=sha256:67cbee427c263a4483e3249fef480788ccc16edb1a4fc330c4c6cb0cb9db94a8 \ + --hash=sha256:7247c1dc7d8eed4e24eb1dd92c4c58ebf1e5159500015652552acfdebdeed256 \ + --hash=sha256:73bf96ece4999b0bbab7169cb2b9c60918b434487009e48be4bd47eeb2aa7b14 \ + --hash=sha256:7b10603ba64af08f5af7eb9a69d6b24e3c69d91fdd48c54b95e284686c1c582d \ + --hash=sha256:811a07bba9d35f1e34159ede632ac71dbc429b372a20004e32d6578af872db1a \ + --hash=sha256:811c41c6227b7548afcb53e1b996c25262d837b5e5f519e2ddc2c7e59d8728a5 \ + --hash=sha256:85b8dd3756b73993b1e3ab6b1cba826b9e4987a094a5d5b6d37313776458cd94 \ + --hash=sha256:887d043ecc0c7d5591925bbc7abb67caf21c94d6e6e5d442cb49eb5d9d8ee76b \ + --hash=sha256:8cee62188127a126f59ea45d3981868a5e35343be4ef4ad8712eaf42be37a00b \ + --hash=sha256:9e0a30a022ac8a9164ee5a4b761e13dbb3d10a21845f7258011e3415151fb645 \ + --hash=sha256:9e99dac3c7c2cb498937cc1767361851099da38861e921113318c87d71e3d127 \ + --hash=sha256:a46c08ef0b273c415b1e8933f6739596be264ae700a4927f84e0b84e70fdf0eb \ + --hash=sha256:a848249d5b4763497add62f7dd7bd0ce1538129bf42f4cb132a76d24c61bf98d \ + --hash=sha256:aa354933a158e57494c98b592f46d5d24d1b109e6ba05a05179cde719d9f7fd3 \ + --hash=sha256:ad360630c221aee7c0841a51851496a3ca6fdea87007098a982c1aa26e34083a \ + --hash=sha256:b897b60b2d55c26f3efea0effc11b655db68125c3731274bc3953375e9ccab73 \ + --hash=sha256:b8b95e2163b73d03a913efa89b0f7c5012be82efd4e9dbce8aa62010a75a277c \ + --hash=sha256:bfd5c7e5bb87171a5296fa32205adb50b27704a612036ec4395c3cd316fc0e91 \ + --hash=sha256:c808098f2cdb87d4035144e536ba5fa7709d0420c17b68e6ace5da18c38ded5f \ + --hash=sha256:d1829a7db720ff586aaf59c806e89e0a388548063aa844d21a570a231ad8ca87 \ + --hash=sha256:d50969de00d3522b2c394f7e59b843871e2be4b525af92066da7f3bd02799fdc \ + --hash=sha256:d63f38454a2e23c117d3ceab3b661568f2418536825787256ad24e5baaedfd27 \ + --hash=sha256:d804eaf19a65211cc2c8c5db75be685c3f31c64cdab639794f66f13f8e258ba6 \ + --hash=sha256:daf35ab13b86aba7cc8c4b019882f1fa8d287a26f586ef5eaf60a5233d3eaa52 \ + --hash=sha256:dbc32217c81d87750401fa1c2bc9450e854b23e6e30243c82d3514b8e58f39e3 \ + --hash=sha256:e175d74c52b6c8414a4b4504a2dd42b0202d101b2eb9508a34c137357683864e \ + --hash=sha256:e4a63ba6813a2168ebd35ea5369f6c33f7787525986cd77668b7956acc3d2a38 \ + --hash=sha256:e935712b17e7a42831022353bac91a346a792658a54e12bec907ec11695cc899 \ + --hash=sha256:ec94d29103317aa920dae59ed385de9604cb0ef840b5b7137b5eaa7a2042580a \ + --hash=sha256:ed6b3a0740efe98bb03ccf054578e9788ebcd06d021d548b8217ab2c82e45975 \ + --hash=sha256:f2a720e787c9b9b912db5bb4c3e7123ccff1352d6c3ac0cb2c7ee392cdc95c00 \ + --hash=sha256:f8822614975038e0cece47d12e7634a79c2ee590a0ae78ae64c37b9c6610a14c \ + --hash=sha256:fb1a884b1c6aeac5ffeb8ccb696fbc242a7ae1bba36f2328c01f76fab7221b94 # via motor python-dateutil==2.9.0.post0 \ --hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \ @@ -397,9 +397,9 @@ pyyaml==6.0.1 \ # via # hexkit # uvicorn -referencing==0.35.0 \ - --hash=sha256:191e936b0c696d0af17ad7430a3dc68e88bc11be6514f4757dc890f04ab05889 \ - --hash=sha256:8080727b30e364e5783152903672df9b6b091c926a146a759080b62ca3126cd6 +referencing==0.35.1 \ + --hash=sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c \ + --hash=sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de # via # jsonschema # jsonschema-specifications diff --git a/scripts/check_license.py b/scripts/check_license.py index 96a2c83..37103d8 100755 --- a/scripts/check_license.py +++ b/scripts/check_license.py @@ -40,7 +40,7 @@ ".git", ".github", ".flake8", - ".gitignore" ".pre-commit-config.yaml", + ".gitignore", ".mypy_cache", ".mypy.ini", ".pylintrc", @@ -115,8 +115,8 @@ See the License for the specific language governing permissions and limitations under the License.""" -# A list of all chars that may be used to introduce a comment: -COMMENT_CHARS = ["#"] +# A list of strings that may be used to introduce a line comment: +LINE_COMMENTS = ["#"] AUTHOR = """Universität Tübingen, DKFZ, EMBL, and Universität zu Köln for the German Human Genome-Phenome Archive (GHGA)""" @@ -202,24 +202,25 @@ def get_target_files( file_ for file_ in all_files if not ( - any([file_.is_relative_to(excl) for excl in exclude_normalized]) - or any([str(file_).endswith(ending) for ending in exclude_endings]) - or any([re.match(pattern, str(file_)) for pattern in exclude_pattern]) + any(file_.is_relative_to(excl) for excl in exclude_normalized) + or any(str(file_).endswith(ending) for ending in exclude_endings) + or any(re.match(pattern, str(file_)) for pattern in exclude_pattern) ) ] return target_files -def normalized_line(line: str, chars_to_trim: list[str] = COMMENT_CHARS) -> str: - norm_line = line.strip() +def normalized_line(line: str, line_comments: list[str] = LINE_COMMENTS) -> str: + line = line.strip() + for line_comment in line_comments: + line_without_comment = line.removeprefix(line_comment) + if line_without_comment != line: + line = line_without_comment.lstrip() + break + return line - for char in chars_to_trim: - norm_line = norm_line.strip(char) - return norm_line.strip("\n").strip("\t").strip() - - -def normalized_text(text: str, chars_to_trim: list[str] = COMMENT_CHARS) -> str: +def normalized_text(text: str, line_comments: list[str] = LINE_COMMENTS) -> str: "Normalize a license header text." lines = text.split("\n") @@ -231,7 +232,7 @@ def normalized_text(text: str, chars_to_trim: list[str] = COMMENT_CHARS) -> str: if stripped_line.startswith("#!"): continue - norm_line = normalized_line(stripped_line) + norm_line = normalized_line(stripped_line, line_comments=line_comments) # exclude empty lines: if norm_line == "": @@ -249,22 +250,17 @@ def format_copyright_template(copyright_template: str, author: str) -> str: return normalized_text(copyright_template.replace("{author}", author)) -def is_commented_line(line: str, comment_chars: list[str] = COMMENT_CHARS) -> bool: +def is_commented_line(line: str, line_comments: list[str] = LINE_COMMENTS) -> bool: """Checks whether a line is a comment.""" - line_stripped = line.strip() - for comment_char in comment_chars: - if line_stripped.startswith(comment_char): - return True - - return False + return line.lstrip().startswith(tuple(line_comments)) def is_empty_line(line: str) -> bool: """Checks whether a line is empty.""" - return line.strip("\n").strip("\t").strip() == "" + return not line.strip() -def get_header(file_path: Path, comment_chars: list[str] = COMMENT_CHARS): +def get_header(file_path: Path, line_comments: list[str] = LINE_COMMENTS): """Extracts the header from a file and normalizes it.""" header_lines: list[str] = [] @@ -272,7 +268,7 @@ def get_header(file_path: Path, comment_chars: list[str] = COMMENT_CHARS): with open(file_path) as file: for line in file: if is_commented_line( - line, comment_chars=comment_chars + line, line_comments=line_comments ) or is_empty_line(line): header_lines.append(line) else: @@ -282,7 +278,7 @@ def get_header(file_path: Path, comment_chars: list[str] = COMMENT_CHARS): # normalize the lines: header = "".join(header_lines) - return normalized_text(header, chars_to_trim=comment_chars) + return normalized_text(header, line_comments=line_comments) def validate_year_string(year_string: str, min_year: int = MIN_YEAR) -> bool: @@ -317,7 +313,7 @@ def check_copyright_notice( global_copyright: GlobalCopyrightNotice, copyright_template: str = COPYRIGHT_TEMPLATE, author: str = AUTHOR, - comment_chars: list[str] = COMMENT_CHARS, + line_comments: list[str] = LINE_COMMENTS, min_year: int = MIN_YEAR, ) -> bool: """Checks the specified copyright text against a template. @@ -385,7 +381,7 @@ def check_file_headers( exclude: list[str] = EXCLUDE, exclude_endings: list[str] = EXCLUDE_ENDINGS, exclude_pattern: list[str] = EXCLUDE_PATTERN, - comment_chars: list[str] = COMMENT_CHARS, + line_comments: list[str] = LINE_COMMENTS, min_year: int = MIN_YEAR, ) -> tuple[list[Path], list[Path]]: """Check files for presence of a license header and verify that @@ -429,13 +425,13 @@ def check_file_headers( for target_file in target_files: try: - header = get_header(target_file, comment_chars=comment_chars) + header = get_header(target_file, line_comments=line_comments) if check_copyright_notice( copyright=header, global_copyright=global_copyright, copyright_template=copyright_template, author=author, - comment_chars=comment_chars, + line_comments=line_comments, min_year=min_year, ): passed_files.append(target_file) @@ -453,7 +449,7 @@ def check_license_file( global_copyright: GlobalCopyrightNotice, copyright_template: str = COPYRIGHT_TEMPLATE, author: str = AUTHOR, - comment_chars: list[str] = COMMENT_CHARS, + line_comments: list[str] = LINE_COMMENTS, min_year: int = MIN_YEAR, ) -> bool: """Currently only checks if the copyright notice in the @@ -495,7 +491,7 @@ def check_license_file( global_copyright=global_copyright, copyright_template=copyright_template, author=author, - comment_chars=comment_chars, + line_comments=line_comments, min_year=min_year, ) diff --git a/src/nos/core/notifications.py b/src/nos/core/notifications.py index 3a15888..a6a17b1 100644 --- a/src/nos/core/notifications.py +++ b/src/nos/core/notifications.py @@ -28,6 +28,13 @@ "ACCESS_REQUEST_ALLOWED_TO_DS", "ACCESS_REQUEST_DENIED_TO_USER", "ACCESS_REQUEST_DENIED_TO_DS", + "FILE_REGISTERED_TO_DS", + "ALL_IVAS_INVALIDATED_TO_USER", + "IVA_CODE_REQUESTED_TO_USER", + "IVA_CODE_REQUESTED_TO_DS", + "IVA_CODE_TRANSMITTED_TO_USER", + "IVA_CODE_SUBMITTED_TO_DS", + "IVA_UNVERIFIED_TO_DS", ] @@ -126,3 +133,57 @@ def formatted(self, **kwargs) -> "Notification": "File upload completed", "The file {file_id} has been successfully uploaded.", ) + +ALL_IVAS_INVALIDATED_TO_USER = Notification( + "Contact Address Invalidation", + """ +All of your registered contact addresses now need re-verification due to the establishment +of a new 2nd authentication factor. + +If you have any questions, please contact a Data Steward at GHGA: {email}. +""", +) + +IVA_CODE_REQUESTED_TO_USER = Notification( + "Contact Address Verification Request Received", + """ +A verification code will be sent to you soon via the specified contact address. +""", +) + +IVA_CODE_REQUESTED_TO_DS = Notification( + "IVA Request Received", + """ +{full_user_name} has requested an IVA verification code. + +The specified contact email address is: {email}. +""", +) + +IVA_CODE_TRANSMITTED_TO_USER = Notification( + "Contact Address Verification Code Transmitted", + """ +A Data Steward has transmitted a verification code to the address specified by +your contact address. Please check for the verification code and submit it on the +GHGA Data Portal. +""", +) + +IVA_CODE_SUBMITTED_TO_DS = Notification( + "IVA Verification Code Submitted", + """ +{full_user_name} has submitted an IVA verification code for review. + +The specified contact email address is: {email}. +""", +) + +IVA_UNVERIFIED_TO_DS = Notification( + "IVA Unverified", + """ +The '{type}' IVA of {full_user_name} has been marked as unverified, due to too +many failed verification attempts. + +The specified contact email address is: {email}. +""", +) diff --git a/src/nos/core/orchestrator.py b/src/nos/core/orchestrator.py index 4d3467e..54c2775 100644 --- a/src/nos/core/orchestrator.py +++ b/src/nos/core/orchestrator.py @@ -17,6 +17,10 @@ """Contains the implementation of the Orchestrator class""" import logging +from collections.abc import Callable +from functools import partial + +from ghga_event_schemas import pydantic_ as event_schemas from nos.config import Config from nos.core import notifications @@ -53,7 +57,7 @@ async def process_access_request_notification( - MissingUserError: When the provided user ID does not exist in the DB. """ - method_map = { + method_map: dict[str, Callable] = { self._config.access_request_created_event_type: self._access_request_created, self._config.access_request_allowed_event_type: self._access_request_allowed, self._config.access_request_denied_event_type: self._access_request_denied, @@ -184,3 +188,135 @@ async def process_file_registered_notification(self, *, file_id: str): notification=notifications.FILE_REGISTERED_TO_DS.formatted(file_id=file_id), ) log.info("Sent File Upload Completed notification to data steward") + + async def _iva_code_requested(self, *, user: User): + """Send notifications relaying that an IVA code has been requested. + + One notification is sent to the user to confirm that their request was received. + + Another notification is sent to the data steward to inform them of the request. + """ + # Send a notification to the user + await self._notification_emitter.notify( + email=user.email, + full_name=user.name, + notification=notifications.IVA_CODE_REQUESTED_TO_USER, + ) + + # Send a notification to the data steward + await self._notification_emitter.notify( + email=self._config.central_data_stewardship_email, + full_name=DATA_STEWARD_NAME, + notification=notifications.IVA_CODE_REQUESTED_TO_DS.formatted( + full_user_name=user.name, email=user.email + ), + ) + + async def _iva_code_transmitted(self, *, user: User): + """Send a notification that an IVA code has been transmitted to the user.""" + await self._notification_emitter.notify( + email=user.email, + full_name=user.name, + notification=notifications.IVA_CODE_TRANSMITTED_TO_USER, + ) + + async def _iva_code_validated(self, *, user: User): + """Send a notification to the data steward that an IVA code has been validated.""" + await self._notification_emitter.notify( + email=self._config.central_data_stewardship_email, + full_name=DATA_STEWARD_NAME, + notification=notifications.IVA_CODE_SUBMITTED_TO_DS.formatted( + full_user_name=user.name, email=user.email + ), + ) + + async def _iva_unverified( + self, + *, + iva_type: str, + user: User, + ): + """Send notifications for IVAs set to 'unverified'. + + This happens when the user exceeds the allotted time to submit their IVA code. + """ + await self._notification_emitter.notify( + email=self._config.central_data_stewardship_email, + full_name=DATA_STEWARD_NAME, + notification=notifications.IVA_UNVERIFIED_TO_DS.formatted( + full_user_name=user.name, email=user.email, type=iva_type + ), + ) + + async def process_all_ivas_invalidated(self, *, user_id: str): + """Send a notification to the user when all their IVAs are reset.""" + try: + user = await self._user_dao.get_by_id(user_id) + except ResourceNotFoundError as err: + error = self.MissingUserError( + user_id=user_id, notification_name="All IVAs Invalidated" + ) + log.error( + error, + extra={"user_id": user_id, "notification_name": "All IVAs Invalidated"}, + ) + raise error from err + + await self._notification_emitter.notify( + email=user.email, + full_name=user.name, + notification=notifications.ALL_IVAS_INVALIDATED_TO_USER.formatted( + email=self._config.central_data_stewardship_email + ), + ) + + async def process_iva_state_change(self, *, user_iva: event_schemas.UserIvaState): + """Handle notifications for IVA state changes.""" + # Map IVA states to their corresponding notification methods and a name for logs + method_map: dict[event_schemas.IvaState, tuple[Callable, str]] = { + event_schemas.IvaState.CODE_REQUESTED: ( + self._iva_code_requested, + "IVA Code Requested", + ), + event_schemas.IvaState.CODE_TRANSMITTED: ( + self._iva_code_transmitted, + "IVA Code Transmitted", + ), + event_schemas.IvaState.VERIFIED: ( + self._iva_code_validated, + "IVA Code Validated", + ), + event_schemas.IvaState.UNVERIFIED: ( + partial( + self._iva_unverified, + iva_type=str(user_iva.type) if user_iva.type else "N/A", + ), + "IVA Unverified", + ), + } + + if user_iva.state not in method_map: + unexpected_iva_state_error = self.UnexpectedIvaState(state=user_iva.state) + log.error( + unexpected_iva_state_error, + extra={ + "user_id": user_iva.user_id, + }, + ) + raise unexpected_iva_state_error + + extra = { + "user_id": user_iva.user_id, + "notification_name": method_map[user_iva.state][1], + } + + try: + user = await self._user_dao.get_by_id(user_iva.user_id) + except ResourceNotFoundError as err: + error = self.MissingUserError( + user_id=user_iva.user_id, notification_name=extra["notification_name"] + ) + log.error(error, extra=extra) + raise error from err + + await method_map[user_iva.state][0](user=user) diff --git a/src/nos/ports/inbound/orchestrator.py b/src/nos/ports/inbound/orchestrator.py index 3d7da38..44c2602 100644 --- a/src/nos/ports/inbound/orchestrator.py +++ b/src/nos/ports/inbound/orchestrator.py @@ -18,6 +18,8 @@ from abc import ABC, abstractmethod +from ghga_event_schemas import pydantic_ as event_schemas + class OrchestratorPort(ABC): """A class that creates notification events from incoming event data.""" @@ -35,6 +37,13 @@ def __init__(self, *, user_id: str, notification_name: str) -> None: ) super().__init__(message) + class UnexpectedIvaState(RuntimeError): + """Raised when an unexpected IVA state is encountered.""" + + def __init__(self, *, state: str) -> None: + message = f"Unexpected IVA state '{state}' encountered." + super().__init__(message) + @abstractmethod async def process_access_request_notification( self, *, event_type: str, user_id: str, dataset_id: str @@ -49,3 +58,11 @@ async def process_access_request_notification( @abstractmethod async def process_file_registered_notification(self, *, file_id: str): """Send notifications for internal file registrations (completed uploads).""" + + @abstractmethod + async def process_all_ivas_invalidated(self, *, user_id: str): + """Handle notifications for all IVA resets.""" + + @abstractmethod + async def process_iva_state_change(self, *, user_iva: event_schemas.UserIvaState): + """Handle notifications for IVA state changes.""" diff --git a/src/nos/ports/outbound/dao.py b/src/nos/ports/outbound/dao.py index 2bbe330..ab61826 100644 --- a/src/nos/ports/outbound/dao.py +++ b/src/nos/ports/outbound/dao.py @@ -16,11 +16,11 @@ """DAO interface for accessing the database.""" -from hexkit.protocols.dao import DaoSurrogateId, ResourceNotFoundError +from hexkit.protocols.dao import DaoNaturalId, ResourceNotFoundError from nos.core import models __all__ = ["UserDaoPort", "ResourceNotFoundError"] # ports described by type aliases: -UserDaoPort = DaoSurrogateId[models.User, models.UserData] +UserDaoPort = DaoNaturalId[models.User] diff --git a/src/nos/translators/inbound/event_sub.py b/src/nos/translators/inbound/event_sub.py index 36d4ce3..52c87c6 100644 --- a/src/nos/translators/inbound/event_sub.py +++ b/src/nos/translators/inbound/event_sub.py @@ -58,6 +58,16 @@ class EventSubTranslatorConfig(BaseSettings): description="The type used for events detailing internally file registrations.", examples=["file_registered"], ) + iva_events_topic: str = Field( + default=..., + description="The name of the topic containing IVA events.", + examples=["ivas"], + ) + iva_state_changed_event_type: str = Field( + default=..., + description="The type to use for iva state changed events.", + examples=["iva_state_changed"], + ) class EventSubTranslator(EventSubscriberProtocol): @@ -69,12 +79,14 @@ def __init__( self.topics_of_interest = [ config.access_request_events_topic, config.file_registered_event_topic, + config.iva_events_topic, ] self.types_of_interest = [ config.access_request_created_event_type, config.access_request_allowed_event_type, config.access_request_denied_event_type, config.file_registered_event_type, + config.iva_state_changed_event_type, ] self._config = config self._orchestrator = orchestrator @@ -99,15 +111,33 @@ async def _handle_file_registered(self, payload: JsonObject) -> None: file_id=validated_payload.file_id ) + async def _handle_iva_state_change(self, payload: JsonObject) -> None: + """Send notifications for IVA state changes.""" + validated_payload = get_validated_payload(payload, event_schemas.UserIvaState) + await self._orchestrator.process_iva_state_change(user_iva=validated_payload) + + async def _handle_all_ivas_reset(self, payload: JsonObject) -> None: + """Send notifications for all IVA resets.""" + validated_payload = get_validated_payload(payload, event_schemas.UserIvaState) + await self._orchestrator.process_all_ivas_invalidated( + user_id=validated_payload.user_id + ) + async def _consume_validated( self, *, payload: JsonObject, type_: Ascii, topic: Ascii, key: Ascii ) -> None: """Consumes an event""" - if type_ in ( - self._config.access_request_created_event_type, - self._config.access_request_allowed_event_type, - self._config.access_request_denied_event_type, - ): - await self._handle_access_request(type_, payload) - elif type_ == self._config.file_registered_event_type: - await self._handle_file_registered(payload=payload) + match type_: + case _ if type_ in ( + self._config.access_request_created_event_type, + self._config.access_request_allowed_event_type, + self._config.access_request_denied_event_type, + ): + await self._handle_access_request(type_, payload) + case self._config.file_registered_event_type: + await self._handle_file_registered(payload=payload) + case self._config.iva_state_changed_event_type: + if key.startswith("all-"): + await self._handle_all_ivas_reset(payload=payload) + else: + await self._handle_iva_state_change(payload=payload) diff --git a/src/nos/translators/outbound/dao.py b/src/nos/translators/outbound/dao.py index 9ccf094..3b3027a 100644 --- a/src/nos/translators/outbound/dao.py +++ b/src/nos/translators/outbound/dao.py @@ -28,5 +28,4 @@ async def user_dao_factory(*, dao_factory: DaoFactoryProtocol) -> UserDaoPort: name="users", dto_model=models.User, id_field="id", - dto_creation_model=models.UserData, ) diff --git a/tests/conftest.py b/tests/conftest.py index 5cc4f90..a6fa703 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -19,13 +19,15 @@ from hexkit.providers.akafka.testutils import get_kafka_fixture from hexkit.providers.mongodb.testutils import get_mongodb_fixture -from nos.core.models import AcademicTitle, UserData +from nos.core.models import AcademicTitle, User from tests.fixtures.joint import JointFixture, get_joint_fixture mongodb_fixture = get_mongodb_fixture(scope="module") kafka_fixture = get_kafka_fixture(scope="module") joint_fixture = get_joint_fixture(scope="module") -TEST_USER = UserData(name="test user", title=AcademicTitle.DR, email="test@test.abc") +TEST_USER = User( + id="test", name="test user", title=AcademicTitle.DR, email="test@test.abc" +) @pytest_asyncio.fixture(autouse=True, scope="module") @@ -36,8 +38,6 @@ async def insert_test_data(joint_fixture: JointFixture): The ID-containing user is assigned as an attribute to the joint_fixture as well so the ID is easily accessible to tests. """ - user_with_id = await joint_fixture.user_dao.insert(TEST_USER) - joint_fixture.test_user = user_with_id + await joint_fixture.user_dao.insert(TEST_USER) yield - await joint_fixture.user_dao.delete(id_=user_with_id.id) - joint_fixture.test_user = None + await joint_fixture.user_dao.delete(id_=TEST_USER.id) diff --git a/tests/fixtures/joint.py b/tests/fixtures/joint.py index f507ccc..f3750d5 100644 --- a/tests/fixtures/joint.py +++ b/tests/fixtures/joint.py @@ -26,7 +26,6 @@ from hexkit.providers.mongodb.testutils import MongoDbFixture from nos.config import Config -from nos.core.models import User from nos.inject import prepare_core, prepare_event_subscriber from nos.ports.inbound.orchestrator import OrchestratorPort from nos.ports.outbound.dao import UserDaoPort @@ -44,7 +43,6 @@ class JointFixture: kafka: KafkaFixture mongodb: MongoDbFixture user_dao: UserDaoPort - test_user: User | None = None async def joint_fixture_function( diff --git a/tests/fixtures/test_config.yaml b/tests/fixtures/test_config.yaml index 27745f3..9b525e4 100644 --- a/tests/fixtures/test_config.yaml +++ b/tests/fixtures/test_config.yaml @@ -11,3 +11,5 @@ notification_event_type: notification notification_event_topic: notification_events file_registered_event_topic: internal_file_registry file_registered_event_type: file_registered +iva_events_topic: ivas +iva_state_changed_event_type: iva_state_changed diff --git a/tests/test_orchestrator.py b/tests/test_orchestrator.py index 87a4a9c..d9d3b84 100644 --- a/tests/test_orchestrator.py +++ b/tests/test_orchestrator.py @@ -37,6 +37,16 @@ def access_request_payload(user_id: str) -> dict[str, Any]: ).model_dump() +def iva_state_payload(user_id: str, state: event_schemas.IvaState) -> dict[str, Any]: + """Succinctly create the payload for an IVA state change event.""" + return event_schemas.UserIvaState( + user_id=user_id, + state=state, + value=None, + type=None, + ).model_dump() + + @pytest.mark.parametrize( "user_notification_content, user_kwargs, ds_notification_content, ds_kwargs, event_type", [ @@ -86,22 +96,18 @@ async def test_access_request( Test will also check idempotence. """ - assert joint_fixture.test_user is not None + test_user = await joint_fixture.user_dao.get_by_id(TEST_USER.id) - event_type_to_use = "" - if event_type == "created": - event_type_to_use = joint_fixture.config.access_request_created_event_type - elif event_type == "allowed": - event_type_to_use = joint_fixture.config.access_request_allowed_event_type - elif event_type == "denied": - event_type_to_use = joint_fixture.config.access_request_denied_event_type + event_type_to_use = getattr( + joint_fixture.config, f"access_request_{event_type}_event_type" + ) assert event_type_to_use user_notification = event_schemas.Notification( - recipient_email=joint_fixture.test_user.email, + recipient_email=test_user.email, subject=user_notification_content.subject, - recipient_name=joint_fixture.test_user.name, + recipient_name=test_user.name, plaintext_body=user_notification_content.text.format(**user_kwargs), ) @@ -116,7 +122,7 @@ async def test_access_request( ExpectedEvent( payload=user_notification.model_dump(), type_=joint_fixture.config.notification_event_type, - key=joint_fixture.test_user.email, + key=test_user.email, ), ExpectedEvent( payload=data_steward_notification.model_dump(), @@ -127,7 +133,7 @@ async def test_access_request( # Create the kafka event that would be published by the access request service await joint_fixture.kafka.publish_event( - payload=access_request_payload(joint_fixture.test_user.id), + payload=access_request_payload(test_user.id), type_=event_type_to_use, topic=joint_fixture.config.access_request_events_topic, ) @@ -141,7 +147,7 @@ async def test_access_request( # Publish and consume event again to check idempotence await joint_fixture.kafka.publish_event( - payload=access_request_payload(joint_fixture.test_user.id), + payload=access_request_payload(test_user.id), type_=event_type_to_use, topic=joint_fixture.config.access_request_events_topic, ) @@ -154,14 +160,58 @@ async def test_access_request( @pytest.mark.asyncio(scope="module") -async def test_missing_user_id(joint_fixture: JointFixture, logot: Logot): - """Test for error handling in case of invalid user id.""" +async def test_missing_user_id_access_requests( + joint_fixture: JointFixture, logot: Logot +): + """Test for error handling in case of invalid user id, specifically for the access + request events. + """ payload = access_request_payload("bogus_user_id") - for event_type in [ + + event_types = ( joint_fixture.config.access_request_created_event_type, joint_fixture.config.access_request_allowed_event_type, joint_fixture.config.access_request_denied_event_type, - ]: + ) + + for event_type in event_types: + await joint_fixture.kafka.publish_event( + payload=payload, + type_=event_type, + topic=joint_fixture.config.access_request_events_topic, + ) + + with pytest.raises(joint_fixture.orchestrator.MissingUserError): + await joint_fixture.event_subscriber.run(forever=False) + logot.assert_logged( + logged.error( + "Unable to publish %s notification as user ID %s was not found in" + + " the database." + ) + ) + + +@pytest.mark.asyncio(scope="module") +async def test_missing_user_id_iva_state_changes( + joint_fixture: JointFixture, logot: Logot +): + """Test for error handling in case of invalid user id, specifically for the IVA + state change events. + """ + payloads = ( + iva_state_payload("bogus_user_id", event_schemas.IvaState.CODE_REQUESTED), + iva_state_payload("bogus_user_id", event_schemas.IvaState.CODE_TRANSMITTED), + iva_state_payload("bogus_user_id", event_schemas.IvaState.VERIFIED), + iva_state_payload("bogus_user_id", event_schemas.IvaState.UNVERIFIED), + ) + + event_types = ( + joint_fixture.config.iva_state_changed_event_type, # requested + joint_fixture.config.iva_state_changed_event_type, # transmitted + joint_fixture.config.iva_state_changed_event_type, # verified + joint_fixture.config.iva_state_changed_event_type, # unverified + ) + for payload, event_type in zip(payloads, event_types, strict=True): await joint_fixture.kafka.publish_event( payload=payload, type_=event_type, @@ -225,3 +275,149 @@ async def test_file_registered(joint_fixture: JointFixture): in_topic=joint_fixture.config.notification_event_topic, ): await joint_fixture.event_subscriber.run(forever=False) + + +@pytest.mark.parametrize( + "iva_state,expected_user_notification,expected_ds_notification", + [ + ( + event_schemas.IvaState.CODE_REQUESTED, + notifications.IVA_CODE_REQUESTED_TO_USER, + notifications.IVA_CODE_REQUESTED_TO_DS, + ), + ( + event_schemas.IvaState.CODE_TRANSMITTED, + notifications.IVA_CODE_TRANSMITTED_TO_USER, + None, + ), + ( + event_schemas.IvaState.VERIFIED, + None, + notifications.IVA_CODE_SUBMITTED_TO_DS, + ), + ( + event_schemas.IvaState.UNVERIFIED, + None, + notifications.IVA_UNVERIFIED_TO_DS, + ), + ], +) +@pytest.mark.asyncio(scope="module") +async def test_iva_state_change( + joint_fixture: JointFixture, + iva_state: event_schemas.IvaState, + expected_user_notification: notifications.Notification | None, + expected_ds_notification: notifications.Notification | None, +): + """Test that the IVA state change events are translated into the proper notification. + + This does not check the wording or content of the notifications, only that the + correct notifications are generated for each state change. + """ + # Prepare triggering event (the IVA state change event). + trigger_event = event_schemas.UserIvaState( + user_id=TEST_USER.id, + state=iva_state, + value=None, + type=event_schemas.IvaType.FAX, + ) + + # Publish the trigger event + await joint_fixture.kafka.publish_event( + payload=trigger_event.model_dump(), + type_=joint_fixture.config.iva_state_changed_event_type, + topic=joint_fixture.config.iva_events_topic, + key=TEST_USER.id, + ) + + # Build a notification payload for the user, if applicable + user_notification = ( + event_schemas.Notification( + recipient_email=TEST_USER.email, + subject=expected_user_notification.subject, + recipient_name=TEST_USER.name, + plaintext_body=expected_user_notification.text, + ) + if expected_user_notification + else None + ) + + # Build a notification payload for the data steward, if applicable + data_steward_notification = ( + event_schemas.Notification( + recipient_email=joint_fixture.config.central_data_stewardship_email, + subject=expected_ds_notification.subject, + recipient_name="Data Steward", + plaintext_body=expected_ds_notification.text.format( + full_user_name=TEST_USER.name, + email=TEST_USER.email, + type=trigger_event.type, + ), + ) + if expected_ds_notification + else None + ) + + # Combine the two notifications into a list of expected events + expected_events = [] + for notification in [user_notification, data_steward_notification]: + if notification: + expected_events.append( + ExpectedEvent( + payload=notification.model_dump(), + type_=joint_fixture.config.notification_event_type, + ) + ) + + # Consume the event and verify that the expected events are published + async with joint_fixture.kafka.expect_events( + events=expected_events, + in_topic=joint_fixture.config.notification_event_topic, + ): + await joint_fixture.event_subscriber.run(forever=False) + + +@pytest.mark.asyncio(scope="module") +async def test_all_ivas_reset(joint_fixture: JointFixture): + """Test that the 'all IVA invalidated' events are translated into a notification.""" + # Prepare triggering event (the IVA state change event). + trigger_event = event_schemas.UserIvaState( + user_id=TEST_USER.id, + state=event_schemas.IvaState.UNVERIFIED, + value=None, + type=None, + ) + + # Publish the trigger event + await joint_fixture.kafka.publish_event( + payload=trigger_event.model_dump(), + type_=joint_fixture.config.iva_state_changed_event_type, + topic=joint_fixture.config.iva_events_topic, + key=f"all-{TEST_USER.id}", + ) + + # Define the event that should be published by the NOS when the trigger is consumed + ds_email = joint_fixture.config.central_data_stewardship_email + expected_notification = event_schemas.Notification( + recipient_email=TEST_USER.email, + recipient_name=TEST_USER.name, + subject="Contact Address Invalidation", + plaintext_body=f""" +All of your registered contact addresses now need re-verification due to the establishment +of a new 2nd authentication factor. + +If you have any questions, please contact a Data Steward at GHGA: {ds_email}. +""", + ) + + expected_event = ExpectedEvent( + payload=expected_notification.model_dump(), + type_=joint_fixture.config.notification_event_type, + ) + + # consume the event and verify that the expected event is published + async with joint_fixture.kafka.expect_events( + events=[expected_event], + in_topic=joint_fixture.config.notification_event_topic, + ): + await joint_fixture.event_subscriber.run(forever=False)