From 0f41d64e0e342098598b4023e98dccc60a09787b Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Thu, 1 Feb 2024 12:01:49 -0800 Subject: [PATCH 01/31] Update order of the column headers --- src/registrar/utility/csv_export.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/registrar/utility/csv_export.py b/src/registrar/utility/csv_export.py index f9608f553..1ea9131e0 100644 --- a/src/registrar/utility/csv_export.py +++ b/src/registrar/utility/csv_export.py @@ -77,6 +77,8 @@ def parse_row(columns, domain_info: DomainInformation, security_emails_dict=None # create a dictionary of fields which can be included in output FIELDS = { "Domain name": domain.name, + "Status": domain.get_state_display(), + "Expiration date": domain.expiration_date, "Domain type": domain_type, "Agency": domain_info.federal_agency, "Organization name": domain_info.organization_name, @@ -85,8 +87,6 @@ def parse_row(columns, domain_info: DomainInformation, security_emails_dict=None "AO": domain_info.ao, # type: ignore "AO email": domain_info.authorizing_official.email if domain_info.authorizing_official else " ", "Security contact email": security_email, - "Status": domain.get_state_display(), - "Expiration date": domain.expiration_date, "Created at": domain.created_at, "First ready": domain.first_ready, "Deleted": domain.deleted, @@ -152,6 +152,8 @@ def export_data_type_to_csv(csv_file): # define columns to include in export columns = [ "Domain name", + "Status", + "Expiration date", "Domain type", "Agency", "Organization name", @@ -160,8 +162,6 @@ def export_data_type_to_csv(csv_file): "AO", "AO email", "Security contact email", - "Status", - "Expiration date", ] # Coalesce is used to replace federal_type of None with ZZZZZ sort_fields = [ From a9302a8428a40a3126e74db7d1699e914d404132 Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Tue, 6 Feb 2024 11:08:42 -0800 Subject: [PATCH 02/31] Get all emails for domain managers and matching header title to be dynamic --- src/registrar/utility/csv_export.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/registrar/utility/csv_export.py b/src/registrar/utility/csv_export.py index 1ea9131e0..c6e278254 100644 --- a/src/registrar/utility/csv_export.py +++ b/src/registrar/utility/csv_export.py @@ -17,7 +17,7 @@ logger = logging.getLogger(__name__) def write_header(writer, columns): """ Receives params from the parent methods and outputs a CSV with a header row. - Works with write_header as longas the same writer object is passed. + Works with write_header as long as the same writer object is passed. """ writer.writerow(columns) @@ -92,6 +92,13 @@ def parse_row(columns, domain_info: DomainInformation, security_emails_dict=None "Deleted": domain.deleted, } + # Get each domain managers email and add to list + dm_emails = [dm.email for dm in domain.permissions] + + # Matching header for domain managers to be dynamic + for i, dm_email in enumerate(dm_emails, start=1): + FIELDS[f"Domain Manager email {i}":dm_email] + row = [FIELDS.get(column, "") for column in columns] return row From 7f7e61ccc1d8a5200612bb4d516f707a932c11f5 Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Tue, 6 Feb 2024 11:52:04 -0800 Subject: [PATCH 03/31] Add logic for domain manager title in header --- src/registrar/utility/csv_export.py | 30 ++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/registrar/utility/csv_export.py b/src/registrar/utility/csv_export.py index c6e278254..9fe62bfcc 100644 --- a/src/registrar/utility/csv_export.py +++ b/src/registrar/utility/csv_export.py @@ -14,11 +14,16 @@ from registrar.models.public_contact import PublicContact logger = logging.getLogger(__name__) -def write_header(writer, columns): +def write_header(writer, columns, max_dm_count): """ Receives params from the parent methods and outputs a CSV with a header row. Works with write_header as long as the same writer object is passed. """ + + for i in range(1, max_dm_count + 1): + columns.append(f"Domain manager email {i}") + + writer.writerow("hello") writer.writerow(columns) @@ -134,12 +139,22 @@ def write_body( else: logger.warning("csv_export -> Domain was none for PublicContact") + # The maximum amount of domain managers an account has + # We get the max so we can set the column header accurately + max_dm_count = 0 + paginator_ran = False + # Reduce the memory overhead when performing the write operation paginator = Paginator(all_domain_infos, 1000) for page_num in paginator.page_range: page = paginator.page(page_num) rows = [] for domain_info in page.object_list: + # Get count of all the domain managers for an account + dm_count = len(domain_info.domain.permissions) + if dm_count > max_dm_count: + max_dm_count = dm_count + try: row = parse_row(columns, domain_info, security_emails_dict) rows.append(row) @@ -149,7 +164,12 @@ def write_body( logger.error("csv_export -> Error when parsing row, domain was None") continue + # We only want this to run once just for the column header + if paginator_ran is False: + write_header(writer, columns, max_dm_count) + writer.writerows(rows) + paginator_ran = True def export_data_type_to_csv(csv_file): @@ -184,7 +204,7 @@ def export_data_type_to_csv(csv_file): Domain.State.ON_HOLD, ], } - write_header(writer, columns) + # write_header(writer, columns) write_body(writer, columns, sort_fields, filter_condition) @@ -216,7 +236,7 @@ def export_data_full_to_csv(csv_file): Domain.State.ON_HOLD, ], } - write_header(writer, columns) + # write_header(writer, columns) write_body(writer, columns, sort_fields, filter_condition) @@ -249,7 +269,7 @@ def export_data_federal_to_csv(csv_file): Domain.State.ON_HOLD, ], } - write_header(writer, columns) + # write_header(writer, columns) write_body(writer, columns, sort_fields, filter_condition) @@ -317,6 +337,6 @@ def export_data_growth_to_csv(csv_file, start_date, end_date): "domain__deleted__gte": start_date_formatted, } - write_header(writer, columns) + # write_header(writer, columns) write_body(writer, columns, sort_fields, filter_condition) write_body(writer, columns, sort_fields_for_deleted_domains, filter_condition_for_deleted_domains) From 029f28aaf40ab72b1ab6c2066152629659a434bf Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Tue, 6 Feb 2024 13:18:05 -0800 Subject: [PATCH 04/31] Testing chanegs to trigger sandbox --- src/registrar/templates/home.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/templates/home.html b/src/registrar/templates/home.html index c7a005f97..21cb1e301 100644 --- a/src/registrar/templates/home.html +++ b/src/registrar/templates/home.html @@ -10,7 +10,7 @@ {# the entire logged in page goes here #}
-

Manage your domains

+

Manage your domains - Test Trigger Here

Date: Tue, 6 Feb 2024 14:04:43 -0800 Subject: [PATCH 05/31] Test an open column title --- src/registrar/utility/csv_export.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/registrar/utility/csv_export.py b/src/registrar/utility/csv_export.py index fcbce470d..64afd2d06 100644 --- a/src/registrar/utility/csv_export.py +++ b/src/registrar/utility/csv_export.py @@ -189,7 +189,14 @@ def export_data_type_to_csv(csv_file): "AO", "AO email", "Security contact email", + "Domain Manager email", ] + + # STUCK HERE + + # So the problem is we don't even have access to domains or a count here. + # We could pass it in, but it's messy. Maybe helper function? Seems repetitive + # Coalesce is used to replace federal_type of None with ZZZZZ sort_fields = [ "organization_type", From 823f134687296cd351a152da7767a8d84b7ff5f4 Mon Sep 17 00:00:00 2001 From: CocoByte Date: Wed, 7 Feb 2024 14:54:28 -0700 Subject: [PATCH 06/31] Test update to Django 4.2.3 --- src/Pipfile | 2 +- src/Pipfile.lock | 1139 ++++++++++++++++++++---------------------- src/requirements.txt | 46 +- 3 files changed, 570 insertions(+), 617 deletions(-) diff --git a/src/Pipfile b/src/Pipfile index d4a9bbafb..a0ada646a 100644 --- a/src/Pipfile +++ b/src/Pipfile @@ -4,7 +4,7 @@ verify_ssl = true name = "pypi" [packages] -django = "*" +django = "4.2.3" cfenv = "*" django-cors-headers = "*" pycryptodomex = "*" diff --git a/src/Pipfile.lock b/src/Pipfile.lock index d265123de..3ac2fad0e 100644 --- a/src/Pipfile.lock +++ b/src/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "a0ea45d8f77132e22b8c3437e90903240af1bb29f9994f6ce4ce1e5b8d06b6ed" + "sha256": "8db8d1bdb9c343c50771fc8bd001c555037dc3606a48dcafb3800d743fb95f3e" }, "pipfile-spec": 6, "requires": {}, @@ -32,20 +32,20 @@ }, "boto3": { "hashes": [ - "sha256:d12467fb3a64d359b0bda0570a8163a5859fcac13e786f2a3db0392523178556", - "sha256:eed0f7df91066b6ac63a53d16459ac082458d57061bedf766135d9e1c2b75a6b" + "sha256:65acfe7f1cf2a9b7df3d4edb87c8022e02685825bd1957e7bb678cc0d09f5e5f", + "sha256:73f5ec89cb3ddb3ed577317889fd2f2df783f66b6502a9a4239979607e33bf74" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==1.33.7" + "markers": "python_version >= '3.8'", + "version": "==1.34.37" }, "botocore": { "hashes": [ - "sha256:71ec0e85b996cf9def3dd8f4ca6cb4a9fd3a614aa4c9c7cbf33f2f68e1d0649a", - "sha256:b2299bc13bb8c0928edc98bf4594deb14cba2357536120f63772027a16ce7374" + "sha256:2a5bf33aacd2d970afd3d492e179e06ea98a5469030d5cfe7a2ad9995f7bb2ef", + "sha256:3c46ddb1679e6ef45ca78b48665398636bda532a07cd476e4b500697d13d9a99" ], - "markers": "python_version >= '3.7'", - "version": "==1.33.7" + "markers": "python_version >= '3.8'", + "version": "==1.34.37" }, "cachetools": { "hashes": [ @@ -58,11 +58,11 @@ }, "certifi": { "hashes": [ - "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1", - "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474" + "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f", + "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" ], "markers": "python_version >= '3.6'", - "version": "==2023.11.17" + "version": "==2024.2.2" }, "cfenv": { "hashes": [ @@ -127,7 +127,7 @@ "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956", "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357" ], - "markers": "python_version >= '3.8'", + "markers": "platform_python_implementation != 'PyPy'", "version": "==1.16.0" }, "charset-normalizer": { @@ -228,32 +228,41 @@ }, "cryptography": { "hashes": [ - "sha256:079b85658ea2f59c4f43b70f8119a52414cdb7be34da5d019a77bf96d473b960", - "sha256:09616eeaef406f99046553b8a40fbf8b1e70795a91885ba4c96a70793de5504a", - "sha256:13f93ce9bea8016c253b34afc6bd6a75993e5c40672ed5405a9c832f0d4a00bc", - "sha256:37a138589b12069efb424220bf78eac59ca68b95696fc622b6ccc1c0a197204a", - "sha256:3c78451b78313fa81607fa1b3f1ae0a5ddd8014c38a02d9db0616133987b9cdf", - "sha256:43f2552a2378b44869fe8827aa19e69512e3245a219104438692385b0ee119d1", - "sha256:48a0476626da912a44cc078f9893f292f0b3e4c739caf289268168d8f4702a39", - "sha256:49f0805fc0b2ac8d4882dd52f4a3b935b210935d500b6b805f321addc8177406", - "sha256:5429ec739a29df2e29e15d082f1d9ad683701f0ec7709ca479b3ff2708dae65a", - "sha256:5a1b41bc97f1ad230a41657d9155113c7521953869ae57ac39ac7f1bb471469a", - "sha256:68a2dec79deebc5d26d617bfdf6e8aab065a4f34934b22d3b5010df3ba36612c", - "sha256:7a698cb1dac82c35fcf8fe3417a3aaba97de16a01ac914b89a0889d364d2f6be", - "sha256:841df4caa01008bad253bce2a6f7b47f86dc9f08df4b433c404def869f590a15", - "sha256:90452ba79b8788fa380dfb587cca692976ef4e757b194b093d845e8d99f612f2", - "sha256:928258ba5d6f8ae644e764d0f996d61a8777559f72dfeb2eea7e2fe0ad6e782d", - "sha256:af03b32695b24d85a75d40e1ba39ffe7db7ffcb099fe507b39fd41a565f1b157", - "sha256:b640981bf64a3e978a56167594a0e97db71c89a479da8e175d8bb5be5178c003", - "sha256:c5ca78485a255e03c32b513f8c2bc39fedb7f5c5f8535545bdc223a03b24f248", - "sha256:c7f3201ec47d5207841402594f1d7950879ef890c0c495052fa62f58283fde1a", - "sha256:d5ec85080cce7b0513cfd233914eb8b7bbd0633f1d1703aa28d1dd5a72f678ec", - "sha256:d6c391c021ab1f7a82da5d8d0b3cee2f4b2c455ec86c8aebbc84837a631ff309", - "sha256:e3114da6d7f95d2dee7d3f4eec16dacff819740bbab931aff8648cb13c5ff5e7", - "sha256:f983596065a18a2183e7f79ab3fd4c475205b839e02cbc0efbbf9666c4b3083d" + "sha256:087887e55e0b9c8724cf05361357875adb5c20dec27e5816b653492980d20380", + "sha256:09a77e5b2e8ca732a19a90c5bca2d124621a1edb5438c5daa2d2738bfeb02589", + "sha256:130c0f77022b2b9c99d8cebcdd834d81705f61c68e91ddd614ce74c657f8b3ea", + "sha256:141e2aa5ba100d3788c0ad7919b288f89d1fe015878b9659b307c9ef867d3a65", + "sha256:28cb2c41f131a5758d6ba6a0504150d644054fd9f3203a1e8e8d7ac3aea7f73a", + "sha256:2f9f14185962e6a04ab32d1abe34eae8a9001569ee4edb64d2304bf0d65c53f3", + "sha256:320948ab49883557a256eab46149df79435a22d2fefd6a66fe6946f1b9d9d008", + "sha256:36d4b7c4be6411f58f60d9ce555a73df8406d484ba12a63549c88bd64f7967f1", + "sha256:3b15c678f27d66d247132cbf13df2f75255627bcc9b6a570f7d2fd08e8c081d2", + "sha256:3dbd37e14ce795b4af61b89b037d4bc157f2cb23e676fa16932185a04dfbf635", + "sha256:4383b47f45b14459cab66048d384614019965ba6c1a1a141f11b5a551cace1b2", + "sha256:44c95c0e96b3cb628e8452ec060413a49002a247b2b9938989e23a2c8291fc90", + "sha256:4b063d3413f853e056161eb0c7724822a9740ad3caa24b8424d776cebf98e7ee", + "sha256:52ed9ebf8ac602385126c9a2fe951db36f2cb0c2538d22971487f89d0de4065a", + "sha256:55d1580e2d7e17f45d19d3b12098e352f3a37fe86d380bf45846ef257054b242", + "sha256:5ef9bc3d046ce83c4bbf4c25e1e0547b9c441c01d30922d812e887dc5f125c12", + "sha256:5fa82a26f92871eca593b53359c12ad7949772462f887c35edaf36f87953c0e2", + "sha256:61321672b3ac7aade25c40449ccedbc6db72c7f5f0fdf34def5e2f8b51ca530d", + "sha256:701171f825dcab90969596ce2af253143b93b08f1a716d4b2a9d2db5084ef7be", + "sha256:841ec8af7a8491ac76ec5a9522226e287187a3107e12b7d686ad354bb78facee", + "sha256:8a06641fb07d4e8f6c7dda4fc3f8871d327803ab6542e33831c7ccfdcb4d0ad6", + "sha256:8e88bb9eafbf6a4014d55fb222e7360eef53e613215085e65a13290577394529", + "sha256:a00aee5d1b6c20620161984f8ab2ab69134466c51f58c052c11b076715e72929", + "sha256:a047682d324ba56e61b7ea7c7299d51e61fd3bca7dad2ccc39b72bd0118d60a1", + "sha256:a7ef8dd0bf2e1d0a27042b231a3baac6883cdd5557036f5e8df7139255feaac6", + "sha256:ad28cff53f60d99a928dfcf1e861e0b2ceb2bc1f08a074fdd601b314e1cc9e0a", + "sha256:b9097a208875fc7bbeb1286d0125d90bdfed961f61f214d3f5be62cd4ed8a446", + "sha256:b97fe7d7991c25e6a31e5d5e795986b18fbbb3107b873d5f3ae6dc9a103278e9", + "sha256:e0ec52ba3c7f1b7d813cd52649a5b3ef1fc0d433219dc8c93827c57eab6cf888", + "sha256:ea2c3ffb662fec8bbbfce5602e2c159ff097a4631d96235fcf0fb00e59e3ece4", + "sha256:fa3dec4ba8fb6e662770b74f62f1a0c7d4e37e25b58b2bf2c1be4c95372b4a33", + "sha256:fbeb725c9dc799a574518109336acccaf1303c30d45c075c665c0793c2f79a7f" ], "markers": "python_version >= '3.7'", - "version": "==41.0.7" + "version": "==42.0.2" }, "defusedxml": { "hashes": [ @@ -279,12 +288,12 @@ }, "django": { "hashes": [ - "sha256:8e0f1c2c2786b5c0e39fe1afce24c926040fad47c8ea8ad30aaf1188df29fc41", - "sha256:e1d37c51ad26186de355cbcec16613ebdabfa9689bbade9c538835205a8abbe9" + "sha256:45a747e1c5b3d6df1b141b1481e193b033fd1fdbda3ff52677dc81afdaacbaed", + "sha256:f7c7852a5ac5a3da5a8d5b35cc6168f31b605971441798dac845f17ca8028039" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.2.7" + "version": "==4.2.3" }, "django-allow-cidr": { "hashes": [ @@ -347,11 +356,11 @@ "phonenumberslite" ], "hashes": [ - "sha256:16778f2717ea2aecc6178beb0d6bc431c78c6a8b0474e1fa8face040efeb6e9e", - "sha256:20c7c5c449e33eed5fd45ef8d3dc668faabaeff3277eddd1892b262d686ba381" + "sha256:bc6eaa49d1f9d870944f5280258db511e3a1ba5e2fbbed255488dceacae45d06", + "sha256:f9cdb3de085f99c249328293a3b93d4e5fa440c0c8e3b99eb0d0f54748629797" ], "markers": "python_version >= '3.8'", - "version": "==7.2.0" + "version": "==7.3.0" }, "django-widget-tweaks": { "hashes": [ @@ -367,19 +376,20 @@ "django" ], "hashes": [ - "sha256:1e549569a3de49c05f856f40bce86979e7d5ffbbc4398e7f338574c220189124", - "sha256:a76307b36fbe856bdca7ee9161e6c466fd7fcffc297109a118c59b54e27e30c9" + "sha256:cc421ddb143fa30183568164755aa113a160e555cd19e97e664c478662032c24", + "sha256:feeaf28f17fd0499f9cd7c0fcf408c6d82c308e69e335eb92d09322fc9ed8138" ], - "markers": "python_version >= '3.6'", - "version": "==9.5.0" + "markers": "python_version >= '3.8'", + "version": "==10.3.0" }, "faker": { "hashes": [ - "sha256:562a3a09c3ed3a1a7b20e13d79f904dfdfc5e740f72813ecf95e4cf71e5a2f52", - "sha256:aeb3e26742863d1e387f9d156f1c36e14af63bf5e6f36fb39b8c27f6a903be38" + "sha256:60e89e5c0b584e285a7db05eceba35011a241954afdab2853cb246c8a56700a2", + "sha256:b7f76bb1b2ac4cdc54442d955e36e477c387000f31ce46887fb9722a041be60b" ], + "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==20.1.0" + "version": "==23.1.0" }, "fred-epplib": { "git": "https://github.com/cisagov/epplib.git", @@ -448,71 +458,72 @@ }, "geventconnpool": { "git": "https://github.com/rasky/geventconnpool.git", - "ref": "1bbb93a714a331a069adf27265fe582d9ba7ecd4" + "ref": null }, "greenlet": { "hashes": [ - "sha256:0a02d259510b3630f330c86557331a3b0e0c79dac3d166e449a39363beaae174", - "sha256:0b6f9f8ca7093fd4433472fd99b5650f8a26dcd8ba410e14094c1e44cd3ceddd", - "sha256:100f78a29707ca1525ea47388cec8a049405147719f47ebf3895e7509c6446aa", - "sha256:1757936efea16e3f03db20efd0cd50a1c86b06734f9f7338a90c4ba85ec2ad5a", - "sha256:19075157a10055759066854a973b3d1325d964d498a805bb68a1f9af4aaef8ec", - "sha256:19bbdf1cce0346ef7341705d71e2ecf6f41a35c311137f29b8a2dc2341374565", - "sha256:20107edf7c2c3644c67c12205dc60b1bb11d26b2610b276f97d666110d1b511d", - "sha256:22f79120a24aeeae2b4471c711dcf4f8c736a2bb2fabad2a67ac9a55ea72523c", - "sha256:2847e5d7beedb8d614186962c3d774d40d3374d580d2cbdab7f184580a39d234", - "sha256:28e89e232c7593d33cac35425b58950789962011cc274aa43ef8865f2e11f46d", - "sha256:329c5a2e5a0ee942f2992c5e3ff40be03e75f745f48847f118a3cfece7a28546", - "sha256:337322096d92808f76ad26061a8f5fccb22b0809bea39212cd6c406f6a7060d2", - "sha256:3fcc780ae8edbb1d050d920ab44790201f027d59fdbd21362340a85c79066a74", - "sha256:41bdeeb552d814bcd7fb52172b304898a35818107cc8778b5101423c9017b3de", - "sha256:4eddd98afc726f8aee1948858aed9e6feeb1758889dfd869072d4465973f6bfd", - "sha256:52e93b28db27ae7d208748f45d2db8a7b6a380e0d703f099c949d0f0d80b70e9", - "sha256:55d62807f1c5a1682075c62436702aaba941daa316e9161e4b6ccebbbf38bda3", - "sha256:5805e71e5b570d490938d55552f5a9e10f477c19400c38bf1d5190d760691846", - "sha256:599daf06ea59bfedbec564b1692b0166a0045f32b6f0933b0dd4df59a854caf2", - "sha256:60d5772e8195f4e9ebf74046a9121bbb90090f6550f81d8956a05387ba139353", - "sha256:696d8e7d82398e810f2b3622b24e87906763b6ebfd90e361e88eb85b0e554dc8", - "sha256:6e6061bf1e9565c29002e3c601cf68569c450be7fc3f7336671af7ddb4657166", - "sha256:80ac992f25d10aaebe1ee15df45ca0d7571d0f70b645c08ec68733fb7a020206", - "sha256:816bd9488a94cba78d93e1abb58000e8266fa9cc2aa9ccdd6eb0696acb24005b", - "sha256:85d2b77e7c9382f004b41d9c72c85537fac834fb141b0296942d52bf03fe4a3d", - "sha256:87c8ceb0cf8a5a51b8008b643844b7f4a8264a2c13fcbcd8a8316161725383fe", - "sha256:89ee2e967bd7ff85d84a2de09df10e021c9b38c7d91dead95b406ed6350c6997", - "sha256:8bef097455dea90ffe855286926ae02d8faa335ed8e4067326257cb571fc1445", - "sha256:8d11ebbd679e927593978aa44c10fc2092bc454b7d13fdc958d3e9d508aba7d0", - "sha256:91e6c7db42638dc45cf2e13c73be16bf83179f7859b07cfc139518941320be96", - "sha256:97e7ac860d64e2dcba5c5944cfc8fa9ea185cd84061c623536154d5a89237884", - "sha256:990066bff27c4fcf3b69382b86f4c99b3652bab2a7e685d968cd4d0cfc6f67c6", - "sha256:9fbc5b8f3dfe24784cee8ce0be3da2d8a79e46a276593db6868382d9c50d97b1", - "sha256:ac4a39d1abae48184d420aa8e5e63efd1b75c8444dd95daa3e03f6c6310e9619", - "sha256:b2c02d2ad98116e914d4f3155ffc905fd0c025d901ead3f6ed07385e19122c94", - "sha256:b2d3337dcfaa99698aa2377c81c9ca72fcd89c07e7eb62ece3f23a3fe89b2ce4", - "sha256:b489c36d1327868d207002391f662a1d163bdc8daf10ab2e5f6e41b9b96de3b1", - "sha256:b641161c302efbb860ae6b081f406839a8b7d5573f20a455539823802c655f63", - "sha256:b8ba29306c5de7717b5761b9ea74f9c72b9e2b834e24aa984da99cbfc70157fd", - "sha256:b9934adbd0f6e476f0ecff3c94626529f344f57b38c9a541f87098710b18af0a", - "sha256:ce85c43ae54845272f6f9cd8320d034d7a946e9773c693b27d620edec825e376", - "sha256:cf868e08690cb89360eebc73ba4be7fb461cfbc6168dd88e2fbbe6f31812cd57", - "sha256:d2905ce1df400360463c772b55d8e2518d0e488a87cdea13dd2c71dcb2a1fa16", - "sha256:d57e20ba591727da0c230ab2c3f200ac9d6d333860d85348816e1dca4cc4792e", - "sha256:d6a8c9d4f8692917a3dc7eb25a6fb337bff86909febe2f793ec1928cd97bedfc", - "sha256:d923ff276f1c1f9680d32832f8d6c040fe9306cbfb5d161b0911e9634be9ef0a", - "sha256:daa7197b43c707462f06d2c693ffdbb5991cbb8b80b5b984007de431493a319c", - "sha256:dbd4c177afb8a8d9ba348d925b0b67246147af806f0b104af4d24f144d461cd5", - "sha256:dc4d815b794fd8868c4d67602692c21bf5293a75e4b607bb92a11e821e2b859a", - "sha256:e9d21aaa84557d64209af04ff48e0ad5e28c5cca67ce43444e939579d085da72", - "sha256:ea6b8aa9e08eea388c5f7a276fabb1d4b6b9d6e4ceb12cc477c3d352001768a9", - "sha256:eabe7090db68c981fca689299c2d116400b553f4b713266b130cfc9e2aa9c5a9", - "sha256:f2f6d303f3dee132b322a14cd8765287b8f86cdc10d2cb6a6fae234ea488888e", - "sha256:f33f3258aae89da191c6ebaa3bc517c6c4cbc9b9f689e5d8452f7aedbb913fa8", - "sha256:f7bfb769f7efa0eefcd039dd19d843a4fbfbac52f1878b1da2ed5793ec9b1a65", - "sha256:f89e21afe925fcfa655965ca8ea10f24773a1791400989ff32f467badfe4a064", - "sha256:fa24255ae3c0ab67e613556375a4341af04a084bd58764731972bcbc8baeba36" + "sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67", + "sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6", + "sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257", + "sha256:098d86f528c855ead3479afe84b49242e174ed262456c342d70fc7f972bc13c4", + "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676", + "sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61", + "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc", + "sha256:1996cb9306c8595335bb157d133daf5cf9f693ef413e7673cb07e3e5871379ca", + "sha256:1a7191e42732df52cb5f39d3527217e7ab73cae2cb3694d241e18f53d84ea9a7", + "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728", + "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305", + "sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6", + "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379", + "sha256:2dd6e660effd852586b6a8478a1d244b8dc90ab5b1321751d2ea15deb49ed414", + "sha256:3ddc0f794e6ad661e321caa8d2f0a55ce01213c74722587256fb6566049a8b04", + "sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a", + "sha256:419b386f84949bf0e7c73e6032e3457b82a787c1ab4a0e43732898a761cc9dbf", + "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491", + "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559", + "sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e", + "sha256:5b51e85cb5ceda94e79d019ed36b35386e8c37d22f07d6a751cb659b180d5274", + "sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb", + "sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b", + "sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9", + "sha256:6b66c9c1e7ccabad3a7d037b2bcb740122a7b17a53734b7d72a344ce39882a1b", + "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be", + "sha256:7170375bcc99f1a2fbd9c306f5be8764eaf3ac6b5cb968862cad4c7057756506", + "sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405", + "sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113", + "sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f", + "sha256:81bb9c6d52e8321f09c3d165b2a78c680506d9af285bfccbad9fb7ad5a5da3e5", + "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230", + "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d", + "sha256:99bf650dc5d69546e076f413a87481ee1d2d09aaaaaca058c9251b6d8c14783f", + "sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a", + "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e", + "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61", + "sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6", + "sha256:b542be2440edc2d48547b5923c408cbe0fc94afb9f18741faa6ae970dbcb9b6d", + "sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71", + "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22", + "sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2", + "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3", + "sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067", + "sha256:c9db1c18f0eaad2f804728c67d6c610778456e3e1cc4ab4bbd5eeb8e6053c6fc", + "sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881", + "sha256:d46677c85c5ba00a9cb6f7a00b2bfa6f812192d2c9f7d9c4f6a55b60216712f3", + "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e", + "sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac", + "sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53", + "sha256:daf3cb43b7cf2ba96d614252ce1684c1bccee6b2183a01328c98d36fcd7d5cb0", + "sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b", + "sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83", + "sha256:e1f145462f1fa6e4a4ae3c0f782e580ce44d57c8f2c7aae1b6fa88c0b2efdb41", + "sha256:e3391d1e16e2a5a1507d83e4a8b100f4ee626e8eca43cf2cadb543de69827c4c", + "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf", + "sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da", + "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==3.0.1" + "version": "==3.0.3" }, "gunicorn": { "hashes": [ @@ -541,183 +552,169 @@ }, "lxml": { "hashes": [ - "sha256:05186a0f1346ae12553d66df1cfce6f251589fea3ad3da4f3ef4e34b2d58c6a3", - "sha256:075b731ddd9e7f68ad24c635374211376aa05a281673ede86cbe1d1b3455279d", - "sha256:081d32421db5df44c41b7f08a334a090a545c54ba977e47fd7cc2deece78809a", - "sha256:0a3d3487f07c1d7f150894c238299934a2a074ef590b583103a45002035be120", - "sha256:0bfd0767c5c1de2551a120673b72e5d4b628737cb05414f03c3277bf9bed3305", - "sha256:0c0850c8b02c298d3c7006b23e98249515ac57430e16a166873fc47a5d549287", - "sha256:0e2cb47860da1f7e9a5256254b74ae331687b9672dfa780eed355c4c9c3dbd23", - "sha256:120fa9349a24c7043854c53cae8cec227e1f79195a7493e09e0c12e29f918e52", - "sha256:1247694b26342a7bf47c02e513d32225ededd18045264d40758abeb3c838a51f", - "sha256:141f1d1a9b663c679dc524af3ea1773e618907e96075262726c7612c02b149a4", - "sha256:14e019fd83b831b2e61baed40cab76222139926b1fb5ed0e79225bc0cae14584", - "sha256:1509dd12b773c02acd154582088820893109f6ca27ef7291b003d0e81666109f", - "sha256:17a753023436a18e27dd7769e798ce302963c236bc4114ceee5b25c18c52c693", - "sha256:1e224d5755dba2f4a9498e150c43792392ac9b5380aa1b845f98a1618c94eeef", - "sha256:1f447ea5429b54f9582d4b955f5f1985f278ce5cf169f72eea8afd9502973dd5", - "sha256:23eed6d7b1a3336ad92d8e39d4bfe09073c31bfe502f20ca5116b2a334f8ec02", - "sha256:25f32acefac14ef7bd53e4218fe93b804ef6f6b92ffdb4322bb6d49d94cad2bc", - "sha256:2c74524e179f2ad6d2a4f7caf70e2d96639c0954c943ad601a9e146c76408ed7", - "sha256:303bf1edce6ced16bf67a18a1cf8339d0db79577eec5d9a6d4a80f0fb10aa2da", - "sha256:3331bece23c9ee066e0fb3f96c61322b9e0f54d775fccefff4c38ca488de283a", - "sha256:3e9bdd30efde2b9ccfa9cb5768ba04fe71b018a25ea093379c857c9dad262c40", - "sha256:411007c0d88188d9f621b11d252cce90c4a2d1a49db6c068e3c16422f306eab8", - "sha256:42871176e7896d5d45138f6d28751053c711ed4d48d8e30b498da155af39aebd", - "sha256:46f409a2d60f634fe550f7133ed30ad5321ae2e6630f13657fb9479506b00601", - "sha256:48628bd53a426c9eb9bc066a923acaa0878d1e86129fd5359aee99285f4eed9c", - "sha256:48d6ed886b343d11493129e019da91d4039826794a3e3027321c56d9e71505be", - "sha256:4930be26af26ac545c3dffb662521d4e6268352866956672231887d18f0eaab2", - "sha256:4aec80cde9197340bc353d2768e2a75f5f60bacda2bab72ab1dc499589b3878c", - "sha256:4c28a9144688aef80d6ea666c809b4b0e50010a2aca784c97f5e6bf143d9f129", - "sha256:4d2d1edbca80b510443f51afd8496be95529db04a509bc8faee49c7b0fb6d2cc", - "sha256:4dd9a263e845a72eacb60d12401e37c616438ea2e5442885f65082c276dfb2b2", - "sha256:4f1026bc732b6a7f96369f7bfe1a4f2290fb34dce00d8644bc3036fb351a4ca1", - "sha256:4fb960a632a49f2f089d522f70496640fdf1218f1243889da3822e0a9f5f3ba7", - "sha256:50670615eaf97227d5dc60de2dc99fb134a7130d310d783314e7724bf163f75d", - "sha256:50baa9c1c47efcaef189f31e3d00d697c6d4afda5c3cde0302d063492ff9b477", - "sha256:53ace1c1fd5a74ef662f844a0413446c0629d151055340e9893da958a374f70d", - "sha256:5515edd2a6d1a5a70bfcdee23b42ec33425e405c5b351478ab7dc9347228f96e", - "sha256:56dc1f1ebccc656d1b3ed288f11e27172a01503fc016bcabdcbc0978b19352b7", - "sha256:578695735c5a3f51569810dfebd05dd6f888147a34f0f98d4bb27e92b76e05c2", - "sha256:57aba1bbdf450b726d58b2aea5fe47c7875f5afb2c4a23784ed78f19a0462574", - "sha256:57d6ba0ca2b0c462f339640d22882acc711de224d769edf29962b09f77129cbf", - "sha256:5c245b783db29c4e4fbbbfc9c5a78be496c9fea25517f90606aa1f6b2b3d5f7b", - "sha256:5c31c7462abdf8f2ac0577d9f05279727e698f97ecbb02f17939ea99ae8daa98", - "sha256:64f479d719dc9f4c813ad9bb6b28f8390360660b73b2e4beb4cb0ae7104f1c12", - "sha256:65299ea57d82fb91c7f019300d24050c4ddeb7c5a190e076b5f48a2b43d19c42", - "sha256:6689a3d7fd13dc687e9102a27e98ef33730ac4fe37795d5036d18b4d527abd35", - "sha256:690dafd0b187ed38583a648076865d8c229661ed20e48f2335d68e2cf7dc829d", - "sha256:6fc3c450eaa0b56f815c7b62f2b7fba7266c4779adcf1cece9e6deb1de7305ce", - "sha256:704f61ba8c1283c71b16135caf697557f5ecf3e74d9e453233e4771d68a1f42d", - "sha256:71c52db65e4b56b8ddc5bb89fb2e66c558ed9d1a74a45ceb7dcb20c191c3df2f", - "sha256:71d66ee82e7417828af6ecd7db817913cb0cf9d4e61aa0ac1fde0583d84358db", - "sha256:7d298a1bd60c067ea75d9f684f5f3992c9d6766fadbc0bcedd39750bf344c2f4", - "sha256:8b77946fd508cbf0fccd8e400a7f71d4ac0e1595812e66025bac475a8e811694", - "sha256:8d7e43bd40f65f7d97ad8ef5c9b1778943d02f04febef12def25f7583d19baac", - "sha256:8df133a2ea5e74eef5e8fc6f19b9e085f758768a16e9877a60aec455ed2609b2", - "sha256:8ed74706b26ad100433da4b9d807eae371efaa266ffc3e9191ea436087a9d6a7", - "sha256:92af161ecbdb2883c4593d5ed4815ea71b31fafd7fd05789b23100d081ecac96", - "sha256:97047f0d25cd4bcae81f9ec9dc290ca3e15927c192df17331b53bebe0e3ff96d", - "sha256:9719fe17307a9e814580af1f5c6e05ca593b12fb7e44fe62450a5384dbf61b4b", - "sha256:9767e79108424fb6c3edf8f81e6730666a50feb01a328f4a016464a5893f835a", - "sha256:9a92d3faef50658dd2c5470af249985782bf754c4e18e15afb67d3ab06233f13", - "sha256:9bb6ad405121241e99a86efff22d3ef469024ce22875a7ae045896ad23ba2340", - "sha256:9e28c51fa0ce5674be9f560c6761c1b441631901993f76700b1b30ca6c8378d6", - "sha256:aca086dc5f9ef98c512bac8efea4483eb84abbf926eaeedf7b91479feb092458", - "sha256:ae8b9c6deb1e634ba4f1930eb67ef6e6bf6a44b6eb5ad605642b2d6d5ed9ce3c", - "sha256:b0a545b46b526d418eb91754565ba5b63b1c0b12f9bd2f808c852d9b4b2f9b5c", - "sha256:b4e4bc18382088514ebde9328da057775055940a1f2e18f6ad2d78aa0f3ec5b9", - "sha256:b6420a005548ad52154c8ceab4a1290ff78d757f9e5cbc68f8c77089acd3c432", - "sha256:b86164d2cff4d3aaa1f04a14685cbc072efd0b4f99ca5708b2ad1b9b5988a991", - "sha256:bb3bb49c7a6ad9d981d734ef7c7193bc349ac338776a0360cc671eaee89bcf69", - "sha256:bef4e656f7d98aaa3486d2627e7d2df1157d7e88e7efd43a65aa5dd4714916cf", - "sha256:c0781a98ff5e6586926293e59480b64ddd46282953203c76ae15dbbbf302e8bb", - "sha256:c2006f5c8d28dee289f7020f721354362fa304acbaaf9745751ac4006650254b", - "sha256:c41bfca0bd3532d53d16fd34d20806d5c2b1ace22a2f2e4c0008570bf2c58833", - "sha256:cd47b4a0d41d2afa3e58e5bf1f62069255aa2fd6ff5ee41604418ca925911d76", - "sha256:cdb650fc86227eba20de1a29d4b2c1bfe139dc75a0669270033cb2ea3d391b85", - "sha256:cef2502e7e8a96fe5ad686d60b49e1ab03e438bd9123987994528febd569868e", - "sha256:d27be7405547d1f958b60837dc4c1007da90b8b23f54ba1f8b728c78fdb19d50", - "sha256:d37017287a7adb6ab77e1c5bee9bcf9660f90ff445042b790402a654d2ad81d8", - "sha256:d3ff32724f98fbbbfa9f49d82852b159e9784d6094983d9a8b7f2ddaebb063d4", - "sha256:d73d8ecf8ecf10a3bd007f2192725a34bd62898e8da27eb9d32a58084f93962b", - "sha256:dd708cf4ee4408cf46a48b108fb9427bfa00b9b85812a9262b5c668af2533ea5", - "sha256:e3cd95e10c2610c360154afdc2f1480aea394f4a4f1ea0a5eacce49640c9b190", - "sha256:e4da8ca0c0c0aea88fd46be8e44bd49716772358d648cce45fe387f7b92374a7", - "sha256:eadfbbbfb41b44034a4c757fd5d70baccd43296fb894dba0295606a7cf3124aa", - "sha256:ed667f49b11360951e201453fc3967344d0d0263aa415e1619e85ae7fd17b4e0", - "sha256:f3df3db1d336b9356dd3112eae5f5c2b8b377f3bc826848567f10bfddfee77e9", - "sha256:f6bdac493b949141b733c5345b6ba8f87a226029cbabc7e9e121a413e49441e0", - "sha256:fbf521479bcac1e25a663df882c46a641a9bff6b56dc8b0fafaebd2f66fb231b", - "sha256:fc9b106a1bf918db68619fdcd6d5ad4f972fdd19c01d19bdb6bf63f3589a9ec5", - "sha256:fcdd00edfd0a3001e0181eab3e63bd5c74ad3e67152c84f93f13769a40e073a7", - "sha256:fe4bda6bd4340caa6e5cf95e73f8fea5c4bfc55763dd42f1b50a94c1b4a2fbd4" + "sha256:13521a321a25c641b9ea127ef478b580b5ec82aa2e9fc076c86169d161798b01", + "sha256:14deca1460b4b0f6b01f1ddc9557704e8b365f55c63070463f6c18619ebf964f", + "sha256:16018f7099245157564d7148165132c70adb272fb5a17c048ba70d9cc542a1a1", + "sha256:16dd953fb719f0ffc5bc067428fc9e88f599e15723a85618c45847c96f11f431", + "sha256:19a1bc898ae9f06bccb7c3e1dfd73897ecbbd2c96afe9095a6026016e5ca97b8", + "sha256:1ad17c20e3666c035db502c78b86e58ff6b5991906e55bdbef94977700c72623", + "sha256:22b7ee4c35f374e2c20337a95502057964d7e35b996b1c667b5c65c567d2252a", + "sha256:24ef5a4631c0b6cceaf2dbca21687e29725b7c4e171f33a8f8ce23c12558ded1", + "sha256:25663d6e99659544ee8fe1b89b1a8c0aaa5e34b103fab124b17fa958c4a324a6", + "sha256:262bc5f512a66b527d026518507e78c2f9c2bd9eb5c8aeeb9f0eb43fcb69dc67", + "sha256:280f3edf15c2a967d923bcfb1f8f15337ad36f93525828b40a0f9d6c2ad24890", + "sha256:2ad3a8ce9e8a767131061a22cd28fdffa3cd2dc193f399ff7b81777f3520e372", + "sha256:2befa20a13f1a75c751f47e00929fb3433d67eb9923c2c0b364de449121f447c", + "sha256:2f37c6d7106a9d6f0708d4e164b707037b7380fcd0b04c5bd9cae1fb46a856fb", + "sha256:304128394c9c22b6569eba2a6d98392b56fbdfbad58f83ea702530be80d0f9df", + "sha256:342e95bddec3a698ac24378d61996b3ee5ba9acfeb253986002ac53c9a5f6f84", + "sha256:3aeca824b38ca78d9ee2ab82bd9883083d0492d9d17df065ba3b94e88e4d7ee6", + "sha256:3d184e0d5c918cff04cdde9dbdf9600e960161d773666958c9d7b565ccc60c45", + "sha256:3e3898ae2b58eeafedfe99e542a17859017d72d7f6a63de0f04f99c2cb125936", + "sha256:3eea6ed6e6c918e468e693c41ef07f3c3acc310b70ddd9cc72d9ef84bc9564ca", + "sha256:3f14a4fb1c1c402a22e6a341a24c1341b4a3def81b41cd354386dcb795f83897", + "sha256:436a943c2900bb98123b06437cdd30580a61340fbdb7b28aaf345a459c19046a", + "sha256:4946e7f59b7b6a9e27bef34422f645e9a368cb2be11bf1ef3cafc39a1f6ba68d", + "sha256:49a9b4af45e8b925e1cd6f3b15bbba2c81e7dba6dce170c677c9cda547411e14", + "sha256:4f8b0c78e7aac24979ef09b7f50da871c2de2def043d468c4b41f512d831e912", + "sha256:52427a7eadc98f9e62cb1368a5079ae826f94f05755d2d567d93ee1bc3ceb354", + "sha256:5e53d7e6a98b64fe54775d23a7c669763451340c3d44ad5e3a3b48a1efbdc96f", + "sha256:5fcfbebdb0c5d8d18b84118842f31965d59ee3e66996ac842e21f957eb76138c", + "sha256:601f4a75797d7a770daed8b42b97cd1bb1ba18bd51a9382077a6a247a12aa38d", + "sha256:61c5a7edbd7c695e54fca029ceb351fc45cd8860119a0f83e48be44e1c464862", + "sha256:6a2a2c724d97c1eb8cf966b16ca2915566a4904b9aad2ed9a09c748ffe14f969", + "sha256:6d48fc57e7c1e3df57be5ae8614bab6d4e7b60f65c5457915c26892c41afc59e", + "sha256:6f11b77ec0979f7e4dc5ae081325a2946f1fe424148d3945f943ceaede98adb8", + "sha256:704f5572ff473a5f897745abebc6df40f22d4133c1e0a1f124e4f2bd3330ff7e", + "sha256:725e171e0b99a66ec8605ac77fa12239dbe061482ac854d25720e2294652eeaa", + "sha256:7cfced4a069003d8913408e10ca8ed092c49a7f6cefee9bb74b6b3e860683b45", + "sha256:7ec465e6549ed97e9f1e5ed51c657c9ede767bc1c11552f7f4d022c4df4a977a", + "sha256:82bddf0e72cb2af3cbba7cec1d2fd11fda0de6be8f4492223d4a268713ef2147", + "sha256:82cd34f1081ae4ea2ede3d52f71b7be313756e99b4b5f829f89b12da552d3aa3", + "sha256:843b9c835580d52828d8f69ea4302537337a21e6b4f1ec711a52241ba4a824f3", + "sha256:877efb968c3d7eb2dad540b6cabf2f1d3c0fbf4b2d309a3c141f79c7e0061324", + "sha256:8b9f19df998761babaa7f09e6bc169294eefafd6149aaa272081cbddc7ba4ca3", + "sha256:8cf5877f7ed384dabfdcc37922c3191bf27e55b498fecece9fd5c2c7aaa34c33", + "sha256:8d2900b7f5318bc7ad8631d3d40190b95ef2aa8cc59473b73b294e4a55e9f30f", + "sha256:8d7b4beebb178e9183138f552238f7e6613162a42164233e2bda00cb3afac58f", + "sha256:8f52fe6859b9db71ee609b0c0a70fea5f1e71c3462ecf144ca800d3f434f0764", + "sha256:98f3f020a2b736566c707c8e034945c02aa94e124c24f77ca097c446f81b01f1", + "sha256:9aa543980ab1fbf1720969af1d99095a548ea42e00361e727c58a40832439114", + "sha256:9b99f564659cfa704a2dd82d0684207b1aadf7d02d33e54845f9fc78e06b7581", + "sha256:9bcf86dfc8ff3e992fed847c077bd875d9e0ba2fa25d859c3a0f0f76f07f0c8d", + "sha256:9bd0ae7cc2b85320abd5e0abad5ccee5564ed5f0cc90245d2f9a8ef330a8deae", + "sha256:9d3c0f8567ffe7502d969c2c1b809892dc793b5d0665f602aad19895f8d508da", + "sha256:9e5ac3437746189a9b4121db2a7b86056ac8786b12e88838696899328fc44bb2", + "sha256:a36c506e5f8aeb40680491d39ed94670487ce6614b9d27cabe45d94cd5d63e1e", + "sha256:a5ab722ae5a873d8dcee1f5f45ddd93c34210aed44ff2dc643b5025981908cda", + "sha256:a96f02ba1bcd330807fc060ed91d1f7a20853da6dd449e5da4b09bfcc08fdcf5", + "sha256:acb6b2f96f60f70e7f34efe0c3ea34ca63f19ca63ce90019c6cbca6b676e81fa", + "sha256:ae15347a88cf8af0949a9872b57a320d2605ae069bcdf047677318bc0bba45b1", + "sha256:af8920ce4a55ff41167ddbc20077f5698c2e710ad3353d32a07d3264f3a2021e", + "sha256:afd825e30f8d1f521713a5669b63657bcfe5980a916c95855060048b88e1adb7", + "sha256:b21b4031b53d25b0858d4e124f2f9131ffc1530431c6d1321805c90da78388d1", + "sha256:b4b68c961b5cc402cbd99cca5eb2547e46ce77260eb705f4d117fd9c3f932b95", + "sha256:b66aa6357b265670bb574f050ffceefb98549c721cf28351b748be1ef9577d93", + "sha256:b9e240ae0ba96477682aa87899d94ddec1cc7926f9df29b1dd57b39e797d5ab5", + "sha256:bc64d1b1dab08f679fb89c368f4c05693f58a9faf744c4d390d7ed1d8223869b", + "sha256:bf8443781533b8d37b295016a4b53c1494fa9a03573c09ca5104550c138d5c05", + "sha256:c26aab6ea9c54d3bed716b8851c8bfc40cb249b8e9880e250d1eddde9f709bf5", + "sha256:c3cd1fc1dc7c376c54440aeaaa0dcc803d2126732ff5c6b68ccd619f2e64be4f", + "sha256:c7257171bb8d4432fe9d6fdde4d55fdbe663a63636a17f7f9aaba9bcb3153ad7", + "sha256:d42e3a3fc18acc88b838efded0e6ec3edf3e328a58c68fbd36a7263a874906c8", + "sha256:d74fcaf87132ffc0447b3c685a9f862ffb5b43e70ea6beec2fb8057d5d2a1fea", + "sha256:d8c1d679df4361408b628f42b26a5d62bd3e9ba7f0c0e7969f925021554755aa", + "sha256:e856c1c7255c739434489ec9c8aa9cdf5179785d10ff20add308b5d673bed5cd", + "sha256:eac68f96539b32fce2c9b47eb7c25bb2582bdaf1bbb360d25f564ee9e04c542b", + "sha256:ed7326563024b6e91fef6b6c7a1a2ff0a71b97793ac33dbbcf38f6005e51ff6e", + "sha256:ed8c3d2cd329bf779b7ed38db176738f3f8be637bb395ce9629fc76f78afe3d4", + "sha256:f4c9bda132ad108b387c33fabfea47866af87f4ea6ffb79418004f0521e63204", + "sha256:f643ffd2669ffd4b5a3e9b41c909b72b2a1d5e4915da90a77e119b8d48ce867a" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==4.9.3" + "markers": "python_version >= '3.6'", + "version": "==5.1.0" }, "mako": { "hashes": [ - "sha256:57d4e997349f1a92035aa25c17ace371a4213f2ca42f99bee9a602500cfd54d9", - "sha256:e3a9d388fd00e87043edbe8792f45880ac0114e9c4adc69f6e9bfb2c55e3b11b" + "sha256:2a0c8ad7f6274271b3bb7467dd37cf9cc6dab4bc19cb69a4ef10669402de698e", + "sha256:32a99d70754dfce237019d17ffe4a282d2d3351b9c476e90d8a60e63f133b80c" ], "markers": "python_version >= '3.8'", - "version": "==1.3.0" + "version": "==1.3.2" }, "markupsafe": { "hashes": [ - "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e", - "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e", - "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431", - "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686", - "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c", - "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559", - "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc", - "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb", - "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939", - "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c", - "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0", - "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4", - "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9", - "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575", - "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba", - "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d", - "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd", - "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3", - "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00", - "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155", - "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac", - "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52", - "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f", - "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8", - "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b", - "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007", - "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24", - "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea", - "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198", - "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0", - "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee", - "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be", - "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2", - "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1", - "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707", - "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6", - "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c", - "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58", - "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823", - "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779", - "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636", - "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c", - "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad", - "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee", - "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc", - "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2", - "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48", - "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7", - "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e", - "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b", - "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa", - "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5", - "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e", - "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb", - "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9", - "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57", - "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc", - "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc", - "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2", - "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11" + "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf", + "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff", + "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f", + "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3", + "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532", + "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f", + "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617", + "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df", + "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4", + "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906", + "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f", + "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4", + "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8", + "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371", + "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2", + "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465", + "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52", + "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6", + "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169", + "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad", + "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2", + "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0", + "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029", + "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f", + "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a", + "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced", + "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5", + "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c", + "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf", + "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9", + "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb", + "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad", + "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3", + "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1", + "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46", + "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc", + "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a", + "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee", + "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900", + "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5", + "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea", + "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f", + "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5", + "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e", + "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a", + "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f", + "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50", + "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a", + "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b", + "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4", + "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff", + "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2", + "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46", + "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b", + "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf", + "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5", + "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5", + "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab", + "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd", + "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68" ], "markers": "python_version >= '3.7'", - "version": "==2.1.3" + "version": "==2.1.5" }, "marshmallow": { "hashes": [ - "sha256:5d2371bbe42000f2b3fb5eaa065224df7d8f8597bc19a1bbfa5bfe7fba8da889", - "sha256:684939db93e80ad3561392f47be0230743131560a41c5110684c16e21ade0a5c" + "sha256:4c1daff273513dc5eb24b219a8035559dc573c8f322558ef85f5438ddd1236dd", + "sha256:c21d4b98fee747c130e6bc8f45c4b3199ea66bc00c12ee1f639f0aeca034d5e9" ], "markers": "python_version >= '3.8'", - "version": "==3.20.1" + "version": "==3.20.2" }, "oic": { "hashes": [ @@ -745,10 +742,10 @@ }, "phonenumberslite": { "hashes": [ - "sha256:305736b1b489e2bc6831710a2f34a9324f2bf96a1e77c8e0b3136dfaf9ca7753", - "sha256:6356f2728fa1d2c2bc9e79c3bfcfedc91a36537df7a134f150731a821a469a96" + "sha256:2b04a53401d01ab42564c1abc762fc9808ad398e71dacfa3b38d4321e112ecb3", + "sha256:74e3ee63dfa2bb562ce2e6ce74ce76ae74a2f81472005b80343235fb43426db4" ], - "version": "==8.13.26" + "version": "==8.13.29" }, "psycopg2-binary": { "hashes": [ @@ -838,161 +835,135 @@ }, "pycryptodomex": { "hashes": [ - "sha256:09c9401dc06fb3d94cb1ec23b4ea067a25d1f4c6b7b118ff5631d0b5daaab3cc", - "sha256:0b2f1982c5bc311f0aab8c293524b861b485d76f7c9ab2c3ac9a25b6f7655975", - "sha256:136b284e9246b4ccf4f752d435c80f2c44fc2321c198505de1d43a95a3453b3c", - "sha256:1789d89f61f70a4cd5483d4dfa8df7032efab1118f8b9894faae03c967707865", - "sha256:2126bc54beccbede6eade00e647106b4f4c21e5201d2b0a73e9e816a01c50905", - "sha256:258c4233a3fe5a6341780306a36c6fb072ef38ce676a6d41eec3e591347919e8", - "sha256:263de9a96d2fcbc9f5bd3a279f14ea0d5f072adb68ebd324987576ec25da084d", - "sha256:50cb18d4dd87571006fd2447ccec85e6cec0136632a550aa29226ba075c80644", - "sha256:5b883e1439ab63af976656446fb4839d566bb096f15fc3c06b5a99cde4927188", - "sha256:5d73e9fa3fe830e7b6b42afc49d8329b07a049a47d12e0ef9225f2fd220f19b2", - "sha256:61056a1fd3254f6f863de94c233b30dd33bc02f8c935b2000269705f1eeeffa4", - "sha256:67c8eb79ab33d0fbcb56842992298ddb56eb6505a72369c20f60bc1d2b6fb002", - "sha256:6e45bb4635b3c4e0a00ca9df75ef6295838c85c2ac44ad882410cb631ed1eeaa", - "sha256:7cb51096a6a8d400724104db8a7e4f2206041a1f23e58924aa3d8d96bcb48338", - "sha256:800a2b05cfb83654df80266692f7092eeefe2a314fa7901dcefab255934faeec", - "sha256:8df69e41f7e7015a90b94d1096ec3d8e0182e73449487306709ec27379fff761", - "sha256:917033016ecc23c8933205585a0ab73e20020fdf671b7cd1be788a5c4039840b", - "sha256:a12144d785518f6491ad334c75ccdc6ad52ea49230b4237f319dbb7cef26f464", - "sha256:a3866d68e2fc345162b1b9b83ef80686acfe5cec0d134337f3b03950a0a8bf56", - "sha256:a588a1cb7781da9d5e1c84affd98c32aff9c89771eac8eaa659d2760666f7139", - "sha256:a77b79852175064c822b047fee7cf5a1f434f06ad075cc9986aa1c19a0c53eb0", - "sha256:af83a554b3f077564229865c45af0791be008ac6469ef0098152139e6bd4b5b6", - "sha256:b801216c48c0886742abf286a9a6b117e248ca144d8ceec1f931ce2dd0c9cb40", - "sha256:bfb040b5dda1dff1e197d2ef71927bd6b8bfcb9793bc4dfe0bb6df1e691eaacb", - "sha256:c01678aee8ac0c1a461cbc38ad496f953f9efcb1fa19f5637cbeba7544792a53", - "sha256:c74eb1f73f788facece7979ce91594dc177e1a9b5d5e3e64697dd58299e5cb4d", - "sha256:c9a68a2f7bd091ccea54ad3be3e9d65eded813e6d79fdf4cc3604e26cdd6384f", - "sha256:d4dd3b381ff5a5907a3eb98f5f6d32c64d319a840278ceea1dcfcc65063856f3", - "sha256:e8e5ecbd4da4157889fce8ba49da74764dd86c891410bfd6b24969fa46edda51", - "sha256:eb2fc0ec241bf5e5ef56c8fbec4a2634d631e4c4f616a59b567947a0f35ad83c", - "sha256:edbe083c299835de7e02c8aa0885cb904a75087d35e7bab75ebe5ed336e8c3e2", - "sha256:ff64fd720def623bf64d8776f8d0deada1cc1bf1ec3c1f9d6f5bb5bd098d034f" + "sha256:0daad007b685db36d977f9de73f61f8da2a7104e20aca3effd30752fd56f73e1", + "sha256:108e5f1c1cd70ffce0b68739c75734437c919d2eaec8e85bffc2c8b4d2794305", + "sha256:19764605feea0df966445d46533729b645033f134baeb3ea26ad518c9fdf212c", + "sha256:1be97461c439a6af4fe1cf8bf6ca5936d3db252737d2f379cc6b2e394e12a458", + "sha256:25cd61e846aaab76d5791d006497134602a9e451e954833018161befc3b5b9ed", + "sha256:2a47bcc478741b71273b917232f521fd5704ab4b25d301669879e7273d3586cc", + "sha256:59af01efb011b0e8b686ba7758d59cf4a8263f9ad35911bfe3f416cee4f5c08c", + "sha256:5dcac11031a71348faaed1f403a0debd56bf5404232284cf8c761ff918886ebc", + "sha256:62a5ec91388984909bb5398ea49ee61b68ecb579123694bffa172c3b0a107079", + "sha256:645bd4ca6f543685d643dadf6a856cc382b654cc923460e3a10a49c1b3832aeb", + "sha256:653b29b0819605fe0898829c8ad6400a6ccde096146730c2da54eede9b7b8baa", + "sha256:69138068268127cd605e03438312d8f271135a33140e2742b417d027a0539427", + "sha256:6e186342cfcc3aafaad565cbd496060e5a614b441cacc3995ef0091115c1f6c5", + "sha256:76bd15bb65c14900d98835fcd10f59e5e0435077431d3a394b60b15864fddd64", + "sha256:7805830e0c56d88f4d491fa5ac640dfc894c5ec570d1ece6ed1546e9df2e98d6", + "sha256:7a710b79baddd65b806402e14766c721aee8fb83381769c27920f26476276c1e", + "sha256:7a7a8f33a1f1fb762ede6cc9cbab8f2a9ba13b196bfaf7bc6f0b39d2ba315a43", + "sha256:82ee7696ed8eb9a82c7037f32ba9b7c59e51dda6f105b39f043b6ef293989cb3", + "sha256:88afd7a3af7ddddd42c2deda43d53d3dfc016c11327d0915f90ca34ebda91499", + "sha256:8af1a451ff9e123d0d8bd5d5e60f8e3315c3a64f3cdd6bc853e26090e195cdc8", + "sha256:8ee606964553c1a0bc74057dd8782a37d1c2bc0f01b83193b6f8bb14523b877b", + "sha256:91852d4480a4537d169c29a9d104dda44094c78f1f5b67bca76c29a91042b623", + "sha256:9c682436c359b5ada67e882fec34689726a09c461efd75b6ea77b2403d5665b7", + "sha256:bc3ee1b4d97081260d92ae813a83de4d2653206967c4a0a017580f8b9548ddbc", + "sha256:bca649483d5ed251d06daf25957f802e44e6bb6df2e8f218ae71968ff8f8edc4", + "sha256:c39778fd0548d78917b61f03c1fa8bfda6cfcf98c767decf360945fe6f97461e", + "sha256:cbe71b6712429650e3883dc81286edb94c328ffcd24849accac0a4dbcc76958a", + "sha256:d00fe8596e1cc46b44bf3907354e9377aa030ec4cd04afbbf6e899fc1e2a7781", + "sha256:d3584623e68a5064a04748fb6d76117a21a7cb5eaba20608a41c7d0c61721794", + "sha256:e48217c7901edd95f9f097feaa0388da215ed14ce2ece803d3f300b4e694abea", + "sha256:f2e497413560e03421484189a6b65e33fe800d3bd75590e6d78d4dfdb7accf3b", + "sha256:ff5c9a67f8a4fba4aed887216e32cbc48f2a6fb2673bb10a99e43be463e15913" ], "index": "pypi", "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==3.19.0" + "version": "==3.20.0" }, "pydantic": { "hashes": [ - "sha256:80c50fb8e3dcecfddae1adbcc00ec5822918490c99ab31f6cf6140ca1c1429f0", - "sha256:ff177ba64c6faf73d7afa2e8cad38fd456c0dbe01c9954e71038001cd15a6edd" + "sha256:0b6a909df3192245cb736509a92ff69e4fef76116feffec68e93a567347bae6f", + "sha256:4fd5c182a2488dc63e6d32737ff19937888001e2a6d86e94b3f233104a5d1fa9" ], - "markers": "python_version >= '3.7'", - "version": "==2.5.2" + "markers": "python_version >= '3.8'", + "version": "==2.6.1" }, "pydantic-core": { "hashes": [ - "sha256:038c9f763e650712b899f983076ce783175397c848da04985658e7628cbe873b", - "sha256:074f3d86f081ce61414d2dc44901f4f83617329c6f3ab49d2bc6c96948b2c26b", - "sha256:079206491c435b60778cf2b0ee5fd645e61ffd6e70c47806c9ed51fc75af078d", - "sha256:09b0e985fbaf13e6b06a56d21694d12ebca6ce5414b9211edf6f17738d82b0f8", - "sha256:0f6116a558fd06d1b7c2902d1c4cf64a5bd49d67c3540e61eccca93f41418124", - "sha256:103ef8d5b58596a731b690112819501ba1db7a36f4ee99f7892c40da02c3e189", - "sha256:16e29bad40bcf97aac682a58861249ca9dcc57c3f6be22f506501833ddb8939c", - "sha256:206ed23aecd67c71daf5c02c3cd19c0501b01ef3cbf7782db9e4e051426b3d0d", - "sha256:2248485b0322c75aee7565d95ad0e16f1c67403a470d02f94da7344184be770f", - "sha256:27548e16c79702f1e03f5628589c6057c9ae17c95b4c449de3c66b589ead0520", - "sha256:2d0ae0d8670164e10accbeb31d5ad45adb71292032d0fdb9079912907f0085f4", - "sha256:3128e0bbc8c091ec4375a1828d6118bc20404883169ac95ffa8d983b293611e6", - "sha256:3387277f1bf659caf1724e1afe8ee7dbc9952a82d90f858ebb931880216ea955", - "sha256:34708cc82c330e303f4ce87758828ef6e457681b58ce0e921b6e97937dd1e2a3", - "sha256:35613015f0ba7e14c29ac6c2483a657ec740e5ac5758d993fdd5870b07a61d8b", - "sha256:3ad873900297bb36e4b6b3f7029d88ff9829ecdc15d5cf20161775ce12306f8a", - "sha256:40180930807ce806aa71eda5a5a5447abb6b6a3c0b4b3b1b1962651906484d68", - "sha256:439c9afe34638ace43a49bf72d201e0ffc1a800295bed8420c2a9ca8d5e3dbb3", - "sha256:45e95333b8418ded64745f14574aa9bfc212cb4fbeed7a687b0c6e53b5e188cd", - "sha256:4641e8ad4efb697f38a9b64ca0523b557c7931c5f84e0fd377a9a3b05121f0de", - "sha256:49b08aae5013640a3bfa25a8eebbd95638ec3f4b2eaf6ed82cf0c7047133f03b", - "sha256:4bc536201426451f06f044dfbf341c09f540b4ebdb9fd8d2c6164d733de5e634", - "sha256:4ce601907e99ea5b4adb807ded3570ea62186b17f88e271569144e8cca4409c7", - "sha256:4e40f2bd0d57dac3feb3a3aed50f17d83436c9e6b09b16af271b6230a2915459", - "sha256:4e47a76848f92529879ecfc417ff88a2806438f57be4a6a8bf2961e8f9ca9ec7", - "sha256:513b07e99c0a267b1d954243845d8a833758a6726a3b5d8948306e3fe14675e3", - "sha256:531f4b4252fac6ca476fbe0e6f60f16f5b65d3e6b583bc4d87645e4e5ddde331", - "sha256:57d52fa717ff445cb0a5ab5237db502e6be50809b43a596fb569630c665abddf", - "sha256:59986de5710ad9613ff61dd9b02bdd2f615f1a7052304b79cc8fa2eb4e336d2d", - "sha256:5baab5455c7a538ac7e8bf1feec4278a66436197592a9bed538160a2e7d11e36", - "sha256:5c7d5b5005f177764e96bd584d7bf28d6e26e96f2a541fdddb934c486e36fd59", - "sha256:60b7607753ba62cf0739177913b858140f11b8af72f22860c28eabb2f0a61937", - "sha256:615a0a4bff11c45eb3c1996ceed5bdaa2f7b432425253a7c2eed33bb86d80abc", - "sha256:61ea96a78378e3bd5a0be99b0e5ed00057b71f66115f5404d0dae4819f495093", - "sha256:652c1988019752138b974c28f43751528116bcceadad85f33a258869e641d753", - "sha256:6637560562134b0e17de333d18e69e312e0458ee4455bdad12c37100b7cad706", - "sha256:678265f7b14e138d9a541ddabbe033012a2953315739f8cfa6d754cc8063e8ca", - "sha256:699156034181e2ce106c89ddb4b6504c30db8caa86e0c30de47b3e0654543260", - "sha256:6b9ff467ffbab9110e80e8c8de3bcfce8e8b0fd5661ac44a09ae5901668ba997", - "sha256:6c327e9cd849b564b234da821236e6bcbe4f359a42ee05050dc79d8ed2a91588", - "sha256:6d30226dfc816dd0fdf120cae611dd2215117e4f9b124af8c60ab9093b6e8e71", - "sha256:6e227c40c02fd873c2a73a98c1280c10315cbebe26734c196ef4514776120aeb", - "sha256:6e4d090e73e0725b2904fdbdd8d73b8802ddd691ef9254577b708d413bf3006e", - "sha256:70f4b4851dbb500129681d04cc955be2a90b2248d69273a787dda120d5cf1f69", - "sha256:70f947628e074bb2526ba1b151cee10e4c3b9670af4dbb4d73bc8a89445916b5", - "sha256:774de879d212db5ce02dfbf5b0da9a0ea386aeba12b0b95674a4ce0593df3d07", - "sha256:77fa384d8e118b3077cccfcaf91bf83c31fe4dc850b5e6ee3dc14dc3d61bdba1", - "sha256:79e0a2cdbdc7af3f4aee3210b1172ab53d7ddb6a2d8c24119b5706e622b346d0", - "sha256:7e88f5696153dc516ba6e79f82cc4747e87027205f0e02390c21f7cb3bd8abfd", - "sha256:7f8210297b04e53bc3da35db08b7302a6a1f4889c79173af69b72ec9754796b8", - "sha256:81982d78a45d1e5396819bbb4ece1fadfe5f079335dd28c4ab3427cd95389944", - "sha256:823fcc638f67035137a5cd3f1584a4542d35a951c3cc68c6ead1df7dac825c26", - "sha256:853a2295c00f1d4429db4c0fb9475958543ee80cfd310814b5c0ef502de24dda", - "sha256:88e74ab0cdd84ad0614e2750f903bb0d610cc8af2cc17f72c28163acfcf372a4", - "sha256:8aa1768c151cf562a9992462239dfc356b3d1037cc5a3ac829bb7f3bda7cc1f9", - "sha256:8c8a8812fe6f43a3a5b054af6ac2d7b8605c7bcab2804a8a7d68b53f3cd86e00", - "sha256:95b15e855ae44f0c6341ceb74df61b606e11f1087e87dcb7482377374aac6abe", - "sha256:96581cfefa9123accc465a5fd0cc833ac4d75d55cc30b633b402e00e7ced00a6", - "sha256:9bd18fee0923ca10f9a3ff67d4851c9d3e22b7bc63d1eddc12f439f436f2aada", - "sha256:a33324437018bf6ba1bb0f921788788641439e0ed654b233285b9c69704c27b4", - "sha256:a6a16f4a527aae4f49c875da3cdc9508ac7eef26e7977952608610104244e1b7", - "sha256:a717aef6971208f0851a2420b075338e33083111d92041157bbe0e2713b37325", - "sha256:a71891847f0a73b1b9eb86d089baee301477abef45f7eaf303495cd1473613e4", - "sha256:aae7ea3a1c5bb40c93cad361b3e869b180ac174656120c42b9fadebf685d121b", - "sha256:ab1cdb0f14dc161ebc268c09db04d2c9e6f70027f3b42446fa11c153521c0e88", - "sha256:ab4ea451082e684198636565224bbb179575efc1658c48281b2c866bfd4ddf04", - "sha256:abf058be9517dc877227ec3223f0300034bd0e9f53aebd63cf4456c8cb1e0863", - "sha256:af36f36538418f3806048f3b242a1777e2540ff9efaa667c27da63d2749dbce0", - "sha256:b53e9ad053cd064f7e473a5f29b37fc4cc9dc6d35f341e6afc0155ea257fc911", - "sha256:b7851992faf25eac90bfcb7bfd19e1f5ffa00afd57daec8a0042e63c74a4551b", - "sha256:b9b759b77f5337b4ea024f03abc6464c9f35d9718de01cfe6bae9f2e139c397e", - "sha256:ba39688799094c75ea8a16a6b544eb57b5b0f3328697084f3f2790892510d144", - "sha256:ba6b6b3846cfc10fdb4c971980a954e49d447cd215ed5a77ec8190bc93dd7bc5", - "sha256:bb4c2eda937a5e74c38a41b33d8c77220380a388d689bcdb9b187cf6224c9720", - "sha256:c0b97ec434041827935044bbbe52b03d6018c2897349670ff8fe11ed24d1d4ab", - "sha256:c1452a1acdf914d194159439eb21e56b89aa903f2e1c65c60b9d874f9b950e5d", - "sha256:c2027d05c8aebe61d898d4cffd774840a9cb82ed356ba47a90d99ad768f39789", - "sha256:c2adbe22ab4babbca99c75c5d07aaf74f43c3195384ec07ccbd2f9e3bddaecec", - "sha256:c2d97e906b4ff36eb464d52a3bc7d720bd6261f64bc4bcdbcd2c557c02081ed2", - "sha256:c339dabd8ee15f8259ee0f202679b6324926e5bc9e9a40bf981ce77c038553db", - "sha256:c6eae413494a1c3f89055da7a5515f32e05ebc1a234c27674a6956755fb2236f", - "sha256:c949f04ecad823f81b1ba94e7d189d9dfb81edbb94ed3f8acfce41e682e48cef", - "sha256:c97bee68898f3f4344eb02fec316db93d9700fb1e6a5b760ffa20d71d9a46ce3", - "sha256:ca61d858e4107ce5e1330a74724fe757fc7135190eb5ce5c9d0191729f033209", - "sha256:cb4679d4c2b089e5ef89756bc73e1926745e995d76e11925e3e96a76d5fa51fc", - "sha256:cb774298da62aea5c80a89bd58c40205ab4c2abf4834453b5de207d59d2e1651", - "sha256:ccd4d5702bb90b84df13bd491be8d900b92016c5a455b7e14630ad7449eb03f8", - "sha256:cf9d3fe53b1ee360e2421be95e62ca9b3296bf3f2fb2d3b83ca49ad3f925835e", - "sha256:d2ae91f50ccc5810b2f1b6b858257c9ad2e08da70bf890dee02de1775a387c66", - "sha256:d37f8ec982ead9ba0a22a996129594938138a1503237b87318392a48882d50b7", - "sha256:d81e6987b27bc7d101c8597e1cd2bcaa2fee5e8e0f356735c7ed34368c471550", - "sha256:dcf4e6d85614f7a4956c2de5a56531f44efb973d2fe4a444d7251df5d5c4dcfd", - "sha256:de790a3b5aa2124b8b78ae5faa033937a72da8efe74b9231698b5a1dd9be3405", - "sha256:e47e9a08bcc04d20975b6434cc50bf82665fbc751bcce739d04a3120428f3e27", - "sha256:e60f112ac88db9261ad3a52032ea46388378034f3279c643499edb982536a093", - "sha256:e87fc540c6cac7f29ede02e0f989d4233f88ad439c5cdee56f693cc9c1c78077", - "sha256:eac5c82fc632c599f4639a5886f96867ffced74458c7db61bc9a66ccb8ee3113", - "sha256:ebb4e035e28f49b6f1a7032920bb9a0c064aedbbabe52c543343d39341a5b2a3", - "sha256:ec1e72d6412f7126eb7b2e3bfca42b15e6e389e1bc88ea0069d0cc1742f477c6", - "sha256:ef98ca7d5995a82f43ec0ab39c4caf6a9b994cb0b53648ff61716370eadc43cf", - "sha256:f0cbc7fff06a90bbd875cc201f94ef0ee3929dfbd5c55a06674b60857b8b85ed", - "sha256:f4791cf0f8c3104ac668797d8c514afb3431bc3305f5638add0ba1a5a37e0d88", - "sha256:f5e412d717366e0677ef767eac93566582518fe8be923361a5c204c1a62eaafe", - "sha256:fb2ed8b3fe4bf4506d6dab3b93b83bbc22237e230cba03866d561c3577517d18", - "sha256:fe0a5a1025eb797752136ac8b4fa21aa891e3d74fd340f864ff982d649691867" + "sha256:02906e7306cb8c5901a1feb61f9ab5e5c690dbbeaa04d84c1b9ae2a01ebe9379", + "sha256:0ba503850d8b8dcc18391f10de896ae51d37fe5fe43dbfb6a35c5c5cad271a06", + "sha256:16aa02e7a0f539098e215fc193c8926c897175d64c7926d00a36188917717a05", + "sha256:18de31781cdc7e7b28678df7c2d7882f9692ad060bc6ee3c94eb15a5d733f8f7", + "sha256:22c5f022799f3cd6741e24f0443ead92ef42be93ffda0d29b2597208c94c3753", + "sha256:2924b89b16420712e9bb8192396026a8fbd6d8726224f918353ac19c4c043d2a", + "sha256:308974fdf98046db28440eb3377abba274808bf66262e042c412eb2adf852731", + "sha256:396fdf88b1b503c9c59c84a08b6833ec0c3b5ad1a83230252a9e17b7dfb4cffc", + "sha256:3ac426704840877a285d03a445e162eb258924f014e2f074e209d9b4ff7bf380", + "sha256:3b052c753c4babf2d1edc034c97851f867c87d6f3ea63a12e2700f159f5c41c3", + "sha256:3fab4e75b8c525a4776e7630b9ee48aea50107fea6ca9f593c98da3f4d11bf7c", + "sha256:406fac1d09edc613020ce9cf3f2ccf1a1b2f57ab00552b4c18e3d5276c67eb11", + "sha256:40a0bd0bed96dae5712dab2aba7d334a6c67cbcac2ddfca7dbcc4a8176445990", + "sha256:41dac3b9fce187a25c6253ec79a3f9e2a7e761eb08690e90415069ea4a68ff7a", + "sha256:459c0d338cc55d099798618f714b21b7ece17eb1a87879f2da20a3ff4c7628e2", + "sha256:459d6be6134ce3b38e0ef76f8a672924460c455d45f1ad8fdade36796df1ddc8", + "sha256:46b0d5520dbcafea9a8645a8164658777686c5c524d381d983317d29687cce97", + "sha256:47924039e785a04d4a4fa49455e51b4eb3422d6eaacfde9fc9abf8fdef164e8a", + "sha256:4bfcbde6e06c56b30668a0c872d75a7ef3025dc3c1823a13cf29a0e9b33f67e8", + "sha256:4f9ee4febb249c591d07b2d4dd36ebcad0ccd128962aaa1801508320896575ef", + "sha256:55749f745ebf154c0d63d46c8c58594d8894b161928aa41adbb0709c1fe78b77", + "sha256:5864b0242f74b9dd0b78fd39db1768bc3f00d1ffc14e596fd3e3f2ce43436a33", + "sha256:5f60f920691a620b03082692c378661947d09415743e437a7478c309eb0e4f82", + "sha256:60eb8ceaa40a41540b9acae6ae7c1f0a67d233c40dc4359c256ad2ad85bdf5e5", + "sha256:69a7b96b59322a81c2203be537957313b07dd333105b73db0b69212c7d867b4b", + "sha256:6ad84731a26bcfb299f9eab56c7932d46f9cad51c52768cace09e92a19e4cf55", + "sha256:6db58c22ac6c81aeac33912fb1af0e930bc9774166cdd56eade913d5f2fff35e", + "sha256:70651ff6e663428cea902dac297066d5c6e5423fda345a4ca62430575364d62b", + "sha256:72f7919af5de5ecfaf1eba47bf9a5d8aa089a3340277276e5636d16ee97614d7", + "sha256:732bd062c9e5d9582a30e8751461c1917dd1ccbdd6cafb032f02c86b20d2e7ec", + "sha256:7924e54f7ce5d253d6160090ddc6df25ed2feea25bfb3339b424a9dd591688bc", + "sha256:7afb844041e707ac9ad9acad2188a90bffce2c770e6dc2318be0c9916aef1469", + "sha256:7b883af50eaa6bb3299780651e5be921e88050ccf00e3e583b1e92020333304b", + "sha256:7beec26729d496a12fd23cf8da9944ee338c8b8a17035a560b585c36fe81af20", + "sha256:7bf26c2e2ea59d32807081ad51968133af3025c4ba5753e6a794683d2c91bf6e", + "sha256:7c31669e0c8cc68400ef0c730c3a1e11317ba76b892deeefaf52dcb41d56ed5d", + "sha256:7e6231aa5bdacda78e96ad7b07d0c312f34ba35d717115f4b4bff6cb87224f0f", + "sha256:870dbfa94de9b8866b37b867a2cb37a60c401d9deb4a9ea392abf11a1f98037b", + "sha256:88646cae28eb1dd5cd1e09605680c2b043b64d7481cdad7f5003ebef401a3039", + "sha256:8aafeedb6597a163a9c9727d8a8bd363a93277701b7bfd2749fbefee2396469e", + "sha256:8bde5b48c65b8e807409e6f20baee5d2cd880e0fad00b1a811ebc43e39a00ab2", + "sha256:8f9142a6ed83d90c94a3efd7af8873bf7cefed2d3d44387bf848888482e2d25f", + "sha256:936a787f83db1f2115ee829dd615c4f684ee48ac4de5779ab4300994d8af325b", + "sha256:98dc6f4f2095fc7ad277782a7c2c88296badcad92316b5a6e530930b1d475ebc", + "sha256:9957433c3a1b67bdd4c63717eaf174ebb749510d5ea612cd4e83f2d9142f3fc8", + "sha256:99af961d72ac731aae2a1b55ccbdae0733d816f8bfb97b41909e143de735f522", + "sha256:9b5f13857da99325dcabe1cc4e9e6a3d7b2e2c726248ba5dd4be3e8e4a0b6d0e", + "sha256:9d776d30cde7e541b8180103c3f294ef7c1862fd45d81738d156d00551005784", + "sha256:9da90d393a8227d717c19f5397688a38635afec89f2e2d7af0df037f3249c39a", + "sha256:a3b7352b48fbc8b446b75f3069124e87f599d25afb8baa96a550256c031bb890", + "sha256:a477932664d9611d7a0816cc3c0eb1f8856f8a42435488280dfbf4395e141485", + "sha256:a7e41e3ada4cca5f22b478c08e973c930e5e6c7ba3588fb8e35f2398cdcc1545", + "sha256:a90fec23b4b05a09ad988e7a4f4e081711a90eb2a55b9c984d8b74597599180f", + "sha256:a9e523474998fb33f7c1a4d55f5504c908d57add624599e095c20fa575b8d943", + "sha256:aa057095f621dad24a1e906747179a69780ef45cc8f69e97463692adbcdae878", + "sha256:aa6c8c582036275997a733427b88031a32ffa5dfc3124dc25a730658c47a572f", + "sha256:ae34418b6b389d601b31153b84dce480351a352e0bb763684a1b993d6be30f17", + "sha256:b0d7a9165167269758145756db43a133608a531b1e5bb6a626b9ee24bc38a8f7", + "sha256:b30b0dd58a4509c3bd7eefddf6338565c4905406aee0c6e4a5293841411a1286", + "sha256:b8f9186ca45aee030dc8234118b9c0784ad91a0bb27fc4e7d9d6608a5e3d386c", + "sha256:b94cbda27267423411c928208e89adddf2ea5dd5f74b9528513f0358bba019cb", + "sha256:cc6f6c9be0ab6da37bc77c2dda5f14b1d532d5dbef00311ee6e13357a418e646", + "sha256:ce232a6170dd6532096cadbf6185271e4e8c70fc9217ebe105923ac105da9978", + "sha256:cf903310a34e14651c9de056fcc12ce090560864d5a2bb0174b971685684e1d8", + "sha256:d5362d099c244a2d2f9659fb3c9db7c735f0004765bbe06b99be69fbd87c3f15", + "sha256:dffaf740fe2e147fedcb6b561353a16243e654f7fe8e701b1b9db148242e1272", + "sha256:e0f686549e32ccdb02ae6f25eee40cc33900910085de6aa3790effd391ae10c2", + "sha256:e4b52776a2e3230f4854907a1e0946eec04d41b1fc64069ee774876bbe0eab55", + "sha256:e4ba0884a91f1aecce75202473ab138724aa4fb26d7707f2e1fa6c3e68c84fbf", + "sha256:e6294e76b0380bb7a61eb8a39273c40b20beb35e8c87ee101062834ced19c545", + "sha256:ebb892ed8599b23fa8f1799e13a12c87a97a6c9d0f497525ce9858564c4575a4", + "sha256:eca58e319f4fd6df004762419612122b2c7e7d95ffafc37e890252f869f3fb2a", + "sha256:ed957db4c33bc99895f3a1672eca7e80e8cda8bd1e29a80536b4ec2153fa9804", + "sha256:ef551c053692b1e39e3f7950ce2296536728871110e7d75c4e7753fb30ca87f4", + "sha256:ef6113cd31411eaf9b39fc5a8848e71c72656fd418882488598758b2c8c6dfa0", + "sha256:f685dbc1fdadb1dcd5b5e51e0a378d4685a891b2ddaf8e2bba89bd3a7144e44a", + "sha256:f8ed79883b4328b7f0bd142733d99c8e6b22703e908ec63d930b06be3a0e7113", + "sha256:fe56851c3f1d6f5384b3051c536cc81b3a93a73faf931f404fef95217cf1e10d", + "sha256:ff7c97eb7a29aba230389a2661edf2e9e06ce616c7e35aa764879b6894a44b25" ], - "markers": "python_version >= '3.7'", - "version": "==2.14.5" + "markers": "python_version >= '3.8'", + "version": "==2.16.2" }, "pydantic-settings": { "hashes": [ @@ -1019,11 +990,11 @@ }, "python-dotenv": { "hashes": [ - "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba", - "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a" + "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", + "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a" ], "markers": "python_version >= '3.8'", - "version": "==1.0.0" + "version": "==1.0.1" }, "requests": { "hashes": [ @@ -1036,19 +1007,19 @@ }, "s3transfer": { "hashes": [ - "sha256:368ac6876a9e9ed91f6bc86581e319be08188dc60d50e0d56308ed5765446283", - "sha256:c9e56cbe88b28d8e197cf841f1f0c130f246595e77ae5b5a05b69fe7cb83de76" + "sha256:3cdb40f5cfa6966e812209d0994f2a4709b561c88e90cf00c2696d2df4e56b2e", + "sha256:d0c8bbf672d5eebbe4e57945e23b972d963f07d82f661cabf678a5c88831595b" ], - "markers": "python_version >= '3.7'", - "version": "==0.8.2" + "markers": "python_version >= '3.8'", + "version": "==0.10.0" }, "setuptools": { "hashes": [ - "sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2", - "sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6" + "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05", + "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78" ], "markers": "python_version >= '3.8'", - "version": "==69.0.2" + "version": "==69.0.3" }, "six": { "hashes": [ @@ -1068,12 +1039,12 @@ }, "typing-extensions": { "hashes": [ - "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0", - "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef" + "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783", + "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.8.0" + "version": "==4.9.0" }, "urllib3": { "hashes": [ @@ -1154,45 +1125,49 @@ }, "bandit": { "hashes": [ - "sha256:75665181dc1e0096369112541a056c59d1c5f66f9bb74a8d686c3c362b83f549", - "sha256:bdfc739baa03b880c2d15d0431b31c658ffc348e907fe197e54e0389dd59e11e" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==1.7.5" - }, - "beautifulsoup4": { - "hashes": [ - "sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da", - "sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a" - ], - "markers": "python_full_version >= '3.6.0'", - "version": "==4.12.2" - }, - "black": { - "hashes": [ - "sha256:250d7e60f323fcfc8ea6c800d5eba12f7967400eb6c2d21ae85ad31c204fb1f4", - "sha256:2a9acad1451632021ee0d146c8765782a0c3846e0e0ea46659d7c4f89d9b212b", - "sha256:412f56bab20ac85927f3a959230331de5614aecda1ede14b373083f62ec24e6f", - "sha256:421f3e44aa67138ab1b9bfbc22ee3780b22fa5b291e4db8ab7eee95200726b07", - "sha256:45aa1d4675964946e53ab81aeec7a37613c1cb71647b5394779e6efb79d6d187", - "sha256:4c44b7211a3a0570cc097e81135faa5f261264f4dfaa22bd5ee2875a4e773bd6", - "sha256:4c68855825ff432d197229846f971bc4d6666ce90492e5b02013bcaca4d9ab05", - "sha256:5133f5507007ba08d8b7b263c7aa0f931af5ba88a29beacc4b2dc23fcefe9c06", - "sha256:54caaa703227c6e0c87b76326d0862184729a69b73d3b7305b6288e1d830067e", - "sha256:58e5f4d08a205b11800332920e285bd25e1a75c54953e05502052738fe16b3b5", - "sha256:698c1e0d5c43354ec5d6f4d914d0d553a9ada56c85415700b81dc90125aac244", - "sha256:6c1cac07e64433f646a9a838cdc00c9768b3c362805afc3fce341af0e6a9ae9f", - "sha256:760415ccc20f9e8747084169110ef75d545f3b0932ee21368f63ac0fee86b221", - "sha256:7f622b6822f02bfaf2a5cd31fdb7cd86fcf33dab6ced5185c35f5db98260b055", - "sha256:cf57719e581cfd48c4efe28543fea3d139c6b6f1238b3f0102a9c73992cbb479", - "sha256:d136ef5b418c81660ad847efe0e55c58c8208b77a57a28a503a5f345ccf01394", - "sha256:dbea0bb8575c6b6303cc65017b46351dc5953eea5c0a59d7b7e3a2d2f433a911", - "sha256:fc7f6a44d52747e65a02558e1d807c82df1d66ffa80a601862040a43ec2e3142" + "sha256:17e60786a7ea3c9ec84569fd5aee09936d116cb0cb43151023258340dbffb7ed", + "sha256:527906bec6088cb499aae31bc962864b4e77569e9d529ee51df3a93b4b8ab28a" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==23.11.0" + "version": "==1.7.7" + }, + "beautifulsoup4": { + "hashes": [ + "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051", + "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed" + ], + "markers": "python_full_version >= '3.6.0'", + "version": "==4.12.3" + }, + "black": { + "hashes": [ + "sha256:0269dfdea12442022e88043d2910429bed717b2d04523867a85dacce535916b8", + "sha256:07204d078e25327aad9ed2c64790d681238686bce254c910de640c7cc4fc3aa6", + "sha256:08b34e85170d368c37ca7bf81cf67ac863c9d1963b2c1780c39102187ec8dd62", + "sha256:1a95915c98d6e32ca43809d46d932e2abc5f1f7d582ffbe65a5b4d1588af7445", + "sha256:2588021038bd5ada078de606f2a804cadd0a3cc6a79cb3e9bb3a8bf581325a4c", + "sha256:2fa6a0e965779c8f2afb286f9ef798df770ba2b6cee063c650b96adec22c056a", + "sha256:34afe9da5056aa123b8bfda1664bfe6fb4e9c6f311d8e4a6eb089da9a9173bf9", + "sha256:3897ae5a21ca132efa219c029cce5e6bfc9c3d34ed7e892113d199c0b1b444a2", + "sha256:40657e1b78212d582a0edecafef133cf1dd02e6677f539b669db4746150d38f6", + "sha256:48b5760dcbfe5cf97fd4fba23946681f3a81514c6ab8a45b50da67ac8fbc6c7b", + "sha256:5242ecd9e990aeb995b6d03dc3b2d112d4a78f2083e5a8e86d566340ae80fec4", + "sha256:5cdc2e2195212208fbcae579b931407c1fa9997584f0a415421748aeafff1168", + "sha256:5d7b06ea8816cbd4becfe5f70accae953c53c0e53aa98730ceccb0395520ee5d", + "sha256:7258c27115c1e3b5de9ac6c4f9957e3ee2c02c0b39222a24dc7aa03ba0e986f5", + "sha256:854c06fb86fd854140f37fb24dbf10621f5dab9e3b0c29a690ba595e3d543024", + "sha256:a21725862d0e855ae05da1dd25e3825ed712eaaccef6b03017fe0853a01aa45e", + "sha256:a83fe522d9698d8f9a101b860b1ee154c1d25f8a82ceb807d319f085b2627c5b", + "sha256:b3d64db762eae4a5ce04b6e3dd745dcca0fb9560eb931a5be97472e38652a161", + "sha256:e298d588744efda02379521a19639ebcd314fba7a49be22136204d7ed1782717", + "sha256:e2c8dfa14677f90d976f68e0c923947ae68fa3961d61ee30976c388adc0b02c8", + "sha256:ecba2a15dfb2d97105be74bbfe5128bc5e9fa8477d8c46766505c1dda5883aac", + "sha256:fc1ec9aa6f4d98d022101e015261c056ddebe3da6a8ccfc2c792cbe0349d48b7" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==24.1.1" }, "blinker": { "hashes": [ @@ -1204,12 +1179,12 @@ }, "boto3": { "hashes": [ - "sha256:d12467fb3a64d359b0bda0570a8163a5859fcac13e786f2a3db0392523178556", - "sha256:eed0f7df91066b6ac63a53d16459ac082458d57061bedf766135d9e1c2b75a6b" + "sha256:65acfe7f1cf2a9b7df3d4edb87c8022e02685825bd1957e7bb678cc0d09f5e5f", + "sha256:73f5ec89cb3ddb3ed577317889fd2f2df783f66b6502a9a4239979607e33bf74" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==1.33.7" + "markers": "python_version >= '3.8'", + "version": "==1.34.37" }, "boto3-mocking": { "hashes": [ @@ -1222,28 +1197,28 @@ }, "boto3-stubs": { "hashes": [ - "sha256:0461f6fec92d96aa2ea3a207329bd020a62a7aaa86f284e5cf054d9b0c7f03c2", - "sha256:449b91060cd953e08980d76a3b67d7eb4246e663b37ecba4ec625b54619e1c22" + "sha256:97b5ca3d3145385acde5af46ca2da3fc74f433545034c36183f389e99771516e", + "sha256:c6618c7126bac0337c05e161e9c428febc57d6a24d7ff62de46e67761f402c57" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==1.33.7" + "markers": "python_version >= '3.8'", + "version": "==1.34.37" }, "botocore": { "hashes": [ - "sha256:71ec0e85b996cf9def3dd8f4ca6cb4a9fd3a614aa4c9c7cbf33f2f68e1d0649a", - "sha256:b2299bc13bb8c0928edc98bf4594deb14cba2357536120f63772027a16ce7374" + "sha256:2a5bf33aacd2d970afd3d492e179e06ea98a5469030d5cfe7a2ad9995f7bb2ef", + "sha256:3c46ddb1679e6ef45ca78b48665398636bda532a07cd476e4b500697d13d9a99" ], - "markers": "python_version >= '3.7'", - "version": "==1.33.7" + "markers": "python_version >= '3.8'", + "version": "==1.34.37" }, "botocore-stubs": { "hashes": [ - "sha256:ca5de1ad4dc384f919387bb96eececb70900fda9219acfcf4b473b35a4834ec9", - "sha256:f73e4728a4a391f0407cd9403f6935343aac5687fb1e0eab7c3351d3419e853b" + "sha256:087cd42973edcb5527dc97eec87fa29fffecc39691249486e02045677d4a2dbe", + "sha256:d6bcea8a6872aa46d389027dc5c022241fd0a2047a8b858aa5005e6151ed30a7" ], - "markers": "python_version >= '3.7' and python_version < '4.0'", - "version": "==1.33.7" + "markers": "python_version >= '3.8' and python_version < '4.0'", + "version": "==1.34.37" }, "click": { "hashes": [ @@ -1255,21 +1230,21 @@ }, "django": { "hashes": [ - "sha256:8e0f1c2c2786b5c0e39fe1afce24c926040fad47c8ea8ad30aaf1188df29fc41", - "sha256:e1d37c51ad26186de355cbcec16613ebdabfa9689bbade9c538835205a8abbe9" + "sha256:45a747e1c5b3d6df1b141b1481e193b033fd1fdbda3ff52677dc81afdaacbaed", + "sha256:f7c7852a5ac5a3da5a8d5b35cc6168f31b605971441798dac845f17ca8028039" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.2.7" + "version": "==4.2.3" }, "django-debug-toolbar": { "hashes": [ - "sha256:af99128c06e8e794479e65ab62cc6c7d1e74e1c19beb44dcbf9bad7a9c017327", - "sha256:bc7fdaafafcdedefcc67a4a5ad9dac96efd6e41db15bc74d402a54a2ba4854dc" + "sha256:0b0dddee5ea29b9cb678593bc0d7a6d76b21d7799cb68e091a2148341a80f3c4", + "sha256:e09b7dcb8417b743234dfc57c95a7c1d1d87a88844abd13b4c5387f807b31bf6" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.2.0" + "version": "==4.3.0" }, "django-model2puml": { "hashes": [ @@ -1280,20 +1255,20 @@ }, "django-stubs": { "hashes": [ - "sha256:2fcd257884a68dfa02de41ee5410ec805264d9b07d9b5b119e4dea82c7b8345e", - "sha256:e60b43de662a199db4b15c803c06669e0ac5035614af291cbd3b91591f7dcc94" + "sha256:4cf4de258fa71adc6f2799e983091b9d46cfc67c6eebc68fe111218c9a62b3b8", + "sha256:8ccd2ff4ee5adf22b9e3b7b1a516d2e1c2191e9d94e672c35cc2bc3dd61e0f6b" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.2.6" + "version": "==4.2.7" }, "django-stubs-ext": { "hashes": [ - "sha256:8c4d1fb5f68419b3b2474c659681a189803e27d6a5e5abf5aa0da57601b58633", - "sha256:921cd7ae4614e74c234bc0fe86ee75537d163addfe1fc6f134bf03e29d86c01e" + "sha256:45a5d102417a412e3606e3c358adb4744988a92b7b58ccf3fd64bddd5d04d14c", + "sha256:519342ac0849cda1559746c9a563f03ff99f636b0ebe7c14b75e816a00dfddc3" ], "markers": "python_version >= '3.8'", - "version": "==4.2.5" + "version": "==4.2.7" }, "django-webtest": { "hashes": [ @@ -1305,28 +1280,12 @@ }, "flake8": { "hashes": [ - "sha256:d5b3857f07c030bdb5bf41c7f53799571d75c4491748a3adcd47de929e34cd23", - "sha256:ffdfce58ea94c6580c77888a86506937f9a1a227dfcd15f245d694ae20a6b6e5" + "sha256:33f96621059e65eec474169085dc92bf26e7b2d47366b70be2f67ab80dc25132", + "sha256:a6dfbb75e03252917f2473ea9653f7cd799c3064e54d4c8140044c5c065f53c3" ], "index": "pypi", "markers": "python_full_version >= '3.8.1'", - "version": "==6.1.0" - }, - "gitdb": { - "hashes": [ - "sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4", - "sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b" - ], - "markers": "python_version >= '3.7'", - "version": "==4.0.11" - }, - "gitpython": { - "hashes": [ - "sha256:22b126e9ffb671fdd0c129796343a02bf67bf2994b35449ffc9321aa755e18a4", - "sha256:cf14627d5a8049ffbf49915732e5eddbe8134c3bdb9d476e6182b676fc573f8a" - ], - "markers": "python_version >= '3.7'", - "version": "==3.1.40" + "version": "==7.0.0" }, "jmespath": { "hashes": [ @@ -1362,37 +1321,37 @@ }, "mypy": { "hashes": [ - "sha256:12cce78e329838d70a204293e7b29af9faa3ab14899aec397798a4b41be7f340", - "sha256:1484b8fa2c10adf4474f016e09d7a159602f3239075c7bf9f1627f5acf40ad49", - "sha256:204e0d6de5fd2317394a4eff62065614c4892d5a4d1a7ee55b765d7a3d9e3f82", - "sha256:2643d145af5292ee956aa0a83c2ce1038a3bdb26e033dadeb2f7066fb0c9abce", - "sha256:2c6e4464ed5f01dc44dc9821caf67b60a4e5c3b04278286a85c067010653a0eb", - "sha256:2f7f6985d05a4e3ce8255396df363046c28bea790e40617654e91ed580ca7c51", - "sha256:31902408f4bf54108bbfb2e35369877c01c95adc6192958684473658c322c8a5", - "sha256:40716d1f821b89838589e5b3106ebbc23636ffdef5abc31f7cd0266db936067e", - "sha256:4b901927f16224d0d143b925ce9a4e6b3a758010673eeded9b748f250cf4e8f7", - "sha256:4fc3d14ee80cd22367caaaf6e014494415bf440980a3045bf5045b525680ac33", - "sha256:5cf3f0c5ac72139797953bd50bc6c95ac13075e62dbfcc923571180bebb662e9", - "sha256:6dbdec441c60699288adf051f51a5d512b0d818526d1dcfff5a41f8cd8b4aaf1", - "sha256:72cf32ce7dd3562373f78bd751f73c96cfb441de147cc2448a92c1a308bd0ca6", - "sha256:75aa828610b67462ffe3057d4d8a4112105ed211596b750b53cbfe182f44777a", - "sha256:75c4d2a6effd015786c87774e04331b6da863fc3fc4e8adfc3b40aa55ab516fe", - "sha256:78e25b2fd6cbb55ddfb8058417df193f0129cad5f4ee75d1502248e588d9e0d7", - "sha256:84860e06ba363d9c0eeabd45ac0fde4b903ad7aa4f93cd8b648385a888e23200", - "sha256:8c5091ebd294f7628eb25ea554852a52058ac81472c921150e3a61cdd68f75a7", - "sha256:944bdc21ebd620eafefc090cdf83158393ec2b1391578359776c00de00e8907a", - "sha256:9c7ac372232c928fff0645d85f273a726970c014749b924ce5710d7d89763a28", - "sha256:d9b338c19fa2412f76e17525c1b4f2c687a55b156320acb588df79f2e6fa9fea", - "sha256:ee5d62d28b854eb61889cde4e1dbc10fbaa5560cb39780c3995f6737f7e82120", - "sha256:f2c2521a8e4d6d769e3234350ba7b65ff5d527137cdcde13ff4d99114b0c8e7d", - "sha256:f6efc9bd72258f89a3816e3a98c09d36f079c223aa345c659622f056b760ab42", - "sha256:f7c5d642db47376a0cc130f0de6d055056e010debdaf0707cd2b0fc7e7ef30ea", - "sha256:fcb6d9afb1b6208b4c712af0dafdc650f518836065df0d4fb1d800f5d6773db2", - "sha256:fcd2572dd4519e8a6642b733cd3a8cfc1ef94bafd0c1ceed9c94fe736cb65b6a" + "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6", + "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d", + "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02", + "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d", + "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3", + "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3", + "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3", + "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66", + "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259", + "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835", + "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd", + "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d", + "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8", + "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07", + "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b", + "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e", + "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6", + "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae", + "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9", + "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d", + "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a", + "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592", + "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218", + "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817", + "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4", + "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410", + "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==1.7.1" + "version": "==1.8.0" }, "mypy-extensions": { "hashes": [ @@ -1420,11 +1379,11 @@ }, "pathspec": { "hashes": [ - "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20", - "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3" + "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", + "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712" ], - "markers": "python_version >= '3.7'", - "version": "==0.11.2" + "markers": "python_version >= '3.8'", + "version": "==0.12.1" }, "pbr": { "hashes": [ @@ -1436,11 +1395,11 @@ }, "platformdirs": { "hashes": [ - "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380", - "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420" + "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068", + "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768" ], "markers": "python_version >= '3.8'", - "version": "==4.1.0" + "version": "==4.2.0" }, "pycodestyle": { "hashes": [ @@ -1452,11 +1411,11 @@ }, "pyflakes": { "hashes": [ - "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774", - "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc" + "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f", + "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a" ], "markers": "python_version >= '3.8'", - "version": "==3.1.0" + "version": "==3.2.0" }, "pygments": { "hashes": [ @@ -1505,6 +1464,7 @@ "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4", "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba", "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8", + "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef", "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5", "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd", "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3", @@ -1540,11 +1500,11 @@ }, "s3transfer": { "hashes": [ - "sha256:368ac6876a9e9ed91f6bc86581e319be08188dc60d50e0d56308ed5765446283", - "sha256:c9e56cbe88b28d8e197cf841f1f0c130f246595e77ae5b5a05b69fe7cb83de76" + "sha256:3cdb40f5cfa6966e812209d0994f2a4709b561c88e90cf00c2696d2df4e56b2e", + "sha256:d0c8bbf672d5eebbe4e57945e23b972d963f07d82f661cabf678a5c88831595b" ], - "markers": "python_version >= '3.7'", - "version": "==0.8.2" + "markers": "python_version >= '3.8'", + "version": "==0.10.0" }, "six": { "hashes": [ @@ -1554,14 +1514,6 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.16.0" }, - "smmap": { - "hashes": [ - "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62", - "sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da" - ], - "markers": "python_version >= '3.7'", - "version": "==5.0.1" - }, "soupsieve": { "hashes": [ "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690", @@ -1596,11 +1548,11 @@ }, "types-awscrt": { "hashes": [ - "sha256:850d5ad95d8f337b15fb154790f39af077faf5c08d43758fd750f379a87d5f73", - "sha256:a577c4d60a7fb7e21b436a73207a66f6ba50329d578b347934c5d99d4d612901" + "sha256:06a859189a329ca8e66d56ceeef2391488e39b878fbd2141f115eab4d416fe22", + "sha256:f61a120d3e98ee1387bc5ca4b93437f258cc5c2af1f55f8634ec4cee5729f178" ], "markers": "python_version >= '3.7' and python_version < '4.0'", - "version": "==0.19.19" + "version": "==0.20.3" }, "types-cachetools": { "hashes": [ @@ -1613,10 +1565,11 @@ }, "types-pytz": { "hashes": [ - "sha256:1999a123a3dc0e39a2ef6d19f3f8584211de9e6a77fe7a0259f04a524e90a5cf", - "sha256:cc23d0192cd49c8f6bba44ee0c81e4586a8f30204970fc0894d209a6b08dab9a" + "sha256:9679eef0365db3af91ef7722c199dbb75ee5c1b67e3c4dd7bfbeb1b8a71c21a3", + "sha256:c93751ee20dfc6e054a0148f8f5227b9a00b79c90a4d3c9f464711a73179c89e" ], - "version": "==2023.3.1.1" + "markers": "python_version >= '3.8'", + "version": "==2024.1.0.20240203" }, "types-pyyaml": { "hashes": [ @@ -1627,29 +1580,29 @@ }, "types-requests": { "hashes": [ - "sha256:b32b9a86beffa876c0c3ac99a4cd3b8b51e973fb8e3bd4e0a6bb32c7efad80fc", - "sha256:dc5852a76f1eaf60eafa81a2e50aefa3d1f015c34cf0cba130930866b1b22a92" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==2.31.0.10" - }, - "types-s3transfer": { - "hashes": [ - "sha256:2e41756fcf94775a9949afa856489ac4570308609b0493dfbd7b4d333eb423e6", - "sha256:5e084ebcf2704281c71b19d5da6e1544b50859367d034b50080d5316a76a9418" - ], - "markers": "python_version >= '3.7' and python_version < '4.0'", - "version": "==0.8.2" - }, - "typing-extensions": { - "hashes": [ - "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0", - "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef" + "sha256:03a28ce1d7cd54199148e043b2079cdded22d6795d19a2c2a6791a4b2b5e2eb5", + "sha256:9592a9a4cb92d6d75d9b491a41477272b710e021011a2a3061157e2fb1f1a5d1" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.8.0" + "version": "==2.31.0.20240125" + }, + "types-s3transfer": { + "hashes": [ + "sha256:35e4998c25df7f8985ad69dedc8e4860e8af3b43b7615e940d53c00d413bdc69", + "sha256:44fcdf0097b924a9aab1ee4baa1179081a9559ca62a88c807e2b256893ce688f" + ], + "markers": "python_version >= '3.7' and python_version < '4.0'", + "version": "==0.10.0" + }, + "typing-extensions": { + "hashes": [ + "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783", + "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==4.9.0" }, "urllib3": { "hashes": [ @@ -1661,11 +1614,11 @@ }, "waitress": { "hashes": [ - "sha256:7500c9625927c8ec60f54377d590f67b30c8e70ef4b8894214ac6e4cad233d2a", - "sha256:780a4082c5fbc0fde6a2fcfe5e26e6efc1e8f425730863c04085769781f51eba" + "sha256:005da479b04134cdd9dd602d1ee7c49d79de0537610d653674cc6cbde222b8a1", + "sha256:2a06f242f4ba0cc563444ca3d1998959447477363a2d7e9b8b4d75d35cfd1669" ], - "markers": "python_full_version >= '3.7.0'", - "version": "==2.1.2" + "markers": "python_full_version >= '3.8.0'", + "version": "==3.0.0" }, "webob": { "hashes": [ diff --git a/src/requirements.txt b/src/requirements.txt index b203f87bb..a748e4b96 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -1,18 +1,18 @@ -i https://pypi.python.org/simple annotated-types==0.6.0; python_version >= '3.8' asgiref==3.7.2; python_version >= '3.7' -boto3==1.33.7; python_version >= '3.7' -botocore==1.33.7; python_version >= '3.7' +boto3==1.34.37; python_version >= '3.8' +botocore==1.34.37; python_version >= '3.8' cachetools==5.3.2; python_version >= '3.7' -certifi==2023.11.17; python_version >= '3.6' +certifi==2024.2.2; python_version >= '3.6' cfenv==0.5.3 -cffi==1.16.0; python_version >= '3.8' +cffi==1.16.0; platform_python_implementation != 'PyPy' charset-normalizer==3.3.2; python_full_version >= '3.7.0' -cryptography==41.0.7; python_version >= '3.7' +cryptography==42.0.2; python_version >= '3.7' defusedxml==0.7.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' dj-database-url==2.1.0 dj-email-url==1.0.6 -django==4.2.7; python_version >= '3.8' +django==4.2.3; python_version >= '3.8' django-allow-cidr==0.7.1 django-auditlog==2.3.0; python_version >= '3.7' django-cache-url==3.4.5 @@ -20,42 +20,42 @@ django-cors-headers==4.3.1; python_version >= '3.8' django-csp==3.7 django-fsm==2.8.1 django-login-required-middleware==0.9.0 -django-phonenumber-field[phonenumberslite]==7.2.0; python_version >= '3.8' +django-phonenumber-field[phonenumberslite]==7.3.0; python_version >= '3.8' django-widget-tweaks==1.5.0; python_version >= '3.8' -environs[django]==9.5.0; python_version >= '3.6' -faker==20.1.0; python_version >= '3.8' +environs[django]==10.3.0; python_version >= '3.8' +faker==23.1.0; python_version >= '3.8' fred-epplib@ git+https://github.com/cisagov/epplib.git@d56d183f1664f34c40ca9716a3a9a345f0ef561c furl==2.1.3 future==0.18.3; python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3' gevent==23.9.1; python_version >= '3.8' -geventconnpool@ git+https://github.com/rasky/geventconnpool.git@1bbb93a714a331a069adf27265fe582d9ba7ecd4 -greenlet==3.0.1; python_version >= '3.7' +geventconnpool@ git+https://github.com/rasky/geventconnpool.git +greenlet==3.0.3; python_version >= '3.7' gunicorn==21.2.0; python_version >= '3.5' idna==3.6; python_version >= '3.5' jmespath==1.0.1; python_version >= '3.7' -lxml==4.9.3; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' -mako==1.3.0; python_version >= '3.8' -markupsafe==2.1.3; python_version >= '3.7' -marshmallow==3.20.1; python_version >= '3.8' +lxml==5.1.0; python_version >= '3.6' +mako==1.3.2; python_version >= '3.8' +markupsafe==2.1.5; python_version >= '3.7' +marshmallow==3.20.2; python_version >= '3.8' oic==1.6.1; python_version ~= '3.7' orderedmultidict==1.0.1 packaging==23.2; python_version >= '3.7' -phonenumberslite==8.13.26 +phonenumberslite==8.13.29 psycopg2-binary==2.9.9; python_version >= '3.7' pycparser==2.21 -pycryptodomex==3.19.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' -pydantic==2.5.2; python_version >= '3.7' -pydantic-core==2.14.5; python_version >= '3.7' +pycryptodomex==3.20.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' +pydantic==2.6.1; python_version >= '3.8' +pydantic-core==2.16.2; python_version >= '3.8' pydantic-settings==2.1.0; python_version >= '3.8' pyjwkest==1.4.2 python-dateutil==2.8.2; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -python-dotenv==1.0.0; python_version >= '3.8' +python-dotenv==1.0.1; python_version >= '3.8' requests==2.31.0; python_version >= '3.7' -s3transfer==0.8.2; python_version >= '3.7' -setuptools==69.0.2; python_version >= '3.8' +s3transfer==0.10.0; python_version >= '3.8' +setuptools==69.0.3; python_version >= '3.8' six==1.16.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' sqlparse==0.4.4; python_version >= '3.5' -typing-extensions==4.8.0; python_version >= '3.8' +typing-extensions==4.9.0; python_version >= '3.8' urllib3==2.0.7; python_version >= '3.7' whitenoise==6.6.0; python_version >= '3.8' zope.event==5.0; python_version >= '3.7' From 9613f14c0144e3742073db7e9f8738095ca16f94 Mon Sep 17 00:00:00 2001 From: CocoByte Date: Wed, 7 Feb 2024 15:46:33 -0700 Subject: [PATCH 07/31] revert geventconnpool --- src/Pipfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Pipfile.lock b/src/Pipfile.lock index 3ac2fad0e..528408952 100644 --- a/src/Pipfile.lock +++ b/src/Pipfile.lock @@ -458,7 +458,7 @@ }, "geventconnpool": { "git": "https://github.com/rasky/geventconnpool.git", - "ref": null + "ref": "1bbb93a714a331a069adf27265fe582d9ba7ecd4" }, "greenlet": { "hashes": [ From 497d11c67cb98f4db93666173a204f0273542616 Mon Sep 17 00:00:00 2001 From: CocoByte Date: Wed, 7 Feb 2024 16:43:16 -0700 Subject: [PATCH 08/31] revert geventconnpool in requirements.txt --- src/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/requirements.txt b/src/requirements.txt index a748e4b96..7c79cf8a3 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -28,7 +28,7 @@ fred-epplib@ git+https://github.com/cisagov/epplib.git@d56d183f1664f34c40ca9716a furl==2.1.3 future==0.18.3; python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3' gevent==23.9.1; python_version >= '3.8' -geventconnpool@ git+https://github.com/rasky/geventconnpool.git +geventconnpool@ git+https://github.com/rasky/geventconnpool.git@1bbb93a714a331a069adf27265fe582d9ba7ecd4 greenlet==3.0.3; python_version >= '3.7' gunicorn==21.2.0; python_version >= '3.5' idna==3.6; python_version >= '3.5' From 39dfb41c2f2db16d7559746226c17911a9ca6ade Mon Sep 17 00:00:00 2001 From: Alysia Broddrick Date: Wed, 7 Feb 2024 16:15:44 -0800 Subject: [PATCH 09/31] ran lint --- src/api/tests/test_available.py | 2 -- src/api/views.py | 1 + src/registrar/admin.py | 1 - src/registrar/apps.py | 1 - src/registrar/config/settings.py | 1 + src/registrar/fixtures_applications.py | 1 - src/registrar/management/commands/cat_files_into_getgov.py | 1 + .../management/commands/generate_current_federal_report.py | 1 + .../management/commands/generate_current_full_report.py | 1 + .../management/commands/patch_federal_agency_info.py | 1 + .../management/commands/utility/epp_data_containers.py | 1 + .../commands/utility/extra_transition_domain_helper.py | 1 + src/registrar/models/contact.py | 1 - src/registrar/models/domain_application.py | 3 --- src/registrar/models/domain_information.py | 1 - src/registrar/models/user_domain_role.py | 2 -- src/registrar/models/verified_by_staff.py | 1 - src/registrar/models/website.py | 1 - src/registrar/no_cache_middleware.py | 1 - src/registrar/templatetags/field_helpers.py | 1 + src/registrar/tests/test_models.py | 2 -- src/registrar/tests/test_models_domain.py | 1 + src/registrar/tests/test_views_application.py | 1 - src/registrar/tests/test_views_domain.py | 1 - src/registrar/utility/email.py | 1 - src/registrar/views/domain.py | 1 - src/registrar/views/utility/mixins.py | 7 ------- src/registrar/views/utility/permission_views.py | 7 ------- 28 files changed, 10 insertions(+), 35 deletions(-) diff --git a/src/api/tests/test_available.py b/src/api/tests/test_available.py index fa9dadcd4..b85ea6335 100644 --- a/src/api/tests/test_available.py +++ b/src/api/tests/test_available.py @@ -19,7 +19,6 @@ API_BASE_PATH = "/api/v1/available/?domain=" class AvailableViewTest(MockEppLib): - """Test that the view function works as expected.""" def setUp(self): @@ -123,7 +122,6 @@ class AvailableViewTest(MockEppLib): class AvailableAPITest(MockEppLib): - """Test that the API can be called as expected.""" def setUp(self): diff --git a/src/api/views.py b/src/api/views.py index f9fa2d1ea..2199e15ac 100644 --- a/src/api/views.py +++ b/src/api/views.py @@ -1,4 +1,5 @@ """Internal API views""" + from django.apps import apps from django.views.decorators.http import require_http_methods from django.http import HttpResponse diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 4034bf35b..c5f5be276 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -739,7 +739,6 @@ class DomainApplicationAdminForm(forms.ModelForm): class DomainApplicationAdmin(ListHeaderAdmin): - """Custom domain applications admin class.""" class InvestigatorFilter(admin.SimpleListFilter): diff --git a/src/registrar/apps.py b/src/registrar/apps.py index 9f1b186ad..fcb5c17fd 100644 --- a/src/registrar/apps.py +++ b/src/registrar/apps.py @@ -2,7 +2,6 @@ from django.apps import AppConfig class RegistrarConfig(AppConfig): - """Configure signal handling for our registrar Django application.""" name = "registrar" diff --git a/src/registrar/config/settings.py b/src/registrar/config/settings.py index 372434887..009baa1c6 100644 --- a/src/registrar/config/settings.py +++ b/src/registrar/config/settings.py @@ -16,6 +16,7 @@ $ docker-compose exec app python manage.py shell ``` """ + import environs from base64 import b64decode from cfenv import AppEnv # type: ignore diff --git a/src/registrar/fixtures_applications.py b/src/registrar/fixtures_applications.py index 659a3040e..3e4e0e362 100644 --- a/src/registrar/fixtures_applications.py +++ b/src/registrar/fixtures_applications.py @@ -201,7 +201,6 @@ class DomainApplicationFixture: class DomainFixture(DomainApplicationFixture): - """Create one domain and permissions on it for each user.""" @classmethod diff --git a/src/registrar/management/commands/cat_files_into_getgov.py b/src/registrar/management/commands/cat_files_into_getgov.py index 4ccb1301b..4fb7ad5b8 100644 --- a/src/registrar/management/commands/cat_files_into_getgov.py +++ b/src/registrar/management/commands/cat_files_into_getgov.py @@ -1,4 +1,5 @@ """Loads files from /tmp into our sandboxes""" + import glob import logging diff --git a/src/registrar/management/commands/generate_current_federal_report.py b/src/registrar/management/commands/generate_current_federal_report.py index 1a123bf5b..6516bf99b 100644 --- a/src/registrar/management/commands/generate_current_federal_report.py +++ b/src/registrar/management/commands/generate_current_federal_report.py @@ -1,4 +1,5 @@ """Generates current-full.csv and current-federal.csv then uploads them to the desired URL.""" + import logging import os diff --git a/src/registrar/management/commands/generate_current_full_report.py b/src/registrar/management/commands/generate_current_full_report.py index 80c031605..be810ee10 100644 --- a/src/registrar/management/commands/generate_current_full_report.py +++ b/src/registrar/management/commands/generate_current_full_report.py @@ -1,4 +1,5 @@ """Generates current-full.csv and current-federal.csv then uploads them to the desired URL.""" + import logging import os diff --git a/src/registrar/management/commands/patch_federal_agency_info.py b/src/registrar/management/commands/patch_federal_agency_info.py index 35642c1bf..b286f1516 100644 --- a/src/registrar/management/commands/patch_federal_agency_info.py +++ b/src/registrar/management/commands/patch_federal_agency_info.py @@ -1,4 +1,5 @@ """Loops through each valid DomainInformation object and updates its agency value""" + import argparse import csv import logging diff --git a/src/registrar/management/commands/utility/epp_data_containers.py b/src/registrar/management/commands/utility/epp_data_containers.py index 1f370dca7..9e5769751 100644 --- a/src/registrar/management/commands/utility/epp_data_containers.py +++ b/src/registrar/management/commands/utility/epp_data_containers.py @@ -5,6 +5,7 @@ Regarding our dataclasses: Not intended to be used as models but rather as an alternative to storing as a dictionary. By keeping it as a dataclass instead of a dictionary, we can maintain data consistency. """ # noqa + from dataclasses import dataclass, field from datetime import date from enum import Enum diff --git a/src/registrar/management/commands/utility/extra_transition_domain_helper.py b/src/registrar/management/commands/utility/extra_transition_domain_helper.py index c082552eb..5c3573fb1 100644 --- a/src/registrar/management/commands/utility/extra_transition_domain_helper.py +++ b/src/registrar/management/commands/utility/extra_transition_domain_helper.py @@ -1,4 +1,5 @@ """""" + import csv from dataclasses import dataclass from datetime import datetime diff --git a/src/registrar/models/contact.py b/src/registrar/models/contact.py index ff7389780..d316cde4c 100644 --- a/src/registrar/models/contact.py +++ b/src/registrar/models/contact.py @@ -6,7 +6,6 @@ from .utility.time_stamped_model import TimeStampedModel class Contact(TimeStampedModel): - """Contact information follows a similar pattern for each contact.""" user = models.OneToOneField( diff --git a/src/registrar/models/domain_application.py b/src/registrar/models/domain_application.py index c37fc19b5..307115112 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_application.py @@ -17,7 +17,6 @@ logger = logging.getLogger(__name__) class DomainApplication(TimeStampedModel): - """A registrant's application for a new domain.""" # Constants for choice fields @@ -97,7 +96,6 @@ class DomainApplication(TimeStampedModel): ARMED_FORCES_AP = "AP", "Armed Forces Pacific (AP)" class OrganizationChoices(models.TextChoices): - """ Primary organization choices: For use in django admin @@ -114,7 +112,6 @@ class DomainApplication(TimeStampedModel): SCHOOL_DISTRICT = "school_district", "School district" class OrganizationChoicesVerbose(models.TextChoices): - """ Secondary organization choices For use in the application form and on the templates diff --git a/src/registrar/models/domain_information.py b/src/registrar/models/domain_information.py index 65d099e5a..acaa330bb 100644 --- a/src/registrar/models/domain_information.py +++ b/src/registrar/models/domain_information.py @@ -14,7 +14,6 @@ logger = logging.getLogger(__name__) class DomainInformation(TimeStampedModel): - """A registrant's domain information for that domain, exported from DomainApplication. We use these field from DomainApplication with few exceptions which are 'removed' via pop at the bottom of this file. Most of design for domain diff --git a/src/registrar/models/user_domain_role.py b/src/registrar/models/user_domain_role.py index 479f75089..6e915e4af 100644 --- a/src/registrar/models/user_domain_role.py +++ b/src/registrar/models/user_domain_role.py @@ -4,11 +4,9 @@ from .utility.time_stamped_model import TimeStampedModel class UserDomainRole(TimeStampedModel): - """This is a linking table that connects a user with a role on a domain.""" class Roles(models.TextChoices): - """The possible roles are listed here. Implementation of the named roles for allowing particular operations happens diff --git a/src/registrar/models/verified_by_staff.py b/src/registrar/models/verified_by_staff.py index 4c9e76e9d..a6d861504 100644 --- a/src/registrar/models/verified_by_staff.py +++ b/src/registrar/models/verified_by_staff.py @@ -4,7 +4,6 @@ from .utility.time_stamped_model import TimeStampedModel class VerifiedByStaff(TimeStampedModel): - """emails that get added to this table will bypass ial2 on login.""" email = models.EmailField( diff --git a/src/registrar/models/website.py b/src/registrar/models/website.py index d21564531..0b337e397 100644 --- a/src/registrar/models/website.py +++ b/src/registrar/models/website.py @@ -4,7 +4,6 @@ from .utility.time_stamped_model import TimeStampedModel class Website(TimeStampedModel): - """Keep domain names in their own table so that applications can refer to many of them.""" diff --git a/src/registrar/no_cache_middleware.py b/src/registrar/no_cache_middleware.py index 6f509b9d6..5edfca20e 100644 --- a/src/registrar/no_cache_middleware.py +++ b/src/registrar/no_cache_middleware.py @@ -6,7 +6,6 @@ better caching responses. class NoCacheMiddleware: - """Middleware to add a single header to every response.""" def __init__(self, get_response): diff --git a/src/registrar/templatetags/field_helpers.py b/src/registrar/templatetags/field_helpers.py index bc296753e..811897908 100644 --- a/src/registrar/templatetags/field_helpers.py +++ b/src/registrar/templatetags/field_helpers.py @@ -1,4 +1,5 @@ """Custom field helpers for our inputs.""" + import re from django import template diff --git a/src/registrar/tests/test_models.py b/src/registrar/tests/test_models.py index d7c8960f6..41fa75f1d 100644 --- a/src/registrar/tests/test_models.py +++ b/src/registrar/tests/test_models.py @@ -600,7 +600,6 @@ class TestPermissions(TestCase): class TestDomainInformation(TestCase): - """Test the DomainInformation model, when approved or otherwise""" def setUp(self): @@ -653,7 +652,6 @@ class TestDomainInformation(TestCase): class TestInvitations(TestCase): - """Test the retrieval of invitations.""" def setUp(self): diff --git a/src/registrar/tests/test_models_domain.py b/src/registrar/tests/test_models_domain.py index ca0a5e8d8..1c4d2521e 100644 --- a/src/registrar/tests/test_models_domain.py +++ b/src/registrar/tests/test_models_domain.py @@ -3,6 +3,7 @@ Feature being tested: Registry Integration This file tests the various ways in which the registrar interacts with the registry. """ + from django.test import TestCase from django.db.utils import IntegrityError from unittest.mock import MagicMock, patch, call diff --git a/src/registrar/tests/test_views_application.py b/src/registrar/tests/test_views_application.py index 02fe5ff76..2b08d8d74 100644 --- a/src/registrar/tests/test_views_application.py +++ b/src/registrar/tests/test_views_application.py @@ -28,7 +28,6 @@ logger = logging.getLogger(__name__) class DomainApplicationTests(TestWithUser, WebTest): - """Webtests for domain application to test filling and submitting.""" # Doesn't work with CSRF checking diff --git a/src/registrar/tests/test_views_domain.py b/src/registrar/tests/test_views_domain.py index c9422e700..2c8e796ac 100644 --- a/src/registrar/tests/test_views_domain.py +++ b/src/registrar/tests/test_views_domain.py @@ -1236,7 +1236,6 @@ class TestDomainSecurityEmail(TestDomainOverview): class TestDomainDNSSEC(TestDomainOverview): - """MockEPPLib is already inherited.""" def test_dnssec_page_refreshes_enable_button(self): diff --git a/src/registrar/utility/email.py b/src/registrar/utility/email.py index d56c02cbf..461637f23 100644 --- a/src/registrar/utility/email.py +++ b/src/registrar/utility/email.py @@ -10,7 +10,6 @@ logger = logging.getLogger(__name__) class EmailSendingError(RuntimeError): - """Local error for handling all failures when sending email.""" pass diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py index 04fe1ce3a..d5f8f67b4 100644 --- a/src/registrar/views/domain.py +++ b/src/registrar/views/domain.py @@ -135,7 +135,6 @@ class DomainFormBaseView(DomainBaseView, FormMixin): class DomainView(DomainBaseView): - """Domain detail overview page.""" template_name = "domain_detail.html" diff --git a/src/registrar/views/utility/mixins.py b/src/registrar/views/utility/mixins.py index b2c4cb364..8de75e151 100644 --- a/src/registrar/views/utility/mixins.py +++ b/src/registrar/views/utility/mixins.py @@ -146,7 +146,6 @@ class OrderableFieldsMixin: class PermissionsLoginMixin(PermissionRequiredMixin): - """Mixin that redirects to login page if not logged in, otherwise 403.""" def handle_no_permission(self): @@ -155,7 +154,6 @@ class PermissionsLoginMixin(PermissionRequiredMixin): class DomainPermission(PermissionsLoginMixin): - """Permission mixin that redirects to domain if user has access, otherwise 403""" @@ -264,7 +262,6 @@ class DomainPermission(PermissionsLoginMixin): class DomainApplicationPermission(PermissionsLoginMixin): - """Permission mixin that redirects to domain application if user has access, otherwise 403""" @@ -287,7 +284,6 @@ class DomainApplicationPermission(PermissionsLoginMixin): class UserDeleteDomainRolePermission(PermissionsLoginMixin): - """Permission mixin for UserDomainRole if user has access, otherwise 403""" @@ -324,7 +320,6 @@ class UserDeleteDomainRolePermission(PermissionsLoginMixin): class DomainApplicationPermissionWithdraw(PermissionsLoginMixin): - """Permission mixin that redirects to withdraw action on domain application if user has access, otherwise 403""" @@ -347,7 +342,6 @@ class DomainApplicationPermissionWithdraw(PermissionsLoginMixin): class ApplicationWizardPermission(PermissionsLoginMixin): - """Permission mixin that redirects to start or edit domain application if user has access, otherwise 403""" @@ -365,7 +359,6 @@ class ApplicationWizardPermission(PermissionsLoginMixin): class DomainInvitationPermission(PermissionsLoginMixin): - """Permission mixin that redirects to domain invitation if user has access, otherwise 403" diff --git a/src/registrar/views/utility/permission_views.py b/src/registrar/views/utility/permission_views.py index 54c96d602..02d3db96d 100644 --- a/src/registrar/views/utility/permission_views.py +++ b/src/registrar/views/utility/permission_views.py @@ -20,7 +20,6 @@ logger = logging.getLogger(__name__) class DomainPermissionView(DomainPermission, DetailView, abc.ABC): - """Abstract base view for domains that enforces permissions. This abstract view cannot be instantiated. Actual views must specify @@ -58,7 +57,6 @@ class DomainPermissionView(DomainPermission, DetailView, abc.ABC): class DomainApplicationPermissionView(DomainApplicationPermission, DetailView, abc.ABC): - """Abstract base view for domain applications that enforces permissions This abstract view cannot be instantiated. Actual views must specify @@ -78,7 +76,6 @@ class DomainApplicationPermissionView(DomainApplicationPermission, DetailView, a class DomainApplicationPermissionWithdrawView(DomainApplicationPermissionWithdraw, DetailView, abc.ABC): - """Abstract base view for domain application withdraw function This abstract view cannot be instantiated. Actual views must specify @@ -98,7 +95,6 @@ class DomainApplicationPermissionWithdrawView(DomainApplicationPermissionWithdra class ApplicationWizardPermissionView(ApplicationWizardPermission, TemplateView, abc.ABC): - """Abstract base view for the application form that enforces permissions This abstract view cannot be instantiated. Actual views must specify @@ -113,7 +109,6 @@ class ApplicationWizardPermissionView(ApplicationWizardPermission, TemplateView, class DomainInvitationPermissionDeleteView(DomainInvitationPermission, DeleteView, abc.ABC): - """Abstract view for deleting a domain invitation. This one is fairly specialized, but this is the only thing that we do @@ -127,7 +122,6 @@ class DomainInvitationPermissionDeleteView(DomainInvitationPermission, DeleteVie class DomainApplicationPermissionDeleteView(DomainApplicationPermission, DeleteView, abc.ABC): - """Abstract view for deleting a DomainApplication.""" model = DomainApplication @@ -135,7 +129,6 @@ class DomainApplicationPermissionDeleteView(DomainApplicationPermission, DeleteV class UserDomainRolePermissionDeleteView(UserDeleteDomainRolePermission, DeleteView, abc.ABC): - """Abstract base view for deleting a UserDomainRole. This abstract view cannot be instantiated. Actual views must specify From 1e5f97720817356e7d3b3def66efdbd97a60747c Mon Sep 17 00:00:00 2001 From: CocoByte Date: Wed, 7 Feb 2024 18:17:48 -0700 Subject: [PATCH 10/31] updated django to 4.2.10 & linted --- src/Pipfile | 2 +- src/Pipfile.lock | 14 +++++++------- src/api/tests/test_available.py | 2 -- src/api/views.py | 1 + src/registrar/admin.py | 1 - src/registrar/apps.py | 1 - src/registrar/config/settings.py | 1 + src/registrar/fixtures_applications.py | 1 - .../management/commands/cat_files_into_getgov.py | 1 + .../commands/generate_current_federal_report.py | 1 + .../commands/generate_current_full_report.py | 1 + .../commands/patch_federal_agency_info.py | 1 + .../commands/utility/epp_data_containers.py | 1 + .../utility/extra_transition_domain_helper.py | 1 + src/registrar/models/contact.py | 1 - src/registrar/models/domain_application.py | 3 --- src/registrar/models/domain_information.py | 1 - src/registrar/models/user_domain_role.py | 2 -- src/registrar/models/verified_by_staff.py | 1 - src/registrar/models/website.py | 1 - src/registrar/no_cache_middleware.py | 1 - src/registrar/templatetags/field_helpers.py | 1 + src/registrar/tests/test_models.py | 2 -- src/registrar/tests/test_models_domain.py | 1 + src/registrar/tests/test_views_application.py | 1 - src/registrar/tests/test_views_domain.py | 1 - src/registrar/utility/email.py | 1 - src/registrar/views/domain.py | 1 - src/registrar/views/utility/mixins.py | 7 ------- src/registrar/views/utility/permission_views.py | 7 ------- src/requirements.txt | 2 +- 31 files changed, 19 insertions(+), 44 deletions(-) diff --git a/src/Pipfile b/src/Pipfile index a0ada646a..51417d578 100644 --- a/src/Pipfile +++ b/src/Pipfile @@ -4,7 +4,7 @@ verify_ssl = true name = "pypi" [packages] -django = "4.2.3" +django = "4.2.10" cfenv = "*" django-cors-headers = "*" pycryptodomex = "*" diff --git a/src/Pipfile.lock b/src/Pipfile.lock index 528408952..7d511a0e5 100644 --- a/src/Pipfile.lock +++ b/src/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "8db8d1bdb9c343c50771fc8bd001c555037dc3606a48dcafb3800d743fb95f3e" + "sha256": "a672aeb8951fd850e90ad87c6f03cf71e2fc2b387d56fd3942361cb0b45bb449" }, "pipfile-spec": 6, "requires": {}, @@ -288,12 +288,12 @@ }, "django": { "hashes": [ - "sha256:45a747e1c5b3d6df1b141b1481e193b033fd1fdbda3ff52677dc81afdaacbaed", - "sha256:f7c7852a5ac5a3da5a8d5b35cc6168f31b605971441798dac845f17ca8028039" + "sha256:a2d4c4d4ea0b6f0895acde632071aff6400bfc331228fc978b05452a0ff3e9f1", + "sha256:b1260ed381b10a11753c73444408e19869f3241fc45c985cd55a30177c789d13" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.2.3" + "version": "==4.2.10" }, "django-allow-cidr": { "hashes": [ @@ -1230,12 +1230,12 @@ }, "django": { "hashes": [ - "sha256:45a747e1c5b3d6df1b141b1481e193b033fd1fdbda3ff52677dc81afdaacbaed", - "sha256:f7c7852a5ac5a3da5a8d5b35cc6168f31b605971441798dac845f17ca8028039" + "sha256:a2d4c4d4ea0b6f0895acde632071aff6400bfc331228fc978b05452a0ff3e9f1", + "sha256:b1260ed381b10a11753c73444408e19869f3241fc45c985cd55a30177c789d13" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.2.3" + "version": "==4.2.10" }, "django-debug-toolbar": { "hashes": [ diff --git a/src/api/tests/test_available.py b/src/api/tests/test_available.py index fa9dadcd4..b85ea6335 100644 --- a/src/api/tests/test_available.py +++ b/src/api/tests/test_available.py @@ -19,7 +19,6 @@ API_BASE_PATH = "/api/v1/available/?domain=" class AvailableViewTest(MockEppLib): - """Test that the view function works as expected.""" def setUp(self): @@ -123,7 +122,6 @@ class AvailableViewTest(MockEppLib): class AvailableAPITest(MockEppLib): - """Test that the API can be called as expected.""" def setUp(self): diff --git a/src/api/views.py b/src/api/views.py index f9fa2d1ea..2199e15ac 100644 --- a/src/api/views.py +++ b/src/api/views.py @@ -1,4 +1,5 @@ """Internal API views""" + from django.apps import apps from django.views.decorators.http import require_http_methods from django.http import HttpResponse diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 4034bf35b..c5f5be276 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -739,7 +739,6 @@ class DomainApplicationAdminForm(forms.ModelForm): class DomainApplicationAdmin(ListHeaderAdmin): - """Custom domain applications admin class.""" class InvestigatorFilter(admin.SimpleListFilter): diff --git a/src/registrar/apps.py b/src/registrar/apps.py index 9f1b186ad..fcb5c17fd 100644 --- a/src/registrar/apps.py +++ b/src/registrar/apps.py @@ -2,7 +2,6 @@ from django.apps import AppConfig class RegistrarConfig(AppConfig): - """Configure signal handling for our registrar Django application.""" name = "registrar" diff --git a/src/registrar/config/settings.py b/src/registrar/config/settings.py index 372434887..009baa1c6 100644 --- a/src/registrar/config/settings.py +++ b/src/registrar/config/settings.py @@ -16,6 +16,7 @@ $ docker-compose exec app python manage.py shell ``` """ + import environs from base64 import b64decode from cfenv import AppEnv # type: ignore diff --git a/src/registrar/fixtures_applications.py b/src/registrar/fixtures_applications.py index 659a3040e..3e4e0e362 100644 --- a/src/registrar/fixtures_applications.py +++ b/src/registrar/fixtures_applications.py @@ -201,7 +201,6 @@ class DomainApplicationFixture: class DomainFixture(DomainApplicationFixture): - """Create one domain and permissions on it for each user.""" @classmethod diff --git a/src/registrar/management/commands/cat_files_into_getgov.py b/src/registrar/management/commands/cat_files_into_getgov.py index 4ccb1301b..4fb7ad5b8 100644 --- a/src/registrar/management/commands/cat_files_into_getgov.py +++ b/src/registrar/management/commands/cat_files_into_getgov.py @@ -1,4 +1,5 @@ """Loads files from /tmp into our sandboxes""" + import glob import logging diff --git a/src/registrar/management/commands/generate_current_federal_report.py b/src/registrar/management/commands/generate_current_federal_report.py index 1a123bf5b..6516bf99b 100644 --- a/src/registrar/management/commands/generate_current_federal_report.py +++ b/src/registrar/management/commands/generate_current_federal_report.py @@ -1,4 +1,5 @@ """Generates current-full.csv and current-federal.csv then uploads them to the desired URL.""" + import logging import os diff --git a/src/registrar/management/commands/generate_current_full_report.py b/src/registrar/management/commands/generate_current_full_report.py index 80c031605..be810ee10 100644 --- a/src/registrar/management/commands/generate_current_full_report.py +++ b/src/registrar/management/commands/generate_current_full_report.py @@ -1,4 +1,5 @@ """Generates current-full.csv and current-federal.csv then uploads them to the desired URL.""" + import logging import os diff --git a/src/registrar/management/commands/patch_federal_agency_info.py b/src/registrar/management/commands/patch_federal_agency_info.py index 35642c1bf..b286f1516 100644 --- a/src/registrar/management/commands/patch_federal_agency_info.py +++ b/src/registrar/management/commands/patch_federal_agency_info.py @@ -1,4 +1,5 @@ """Loops through each valid DomainInformation object and updates its agency value""" + import argparse import csv import logging diff --git a/src/registrar/management/commands/utility/epp_data_containers.py b/src/registrar/management/commands/utility/epp_data_containers.py index 1f370dca7..9e5769751 100644 --- a/src/registrar/management/commands/utility/epp_data_containers.py +++ b/src/registrar/management/commands/utility/epp_data_containers.py @@ -5,6 +5,7 @@ Regarding our dataclasses: Not intended to be used as models but rather as an alternative to storing as a dictionary. By keeping it as a dataclass instead of a dictionary, we can maintain data consistency. """ # noqa + from dataclasses import dataclass, field from datetime import date from enum import Enum diff --git a/src/registrar/management/commands/utility/extra_transition_domain_helper.py b/src/registrar/management/commands/utility/extra_transition_domain_helper.py index c082552eb..5c3573fb1 100644 --- a/src/registrar/management/commands/utility/extra_transition_domain_helper.py +++ b/src/registrar/management/commands/utility/extra_transition_domain_helper.py @@ -1,4 +1,5 @@ """""" + import csv from dataclasses import dataclass from datetime import datetime diff --git a/src/registrar/models/contact.py b/src/registrar/models/contact.py index ff7389780..d316cde4c 100644 --- a/src/registrar/models/contact.py +++ b/src/registrar/models/contact.py @@ -6,7 +6,6 @@ from .utility.time_stamped_model import TimeStampedModel class Contact(TimeStampedModel): - """Contact information follows a similar pattern for each contact.""" user = models.OneToOneField( diff --git a/src/registrar/models/domain_application.py b/src/registrar/models/domain_application.py index c37fc19b5..307115112 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_application.py @@ -17,7 +17,6 @@ logger = logging.getLogger(__name__) class DomainApplication(TimeStampedModel): - """A registrant's application for a new domain.""" # Constants for choice fields @@ -97,7 +96,6 @@ class DomainApplication(TimeStampedModel): ARMED_FORCES_AP = "AP", "Armed Forces Pacific (AP)" class OrganizationChoices(models.TextChoices): - """ Primary organization choices: For use in django admin @@ -114,7 +112,6 @@ class DomainApplication(TimeStampedModel): SCHOOL_DISTRICT = "school_district", "School district" class OrganizationChoicesVerbose(models.TextChoices): - """ Secondary organization choices For use in the application form and on the templates diff --git a/src/registrar/models/domain_information.py b/src/registrar/models/domain_information.py index 65d099e5a..acaa330bb 100644 --- a/src/registrar/models/domain_information.py +++ b/src/registrar/models/domain_information.py @@ -14,7 +14,6 @@ logger = logging.getLogger(__name__) class DomainInformation(TimeStampedModel): - """A registrant's domain information for that domain, exported from DomainApplication. We use these field from DomainApplication with few exceptions which are 'removed' via pop at the bottom of this file. Most of design for domain diff --git a/src/registrar/models/user_domain_role.py b/src/registrar/models/user_domain_role.py index 479f75089..6e915e4af 100644 --- a/src/registrar/models/user_domain_role.py +++ b/src/registrar/models/user_domain_role.py @@ -4,11 +4,9 @@ from .utility.time_stamped_model import TimeStampedModel class UserDomainRole(TimeStampedModel): - """This is a linking table that connects a user with a role on a domain.""" class Roles(models.TextChoices): - """The possible roles are listed here. Implementation of the named roles for allowing particular operations happens diff --git a/src/registrar/models/verified_by_staff.py b/src/registrar/models/verified_by_staff.py index 4c9e76e9d..a6d861504 100644 --- a/src/registrar/models/verified_by_staff.py +++ b/src/registrar/models/verified_by_staff.py @@ -4,7 +4,6 @@ from .utility.time_stamped_model import TimeStampedModel class VerifiedByStaff(TimeStampedModel): - """emails that get added to this table will bypass ial2 on login.""" email = models.EmailField( diff --git a/src/registrar/models/website.py b/src/registrar/models/website.py index d21564531..0b337e397 100644 --- a/src/registrar/models/website.py +++ b/src/registrar/models/website.py @@ -4,7 +4,6 @@ from .utility.time_stamped_model import TimeStampedModel class Website(TimeStampedModel): - """Keep domain names in their own table so that applications can refer to many of them.""" diff --git a/src/registrar/no_cache_middleware.py b/src/registrar/no_cache_middleware.py index 6f509b9d6..5edfca20e 100644 --- a/src/registrar/no_cache_middleware.py +++ b/src/registrar/no_cache_middleware.py @@ -6,7 +6,6 @@ better caching responses. class NoCacheMiddleware: - """Middleware to add a single header to every response.""" def __init__(self, get_response): diff --git a/src/registrar/templatetags/field_helpers.py b/src/registrar/templatetags/field_helpers.py index bc296753e..811897908 100644 --- a/src/registrar/templatetags/field_helpers.py +++ b/src/registrar/templatetags/field_helpers.py @@ -1,4 +1,5 @@ """Custom field helpers for our inputs.""" + import re from django import template diff --git a/src/registrar/tests/test_models.py b/src/registrar/tests/test_models.py index d7c8960f6..41fa75f1d 100644 --- a/src/registrar/tests/test_models.py +++ b/src/registrar/tests/test_models.py @@ -600,7 +600,6 @@ class TestPermissions(TestCase): class TestDomainInformation(TestCase): - """Test the DomainInformation model, when approved or otherwise""" def setUp(self): @@ -653,7 +652,6 @@ class TestDomainInformation(TestCase): class TestInvitations(TestCase): - """Test the retrieval of invitations.""" def setUp(self): diff --git a/src/registrar/tests/test_models_domain.py b/src/registrar/tests/test_models_domain.py index ca0a5e8d8..1c4d2521e 100644 --- a/src/registrar/tests/test_models_domain.py +++ b/src/registrar/tests/test_models_domain.py @@ -3,6 +3,7 @@ Feature being tested: Registry Integration This file tests the various ways in which the registrar interacts with the registry. """ + from django.test import TestCase from django.db.utils import IntegrityError from unittest.mock import MagicMock, patch, call diff --git a/src/registrar/tests/test_views_application.py b/src/registrar/tests/test_views_application.py index 02fe5ff76..2b08d8d74 100644 --- a/src/registrar/tests/test_views_application.py +++ b/src/registrar/tests/test_views_application.py @@ -28,7 +28,6 @@ logger = logging.getLogger(__name__) class DomainApplicationTests(TestWithUser, WebTest): - """Webtests for domain application to test filling and submitting.""" # Doesn't work with CSRF checking diff --git a/src/registrar/tests/test_views_domain.py b/src/registrar/tests/test_views_domain.py index c9422e700..2c8e796ac 100644 --- a/src/registrar/tests/test_views_domain.py +++ b/src/registrar/tests/test_views_domain.py @@ -1236,7 +1236,6 @@ class TestDomainSecurityEmail(TestDomainOverview): class TestDomainDNSSEC(TestDomainOverview): - """MockEPPLib is already inherited.""" def test_dnssec_page_refreshes_enable_button(self): diff --git a/src/registrar/utility/email.py b/src/registrar/utility/email.py index d56c02cbf..461637f23 100644 --- a/src/registrar/utility/email.py +++ b/src/registrar/utility/email.py @@ -10,7 +10,6 @@ logger = logging.getLogger(__name__) class EmailSendingError(RuntimeError): - """Local error for handling all failures when sending email.""" pass diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py index 04fe1ce3a..d5f8f67b4 100644 --- a/src/registrar/views/domain.py +++ b/src/registrar/views/domain.py @@ -135,7 +135,6 @@ class DomainFormBaseView(DomainBaseView, FormMixin): class DomainView(DomainBaseView): - """Domain detail overview page.""" template_name = "domain_detail.html" diff --git a/src/registrar/views/utility/mixins.py b/src/registrar/views/utility/mixins.py index b2c4cb364..8de75e151 100644 --- a/src/registrar/views/utility/mixins.py +++ b/src/registrar/views/utility/mixins.py @@ -146,7 +146,6 @@ class OrderableFieldsMixin: class PermissionsLoginMixin(PermissionRequiredMixin): - """Mixin that redirects to login page if not logged in, otherwise 403.""" def handle_no_permission(self): @@ -155,7 +154,6 @@ class PermissionsLoginMixin(PermissionRequiredMixin): class DomainPermission(PermissionsLoginMixin): - """Permission mixin that redirects to domain if user has access, otherwise 403""" @@ -264,7 +262,6 @@ class DomainPermission(PermissionsLoginMixin): class DomainApplicationPermission(PermissionsLoginMixin): - """Permission mixin that redirects to domain application if user has access, otherwise 403""" @@ -287,7 +284,6 @@ class DomainApplicationPermission(PermissionsLoginMixin): class UserDeleteDomainRolePermission(PermissionsLoginMixin): - """Permission mixin for UserDomainRole if user has access, otherwise 403""" @@ -324,7 +320,6 @@ class UserDeleteDomainRolePermission(PermissionsLoginMixin): class DomainApplicationPermissionWithdraw(PermissionsLoginMixin): - """Permission mixin that redirects to withdraw action on domain application if user has access, otherwise 403""" @@ -347,7 +342,6 @@ class DomainApplicationPermissionWithdraw(PermissionsLoginMixin): class ApplicationWizardPermission(PermissionsLoginMixin): - """Permission mixin that redirects to start or edit domain application if user has access, otherwise 403""" @@ -365,7 +359,6 @@ class ApplicationWizardPermission(PermissionsLoginMixin): class DomainInvitationPermission(PermissionsLoginMixin): - """Permission mixin that redirects to domain invitation if user has access, otherwise 403" diff --git a/src/registrar/views/utility/permission_views.py b/src/registrar/views/utility/permission_views.py index 54c96d602..02d3db96d 100644 --- a/src/registrar/views/utility/permission_views.py +++ b/src/registrar/views/utility/permission_views.py @@ -20,7 +20,6 @@ logger = logging.getLogger(__name__) class DomainPermissionView(DomainPermission, DetailView, abc.ABC): - """Abstract base view for domains that enforces permissions. This abstract view cannot be instantiated. Actual views must specify @@ -58,7 +57,6 @@ class DomainPermissionView(DomainPermission, DetailView, abc.ABC): class DomainApplicationPermissionView(DomainApplicationPermission, DetailView, abc.ABC): - """Abstract base view for domain applications that enforces permissions This abstract view cannot be instantiated. Actual views must specify @@ -78,7 +76,6 @@ class DomainApplicationPermissionView(DomainApplicationPermission, DetailView, a class DomainApplicationPermissionWithdrawView(DomainApplicationPermissionWithdraw, DetailView, abc.ABC): - """Abstract base view for domain application withdraw function This abstract view cannot be instantiated. Actual views must specify @@ -98,7 +95,6 @@ class DomainApplicationPermissionWithdrawView(DomainApplicationPermissionWithdra class ApplicationWizardPermissionView(ApplicationWizardPermission, TemplateView, abc.ABC): - """Abstract base view for the application form that enforces permissions This abstract view cannot be instantiated. Actual views must specify @@ -113,7 +109,6 @@ class ApplicationWizardPermissionView(ApplicationWizardPermission, TemplateView, class DomainInvitationPermissionDeleteView(DomainInvitationPermission, DeleteView, abc.ABC): - """Abstract view for deleting a domain invitation. This one is fairly specialized, but this is the only thing that we do @@ -127,7 +122,6 @@ class DomainInvitationPermissionDeleteView(DomainInvitationPermission, DeleteVie class DomainApplicationPermissionDeleteView(DomainApplicationPermission, DeleteView, abc.ABC): - """Abstract view for deleting a DomainApplication.""" model = DomainApplication @@ -135,7 +129,6 @@ class DomainApplicationPermissionDeleteView(DomainApplicationPermission, DeleteV class UserDomainRolePermissionDeleteView(UserDeleteDomainRolePermission, DeleteView, abc.ABC): - """Abstract base view for deleting a UserDomainRole. This abstract view cannot be instantiated. Actual views must specify diff --git a/src/requirements.txt b/src/requirements.txt index 7c79cf8a3..a6130a3bf 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -12,7 +12,7 @@ cryptography==42.0.2; python_version >= '3.7' defusedxml==0.7.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' dj-database-url==2.1.0 dj-email-url==1.0.6 -django==4.2.3; python_version >= '3.8' +django==4.2.10; python_version >= '3.8' django-allow-cidr==0.7.1 django-auditlog==2.3.0; python_version >= '3.7' django-cache-url==3.4.5 From 8ed88aa137b5093b323cd1bc4102e7ee14d9af12 Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Mon, 12 Feb 2024 10:02:55 -0800 Subject: [PATCH 11/31] Add conditionals for domain managers --- src/registrar/utility/csv_export.py | 53 ++++++++++++++++------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/src/registrar/utility/csv_export.py b/src/registrar/utility/csv_export.py index 64afd2d06..fc3faae05 100644 --- a/src/registrar/utility/csv_export.py +++ b/src/registrar/utility/csv_export.py @@ -14,14 +14,14 @@ from registrar.utility.enums import DefaultEmail logger = logging.getLogger(__name__) -def write_header(writer, columns, max_dm_count): +def write_header(writer, columns, max_dm_count, get_domain_managers): """ Receives params from the parent methods and outputs a CSV with a header row. Works with write_header as long as the same writer object is passed. """ - - for i in range(1, max_dm_count + 1): - columns.append(f"Domain manager email {i}") + if get_domain_managers: + for i in range(1, max_dm_count + 1): + columns.append(f"Domain manager email {i}") writer.writerow("hello") writer.writerow(columns) @@ -48,7 +48,7 @@ def get_domain_infos(filter_condition, sort_fields): return domain_infos_cleaned -def parse_row(columns, domain_info: DomainInformation, security_emails_dict=None): +def parse_row(columns, domain_info: DomainInformation, get_domain_managers, security_emails_dict=None): """Given a set of columns, generate a new row from cleaned column data""" # Domain should never be none when parsing this information @@ -97,12 +97,13 @@ def parse_row(columns, domain_info: DomainInformation, security_emails_dict=None "Deleted": domain.deleted, } - # Get each domain managers email and add to list - dm_emails = [dm.email for dm in domain.permissions] + if get_domain_managers: + # Get each domain managers email and add to list + dm_emails = [dm.email for dm in domain.permissions] - # Matching header for domain managers to be dynamic - for i, dm_email in enumerate(dm_emails, start=1): - FIELDS[f"Domain Manager email {i}":dm_email] + # Matching header for domain managers to be dynamic + for i, dm_email in enumerate(dm_emails, start=1): + FIELDS[f"Domain Manager email {i}":dm_email] row = [FIELDS.get(column, "") for column in columns] return row @@ -113,12 +114,17 @@ def write_body( columns, sort_fields, filter_condition, + get_domain_managers=False, ): """ Receives params from the parent methods and outputs a CSV with fltered and sorted domains. Works with write_header as longas the same writer object is passed. """ + # We only want to write the domain manager information for export_thing_here so we have to make it conditional + + # Trying to make the domain managers logic conditional + # Get the domainInfos all_domain_infos = get_domain_infos(filter_condition, sort_fields) @@ -151,12 +157,12 @@ def write_body( rows = [] for domain_info in page.object_list: # Get count of all the domain managers for an account - dm_count = len(domain_info.domain.permissions) - if dm_count > max_dm_count: - max_dm_count = dm_count - + if get_domain_managers: + dm_count = len(domain_info.domain.permissions) + if dm_count > max_dm_count: + max_dm_count = dm_count try: - row = parse_row(columns, domain_info, security_emails_dict) + row = parse_row(columns, domain_info, security_emails_dict, get_domain_managers) rows.append(row) except ValueError: # This should not happen. If it does, just skip this row. @@ -165,8 +171,8 @@ def write_body( continue # We only want this to run once just for the column header - if paginator_ran is False: - write_header(writer, columns, max_dm_count) + if paginator_ran is False and "Domain name" in columns: + write_header(writer, columns, max_dm_count, get_domain_managers) writer.writerows(rows) paginator_ran = True @@ -189,14 +195,9 @@ def export_data_type_to_csv(csv_file): "AO", "AO email", "Security contact email", - "Domain Manager email", + # For domain manager we are pass it in as a parameter below in write_body ] - # STUCK HERE - - # So the problem is we don't even have access to domains or a count here. - # We could pass it in, but it's messy. Maybe helper function? Seems repetitive - # Coalesce is used to replace federal_type of None with ZZZZZ sort_fields = [ "organization_type", @@ -212,7 +213,7 @@ def export_data_type_to_csv(csv_file): ], } # write_header(writer, columns) - write_body(writer, columns, sort_fields, filter_condition) + write_body(writer, columns, sort_fields, filter_condition, True) def export_data_full_to_csv(csv_file): @@ -345,5 +346,9 @@ def export_data_growth_to_csv(csv_file, start_date, end_date): } # write_header(writer, columns) + # Domains that got created write_body(writer, columns, sort_fields, filter_condition) + # Domains that got deleted + # Have a way to skip the header for this one + write_body(writer, columns, sort_fields_for_deleted_domains, filter_condition_for_deleted_domains) From ee76372a19ee90aed70cfa47745527037d99de26 Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Mon, 12 Feb 2024 10:16:45 -0800 Subject: [PATCH 12/31] Add comment to jumpstart deploy --- src/registrar/utility/csv_export.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/registrar/utility/csv_export.py b/src/registrar/utility/csv_export.py index fa252112d..9ffbb057c 100644 --- a/src/registrar/utility/csv_export.py +++ b/src/registrar/utility/csv_export.py @@ -19,11 +19,13 @@ def write_header(writer, columns, max_dm_count, get_domain_managers): Receives params from the parent methods and outputs a CSV with a header row. Works with write_header as long as the same writer object is passed. """ + + # If we have domain managers, set column title dynamically here if get_domain_managers: for i in range(1, max_dm_count + 1): columns.append(f"Domain manager email {i}") - writer.writerow("hello") + writer.writerow("hellotesting123") writer.writerow(columns) @@ -96,7 +98,7 @@ def parse_row(columns, domain_info: DomainInformation, get_domain_managers, secu "First ready": domain.first_ready, "Deleted": domain.deleted, } - + if get_domain_managers: # Get each domain managers email and add to list dm_emails = [dm.email for dm in domain.permissions] From eb89ceb9f3f62f25cb15de72a66ee2528ed16490 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 12 Feb 2024 13:13:24 -0700 Subject: [PATCH 13/31] Update domain.py --- src/registrar/views/domain.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py index 04fe1ce3a..42db3b677 100644 --- a/src/registrar/views/domain.py +++ b/src/registrar/views/domain.py @@ -791,10 +791,11 @@ class DomainInvitationDeleteView(DomainInvitationPermissionDeleteView, SuccessMe object: DomainInvitation # workaround for type mismatch in DeleteView def get_success_url(self): + messages.success(self.request, self.get_success_message()) return reverse("domain-users", kwargs={"pk": self.object.domain.id}) - def get_success_message(self, cleaned_data): - return f"Successfully canceled invitation for {self.object.email}." + def get_success_message(self): + return f"Canceled invitation to {self.object.email}." class DomainDeleteUserView(UserDomainRolePermissionDeleteView): From 5412933d4d9158db0c51ea866f71041391e2e3e5 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 12 Feb 2024 15:24:55 -0700 Subject: [PATCH 14/31] Update domain.py --- src/registrar/views/domain.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py index 42db3b677..c7981f617 100644 --- a/src/registrar/views/domain.py +++ b/src/registrar/views/domain.py @@ -787,14 +787,13 @@ class DomainAddUserView(DomainFormBaseView): return redirect(self.get_success_url()) -class DomainInvitationDeleteView(DomainInvitationPermissionDeleteView, SuccessMessageMixin): +class DomainInvitationDeleteView(SuccessMessageMixin, DomainInvitationPermissionDeleteView): object: DomainInvitation # workaround for type mismatch in DeleteView def get_success_url(self): - messages.success(self.request, self.get_success_message()) return reverse("domain-users", kwargs={"pk": self.object.domain.id}) - def get_success_message(self): + def get_success_message(self, cleaned_data): return f"Canceled invitation to {self.object.email}." From f1f91669d7f64bd43b60e566ce504dc61b492339 Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Mon, 12 Feb 2024 15:02:36 -0800 Subject: [PATCH 15/31] Fix logic --- src/registrar/utility/csv_export.py | 53 +++++++++++------------------ 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/src/registrar/utility/csv_export.py b/src/registrar/utility/csv_export.py index 9ffbb057c..242c997de 100644 --- a/src/registrar/utility/csv_export.py +++ b/src/registrar/utility/csv_export.py @@ -14,18 +14,12 @@ from registrar.utility.enums import DefaultEmail logger = logging.getLogger(__name__) -def write_header(writer, columns, max_dm_count, get_domain_managers): +def write_header(writer, columns): """ Receives params from the parent methods and outputs a CSV with a header row. Works with write_header as long as the same writer object is passed. """ - # If we have domain managers, set column title dynamically here - if get_domain_managers: - for i in range(1, max_dm_count + 1): - columns.append(f"Domain manager email {i}") - - writer.writerow("hellotesting123") writer.writerow(columns) @@ -50,7 +44,7 @@ def get_domain_infos(filter_condition, sort_fields): return domain_infos_cleaned -def parse_row(columns, domain_info: DomainInformation, get_domain_managers, security_emails_dict=None): +def parse_row(columns, domain_info: DomainInformation, security_emails_dict=None, get_domain_managers=False): """Given a set of columns, generate a new row from cleaned column data""" # Domain should never be none when parsing this information @@ -101,11 +95,11 @@ def parse_row(columns, domain_info: DomainInformation, get_domain_managers, secu if get_domain_managers: # Get each domain managers email and add to list - dm_emails = [dm.email for dm in domain.permissions] + dm_emails = [dm.user.email for dm in domain.permissions.all()] - # Matching header for domain managers to be dynamic + # This is the row fields for i, dm_email in enumerate(dm_emails, start=1): - FIELDS[f"Domain Manager email {i}":dm_email] + FIELDS[f"Domain manager email {i}"] = dm_email row = [FIELDS.get(column, "") for column in columns] return row @@ -117,6 +111,7 @@ def write_body( sort_fields, filter_condition, get_domain_managers=False, + should_write_header=True, ): """ Receives params from the parent methods and outputs a CSV with fltered and sorted domains. @@ -151,18 +146,19 @@ def write_body( # We get the max so we can set the column header accurately max_dm_count = 0 paginator_ran = False - # Reduce the memory overhead when performing the write operation paginator = Paginator(all_domain_infos, 1000) for page_num in paginator.page_range: page = paginator.page(page_num) rows = [] for domain_info in page.object_list: - # Get count of all the domain managers for an account if get_domain_managers: - dm_count = len(domain_info.domain.permissions) + dm_count = len(domain_info.domain.permissions.all()) if dm_count > max_dm_count: max_dm_count = dm_count + for i in range(1, max_dm_count + 1): + if f"Domain manager email {i}" not in columns: + columns.append(f"Domain manager email {i}") try: row = parse_row(columns, domain_info, security_emails_dict, get_domain_managers) rows.append(row) @@ -171,13 +167,12 @@ def write_body( # It indicates that DomainInformation.domain is None. logger.error("csv_export -> Error when parsing row, domain was None") continue + # We only want this to run once just for the column header + if paginator_ran is False and should_write_header: + write_header(writer, columns) - # We only want this to run once just for the column header - if paginator_ran is False and "Domain name" in columns: - write_header(writer, columns, max_dm_count, get_domain_managers) - - writer.writerows(rows) - paginator_ran = True + writer.writerows(rows) + paginator_ran = True def export_data_type_to_csv(csv_file): @@ -214,8 +209,7 @@ def export_data_type_to_csv(csv_file): Domain.State.ON_HOLD, ], } - # write_header(writer, columns) - write_body(writer, columns, sort_fields, filter_condition, True) + write_body(writer, columns, sort_fields, filter_condition, True, True) def export_data_full_to_csv(csv_file): @@ -246,8 +240,7 @@ def export_data_full_to_csv(csv_file): Domain.State.ON_HOLD, ], } - # write_header(writer, columns) - write_body(writer, columns, sort_fields, filter_condition) + write_body(writer, columns, sort_fields, filter_condition, False, True) def export_data_federal_to_csv(csv_file): @@ -279,8 +272,7 @@ def export_data_federal_to_csv(csv_file): Domain.State.ON_HOLD, ], } - # write_header(writer, columns) - write_body(writer, columns, sort_fields, filter_condition) + write_body(writer, columns, sort_fields, filter_condition, False, True) def get_default_start_date(): @@ -347,10 +339,5 @@ def export_data_growth_to_csv(csv_file, start_date, end_date): "domain__deleted__gte": start_date_formatted, } - # write_header(writer, columns) - # Domains that got created - write_body(writer, columns, sort_fields, filter_condition) - # Domains that got deleted - # Have a way to skip the header for this one - - write_body(writer, columns, sort_fields_for_deleted_domains, filter_condition_for_deleted_domains) + write_body(writer, columns, sort_fields, filter_condition, False, True) + write_body(writer, columns, sort_fields_for_deleted_domains, filter_condition_for_deleted_domains, False, False) From 3c48fb9f7e54de29a603211bae8abe7faaa49041 Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Mon, 12 Feb 2024 15:26:31 -0800 Subject: [PATCH 16/31] Refactor parts of the code --- src/registrar/utility/csv_export.py | 66 +++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 17 deletions(-) diff --git a/src/registrar/utility/csv_export.py b/src/registrar/utility/csv_export.py index 242c997de..1c8f365cf 100644 --- a/src/registrar/utility/csv_export.py +++ b/src/registrar/utility/csv_export.py @@ -105,6 +105,51 @@ def parse_row(columns, domain_info: DomainInformation, security_emails_dict=None return row +# def _check_domain_managers(domain_info, columns): +# max_dm_count = 0 + +# dm_count = len(domain_info.domain.permissions.all()) +# if dm_count > max_dm_count: +# max_dm_count = dm_count +# for i in range(1, max_dm_count + 1): +# if f"Domain manager email {i}" not in columns: +# columns.append(f"Domain manager email {i}") + +# return columns + + +def _get_security_emails(sec_contact_ids): + """ + Retrieve security contact emails for the given security contact IDs. + """ + security_emails_dict = {} + public_contacts = ( + PublicContact.objects.only("email", "domain__name") + .select_related("domain") + .filter(registry_id__in=sec_contact_ids) + ) + + # Populate a dictionary of domain names and their security contacts + for contact in public_contacts: + domain: Domain = contact.domain + if domain is not None and domain.name not in security_emails_dict: + security_emails_dict[domain.name] = contact.email + else: + logger.warning("csv_export -> Domain was none for PublicContact") + + return security_emails_dict + + +def update_columns_with_domain_managers(columns, max_dm_count): + """ + Update the columns list to include "Domain manager email" headers + based on the maximum domain manager count. + """ + for i in range(1, max_dm_count + 1): + if f"Domain manager email {i}" not in columns: + columns.append(f"Domain manager email {i}") + + def write_body( writer, columns, @@ -127,24 +172,12 @@ def write_body( # Store all security emails to avoid epp calls or excessive filters sec_contact_ids = all_domain_infos.values_list("domain__security_contact_registry_id", flat=True) - security_emails_dict = {} - public_contacts = ( - PublicContact.objects.only("email", "domain__name") - .select_related("domain") - .filter(registry_id__in=sec_contact_ids) - ) - # Populate a dictionary of domain names and their security contacts - for contact in public_contacts: - domain: Domain = contact.domain - if domain is not None and domain.name not in security_emails_dict: - security_emails_dict[domain.name] = contact.email - else: - logger.warning("csv_export -> Domain was none for PublicContact") + security_emails_dict = _get_security_emails(sec_contact_ids) # The maximum amount of domain managers an account has - # We get the max so we can set the column header accurately max_dm_count = 0 + # We get the max so we can set the column header accurately paginator_ran = False # Reduce the memory overhead when performing the write operation paginator = Paginator(all_domain_infos, 1000) @@ -153,12 +186,11 @@ def write_body( rows = [] for domain_info in page.object_list: if get_domain_managers: + # _check_domain_managers(domain_info, columns) dm_count = len(domain_info.domain.permissions.all()) if dm_count > max_dm_count: max_dm_count = dm_count - for i in range(1, max_dm_count + 1): - if f"Domain manager email {i}" not in columns: - columns.append(f"Domain manager email {i}") + update_columns_with_domain_managers(columns, max_dm_count) try: row = parse_row(columns, domain_info, security_emails_dict, get_domain_managers) rows.append(row) From 8ea135b5a4b8aff3baf15dfe21cf640506976e3e Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Mon, 12 Feb 2024 16:48:33 -0800 Subject: [PATCH 17/31] Update unit tests --- src/registrar/tests/test_reports.py | 84 +++++++++++++++++++++++++---- src/registrar/utility/csv_export.py | 14 ----- 2 files changed, 75 insertions(+), 23 deletions(-) diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index 630904218..3ea6b3695 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -7,13 +7,14 @@ from registrar.models.domain import Domain from registrar.models.public_contact import PublicContact from registrar.models.user import User from django.contrib.auth import get_user_model +from registrar.models.user_domain_role import UserDomainRole from registrar.tests.common import MockEppLib from registrar.utility.csv_export import ( - write_header, write_body, get_default_start_date, get_default_end_date, ) + from django.core.management import call_command from unittest.mock import MagicMock, call, mock_open, patch from api.views import get_current_federal, get_current_full @@ -336,11 +337,28 @@ class ExportDataTest(MockEppLib): federal_agency="Armed Forces Retirement Home", ) + meoward_user = get_user_model().objects.create( + username="meoward_username", first_name="first_meoward", last_name="last_meoward", email="meoward@rocks.com" + ) + + _, created = UserDomainRole.objects.get_or_create( + user=meoward_user, domain=self.domain_1, role=UserDomainRole.Roles.MANAGER + ) + + _, created = UserDomainRole.objects.get_or_create( + user=self.user, domain=self.domain_1, role=UserDomainRole.Roles.MANAGER + ) + + _, created = UserDomainRole.objects.get_or_create( + user=meoward_user, domain=self.domain_2, role=UserDomainRole.Roles.MANAGER + ) + def tearDown(self): PublicContact.objects.all().delete() Domain.objects.all().delete() DomainInformation.objects.all().delete() User.objects.all().delete() + UserDomainRole.objects.all().delete() super().tearDown() def test_export_domains_to_writer_security_emails(self): @@ -383,7 +401,6 @@ class ExportDataTest(MockEppLib): } self.maxDiff = None # Call the export functions - write_header(writer, columns) write_body(writer, columns, sort_fields, filter_condition) # Reset the CSV file's position to the beginning csv_file.seek(0) @@ -440,7 +457,6 @@ class ExportDataTest(MockEppLib): ], } # Call the export functions - write_header(writer, columns) write_body(writer, columns, sort_fields, filter_condition) # Reset the CSV file's position to the beginning csv_file.seek(0) @@ -489,7 +505,6 @@ class ExportDataTest(MockEppLib): ], } # Call the export functions - write_header(writer, columns) write_body(writer, columns, sort_fields, filter_condition) # Reset the CSV file's position to the beginning csv_file.seek(0) @@ -567,7 +582,6 @@ class ExportDataTest(MockEppLib): } # Call the export functions - write_header(writer, columns) write_body( writer, columns, @@ -575,10 +589,7 @@ class ExportDataTest(MockEppLib): filter_condition, ) write_body( - writer, - columns, - sort_fields_for_deleted_domains, - filter_conditions_for_deleted_domains, + writer, columns, sort_fields_for_deleted_domains, filter_conditions_for_deleted_domains, False, False ) # Reset the CSV file's position to the beginning @@ -606,6 +617,61 @@ class ExportDataTest(MockEppLib): self.assertEqual(csv_content, expected_content) + def test_export_domains_to_writer_domain_managers(self): + """Test that export_domains_to_writer returns the + expected domain managers""" + with less_console_noise(): + # Create a CSV file in memory + csv_file = StringIO() + writer = csv.writer(csv_file) + # Define columns, sort fields, and filter condition + + columns = [ + "Domain name", + "Status", + "Expiration date", + "Domain type", + "Agency", + "Organization name", + "City", + "State", + "AO", + "AO email", + "Security contact email", + ] + sort_fields = ["domain__name"] + filter_condition = { + "domain__state__in": [ + Domain.State.READY, + Domain.State.DNS_NEEDED, + Domain.State.ON_HOLD, + ], + } + self.maxDiff = None + # Call the export functions + write_body(writer, columns, sort_fields, filter_condition, True, True) + # Reset the CSV file's position to the beginning + csv_file.seek(0) + # Read the content into a variable + csv_content = csv_file.read() + # We expect READY domains, + # sorted alphabetially by domain name + expected_content = ( + "Domain name,Status,Expiration date,Domain type,Agency," + "Organization name,City,State,AO,AO email," + "Security contact email,Domain manager email 1,Domain manager email 2,\n" + "adomain10.gov,Ready,,Federal,Armed Forces Retirement Home,,,, , ,\n" + "adomain2.gov,Dns needed,,Interstate,,,,, , , ,meoward@rocks.com\n" + "cdomain1.gov,Ready,,Federal - Executive,World War I Centennial Commission,,," + ", , , ,meoward@rocks.com,info@example.com\n" + "ddomain3.gov,On hold,,Federal,Armed Forces Retirement Home,,,, , , ,,\n" + ) + # Normalize line endings and remove commas, + # spaces and leading/trailing whitespace + csv_content = csv_content.replace(",,", "").replace(",", "").replace(" ", "").replace("\r\n", "\n").strip() + expected_content = expected_content.replace(",,", "").replace(",", "").replace(" ", "").strip() + self.assertEqual(csv_content, expected_content) + class HelperFunctions(TestCase): """This asserts that 1=1. Its limited usefulness lies in making sure the helper methods stay healthy.""" diff --git a/src/registrar/utility/csv_export.py b/src/registrar/utility/csv_export.py index 1c8f365cf..806e72952 100644 --- a/src/registrar/utility/csv_export.py +++ b/src/registrar/utility/csv_export.py @@ -105,19 +105,6 @@ def parse_row(columns, domain_info: DomainInformation, security_emails_dict=None return row -# def _check_domain_managers(domain_info, columns): -# max_dm_count = 0 - -# dm_count = len(domain_info.domain.permissions.all()) -# if dm_count > max_dm_count: -# max_dm_count = dm_count -# for i in range(1, max_dm_count + 1): -# if f"Domain manager email {i}" not in columns: -# columns.append(f"Domain manager email {i}") - -# return columns - - def _get_security_emails(sec_contact_ids): """ Retrieve security contact emails for the given security contact IDs. @@ -186,7 +173,6 @@ def write_body( rows = [] for domain_info in page.object_list: if get_domain_managers: - # _check_domain_managers(domain_info, columns) dm_count = len(domain_info.domain.permissions.all()) if dm_count > max_dm_count: max_dm_count = dm_count From d329ae6c8f1167f0100e832858e6c63ed17d489a Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Mon, 12 Feb 2024 17:46:24 -0800 Subject: [PATCH 18/31] Update comments --- src/registrar/templates/home.html | 2 +- src/registrar/utility/csv_export.py | 15 ++++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/registrar/templates/home.html b/src/registrar/templates/home.html index 2f4f6d2e9..9dd093de9 100644 --- a/src/registrar/templates/home.html +++ b/src/registrar/templates/home.html @@ -13,7 +13,7 @@ {% block messages %} {% include "includes/form_messages.html" %} {% endblock %} -

Manage your domains - TEST TEST 123

+

Manage your domains

diff --git a/src/registrar/utility/csv_export.py b/src/registrar/utility/csv_export.py index 806e72952..af4162489 100644 --- a/src/registrar/utility/csv_export.py +++ b/src/registrar/utility/csv_export.py @@ -97,7 +97,7 @@ def parse_row(columns, domain_info: DomainInformation, security_emails_dict=None # Get each domain managers email and add to list dm_emails = [dm.user.email for dm in domain.permissions.all()] - # This is the row fields + # Set up the "matching header" + row field data for i, dm_email in enumerate(dm_emails, start=1): FIELDS[f"Domain manager email {i}"] = dm_email @@ -129,7 +129,7 @@ def _get_security_emails(sec_contact_ids): def update_columns_with_domain_managers(columns, max_dm_count): """ - Update the columns list to include "Domain manager email" headers + Update the columns list to include "Domain manager email {#}" headers based on the maximum domain manager count. """ for i in range(1, max_dm_count + 1): @@ -148,13 +148,10 @@ def write_body( """ Receives params from the parent methods and outputs a CSV with fltered and sorted domains. Works with write_header as longas the same writer object is passed. + get_domain_managers: Conditional bc we only use domain manager info for export_data_full_to_csv + should_write_header: Conditional bc export_data_growth_to_csv calls write_body twice """ - # We only want to write the domain manager information for export_thing_here so we have to make it conditional - - # Trying to make the domain managers logic conditional - - # Get the domainInfos all_domain_infos = get_domain_infos(filter_condition, sort_fields) # Store all security emails to avoid epp calls or excessive filters @@ -163,8 +160,9 @@ def write_body( security_emails_dict = _get_security_emails(sec_contact_ids) # The maximum amount of domain managers an account has - max_dm_count = 0 # We get the max so we can set the column header accurately + max_dm_count = 0 + # Flag bc we don't want to set header every loop paginator_ran = False # Reduce the memory overhead when performing the write operation paginator = Paginator(all_domain_infos, 1000) @@ -185,7 +183,6 @@ def write_body( # It indicates that DomainInformation.domain is None. logger.error("csv_export -> Error when parsing row, domain was None") continue - # We only want this to run once just for the column header if paginator_ran is False and should_write_header: write_header(writer, columns) From 166135a2362a9b8bf3d74873f1a2f802d3e5a3a1 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 13 Feb 2024 10:35:38 -0700 Subject: [PATCH 19/31] Add comment --- src/registrar/views/domain.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py index c7981f617..653eb8661 100644 --- a/src/registrar/views/domain.py +++ b/src/registrar/views/domain.py @@ -786,7 +786,9 @@ class DomainAddUserView(DomainFormBaseView): return redirect(self.get_success_url()) - +# The order of the superclasses matters here. BaseDeleteView has a bug where the +# "form_valid" function does not call super, so it cannot use SuccessMessageMixin. +# The workaround is to use SuccessMessageMixin first. class DomainInvitationDeleteView(SuccessMessageMixin, DomainInvitationPermissionDeleteView): object: DomainInvitation # workaround for type mismatch in DeleteView From 5cf18eb5991d8a4eab45395b3ebfa8c3ad97b68a Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 13 Feb 2024 10:39:18 -0700 Subject: [PATCH 20/31] Lint --- src/registrar/views/domain.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py index 653eb8661..25625dd82 100644 --- a/src/registrar/views/domain.py +++ b/src/registrar/views/domain.py @@ -786,7 +786,8 @@ class DomainAddUserView(DomainFormBaseView): return redirect(self.get_success_url()) -# The order of the superclasses matters here. BaseDeleteView has a bug where the + +# The order of the superclasses matters here. BaseDeleteView has a bug where the # "form_valid" function does not call super, so it cannot use SuccessMessageMixin. # The workaround is to use SuccessMessageMixin first. class DomainInvitationDeleteView(SuccessMessageMixin, DomainInvitationPermissionDeleteView): From 6e062e841fc9f085d6f05a9a6c9743a237551e52 Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Tue, 13 Feb 2024 10:25:41 -0800 Subject: [PATCH 21/31] Update test comments --- src/registrar/tests/test_reports.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index 3ea6b3695..386acb253 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -341,6 +341,7 @@ class ExportDataTest(MockEppLib): username="meoward_username", first_name="first_meoward", last_name="last_meoward", email="meoward@rocks.com" ) + # Test for more than 1 domain manager _, created = UserDomainRole.objects.get_or_create( user=meoward_user, domain=self.domain_1, role=UserDomainRole.Roles.MANAGER ) @@ -349,6 +350,7 @@ class ExportDataTest(MockEppLib): user=self.user, domain=self.domain_1, role=UserDomainRole.Roles.MANAGER ) + # Test for just 1 domain manager _, created = UserDomainRole.objects.get_or_create( user=meoward_user, domain=self.domain_2, role=UserDomainRole.Roles.MANAGER ) From 3387ec032bf0ed715236865996d2b7cd8edc7be6 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Wed, 14 Feb 2024 12:09:27 -0500 Subject: [PATCH 22/31] handle logout when no session is present --- src/djangooidc/tests/test_views.py | 20 ++++++++++++++++++++ src/djangooidc/views.py | 6 +++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/djangooidc/tests/test_views.py b/src/djangooidc/tests/test_views.py index 4cd2241e3..462917947 100644 --- a/src/djangooidc/tests/test_views.py +++ b/src/djangooidc/tests/test_views.py @@ -327,6 +327,26 @@ class ViewsTest(TestCase): self.assertEqual(response.status_code, 302) self.assertEqual(actual, expected) + def test_logout_redirect_url_with_no_session_state(self, mock_client): + """Test that logout redirects to the configured post_logout_redirect_uris.""" + with less_console_noise(): + # MOCK + mock_client.callback.side_effect = self.user_info + mock_client.registration_response = {"post_logout_redirect_uris": ["http://example.com/back"]} + mock_client.provider_info = {"end_session_endpoint": "http://example.com/log_me_out"} + mock_client.client_id = "TEST" + # TEST + with less_console_noise(): + response = self.client.get(reverse("logout")) + # ASSERTIONS + expected = ( + "http://example.com/log_me_out?client_id=TEST" + "&post_logout_redirect_uri=http%3A%2F%2Fexample.com%2Fback" + ) + actual = response.url + self.assertEqual(response.status_code, 302) + self.assertEqual(actual, expected) + @patch("djangooidc.views.auth_logout") def test_logout_always_logs_out(self, mock_logout, _): """Without additional mocking, logout will always fail. diff --git a/src/djangooidc/views.py b/src/djangooidc/views.py index 444b8b950..2d3c842d2 100644 --- a/src/djangooidc/views.py +++ b/src/djangooidc/views.py @@ -145,8 +145,12 @@ def logout(request, next_page=None): user = request.user request_args = { "client_id": CLIENT.client_id, - "state": request.session["state"], } + # if state is not in request session, still redirect to the identity + # provider's logout url, but don't include the state in the url; this + # will successfully log out of the identity provider + if "state" in request.session: + request_args["state"] = request.session["state"] if ( "post_logout_redirect_uris" in CLIENT.registration_response.keys() and len(CLIENT.registration_response["post_logout_redirect_uris"]) > 0 From a8857ef18e917b9b81b7eefe23921d3751ec4669 Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Wed, 14 Feb 2024 13:09:25 -0800 Subject: [PATCH 23/31] Address refactor feedback --- src/registrar/utility/csv_export.py | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/registrar/utility/csv_export.py b/src/registrar/utility/csv_export.py index af4162489..1c2b64f3d 100644 --- a/src/registrar/utility/csv_export.py +++ b/src/registrar/utility/csv_export.py @@ -133,8 +133,7 @@ def update_columns_with_domain_managers(columns, max_dm_count): based on the maximum domain manager count. """ for i in range(1, max_dm_count + 1): - if f"Domain manager email {i}" not in columns: - columns.append(f"Domain manager email {i}") + columns.append(f"Domain manager email {i}") def write_body( @@ -159,22 +158,19 @@ def write_body( security_emails_dict = _get_security_emails(sec_contact_ids) - # The maximum amount of domain managers an account has - # We get the max so we can set the column header accurately - max_dm_count = 0 - # Flag bc we don't want to set header every loop - paginator_ran = False # Reduce the memory overhead when performing the write operation paginator = Paginator(all_domain_infos, 1000) + + if get_domain_managers: + # We want to get the max amont of domain managers an + # account has to set the column header dynamically + max_dm_count = max(len(domain_info.domain.permissions.all()) for domain_info in all_domain_infos) + update_columns_with_domain_managers(columns, max_dm_count) + for page_num in paginator.page_range: page = paginator.page(page_num) rows = [] for domain_info in page.object_list: - if get_domain_managers: - dm_count = len(domain_info.domain.permissions.all()) - if dm_count > max_dm_count: - max_dm_count = dm_count - update_columns_with_domain_managers(columns, max_dm_count) try: row = parse_row(columns, domain_info, security_emails_dict, get_domain_managers) rows.append(row) @@ -183,11 +179,10 @@ def write_body( # It indicates that DomainInformation.domain is None. logger.error("csv_export -> Error when parsing row, domain was None") continue - if paginator_ran is False and should_write_header: + if should_write_header: write_header(writer, columns) writer.writerows(rows) - paginator_ran = True def export_data_type_to_csv(csv_file): @@ -222,6 +217,7 @@ def export_data_type_to_csv(csv_file): Domain.State.READY, Domain.State.DNS_NEEDED, Domain.State.ON_HOLD, + Domain.State.UNKNOWN, # REMOVE ], } write_body(writer, columns, sort_fields, filter_condition, True, True) From 2dbf9cfa84d7a1847d0e8a9567ee215d5e3be866 Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Wed, 14 Feb 2024 13:33:41 -0800 Subject: [PATCH 24/31] Remove extra test line --- src/registrar/utility/csv_export.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/registrar/utility/csv_export.py b/src/registrar/utility/csv_export.py index 1c2b64f3d..85bc00e33 100644 --- a/src/registrar/utility/csv_export.py +++ b/src/registrar/utility/csv_export.py @@ -217,7 +217,6 @@ def export_data_type_to_csv(csv_file): Domain.State.READY, Domain.State.DNS_NEEDED, Domain.State.ON_HOLD, - Domain.State.UNKNOWN, # REMOVE ], } write_body(writer, columns, sort_fields, filter_condition, True, True) From 22cefd6ed8caf85f7709f029da0955b3ab470568 Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Wed, 14 Feb 2024 13:45:33 -0800 Subject: [PATCH 25/31] Add parameter logic --- src/registrar/tests/test_reports.py | 28 ++++++++++++++++++++++------ src/registrar/utility/csv_export.py | 17 ++++++++++++----- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index 386acb253..fa5acc96d 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -403,7 +403,10 @@ class ExportDataTest(MockEppLib): } self.maxDiff = None # Call the export functions - write_body(writer, columns, sort_fields, filter_condition) + write_body( + writer, columns, sort_fields, filter_condition, get_domain_managers=False, should_write_header=True + ) + # Reset the CSV file's position to the beginning csv_file.seek(0) # Read the content into a variable @@ -459,7 +462,9 @@ class ExportDataTest(MockEppLib): ], } # Call the export functions - write_body(writer, columns, sort_fields, filter_condition) + write_body( + writer, columns, sort_fields, filter_condition, get_domain_managers=False, should_write_header=True + ) # Reset the CSV file's position to the beginning csv_file.seek(0) # Read the content into a variable @@ -507,7 +512,9 @@ class ExportDataTest(MockEppLib): ], } # Call the export functions - write_body(writer, columns, sort_fields, filter_condition) + write_body( + writer, columns, sort_fields, filter_condition, get_domain_managers=False, should_write_header=True + ) # Reset the CSV file's position to the beginning csv_file.seek(0) # Read the content into a variable @@ -589,11 +596,17 @@ class ExportDataTest(MockEppLib): columns, sort_fields, filter_condition, + get_domain_managers=False, + should_write_header=True, ) write_body( - writer, columns, sort_fields_for_deleted_domains, filter_conditions_for_deleted_domains, False, False + writer, + columns, + sort_fields_for_deleted_domains, + filter_conditions_for_deleted_domains, + get_domain_managers=False, + should_write_header=False, ) - # Reset the CSV file's position to the beginning csv_file.seek(0) @@ -651,7 +664,10 @@ class ExportDataTest(MockEppLib): } self.maxDiff = None # Call the export functions - write_body(writer, columns, sort_fields, filter_condition, True, True) + write_body( + writer, columns, sort_fields, filter_condition, get_domain_managers=True, should_write_header=True + ) + # Reset the CSV file's position to the beginning csv_file.seek(0) # Read the content into a variable diff --git a/src/registrar/utility/csv_export.py b/src/registrar/utility/csv_export.py index 85bc00e33..1e4895f80 100644 --- a/src/registrar/utility/csv_export.py +++ b/src/registrar/utility/csv_export.py @@ -219,7 +219,7 @@ def export_data_type_to_csv(csv_file): Domain.State.ON_HOLD, ], } - write_body(writer, columns, sort_fields, filter_condition, True, True) + write_body(writer, columns, sort_fields, filter_condition, get_domain_managers=True, should_write_header=True) def export_data_full_to_csv(csv_file): @@ -250,7 +250,7 @@ def export_data_full_to_csv(csv_file): Domain.State.ON_HOLD, ], } - write_body(writer, columns, sort_fields, filter_condition, False, True) + write_body(writer, columns, sort_fields, filter_condition, get_domain_managers=False, should_write_header=True) def export_data_federal_to_csv(csv_file): @@ -282,7 +282,7 @@ def export_data_federal_to_csv(csv_file): Domain.State.ON_HOLD, ], } - write_body(writer, columns, sort_fields, filter_condition, False, True) + write_body(writer, columns, sort_fields, filter_condition, get_domain_managers=False, should_write_header=True) def get_default_start_date(): @@ -349,5 +349,12 @@ def export_data_growth_to_csv(csv_file, start_date, end_date): "domain__deleted__gte": start_date_formatted, } - write_body(writer, columns, sort_fields, filter_condition, False, True) - write_body(writer, columns, sort_fields_for_deleted_domains, filter_condition_for_deleted_domains, False, False) + write_body(writer, columns, sort_fields, filter_condition, get_domain_managers=False, should_write_header=True) + write_body( + writer, + columns, + sort_fields_for_deleted_domains, + filter_condition_for_deleted_domains, + get_domain_managers=False, + should_write_header=False, + ) From da30c2dda04ae7ae4fb00d318d9c306cd8cf9103 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Wed, 14 Feb 2024 16:45:50 -0500 Subject: [PATCH 26/31] removed help_text from fields in contact model --- ...email_alter_contact_first_name_and_more.py | 45 +++++++++++++++++++ src/registrar/models/contact.py | 6 --- 2 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 src/registrar/migrations/0069_alter_contact_email_alter_contact_first_name_and_more.py diff --git a/src/registrar/migrations/0069_alter_contact_email_alter_contact_first_name_and_more.py b/src/registrar/migrations/0069_alter_contact_email_alter_contact_first_name_and_more.py new file mode 100644 index 000000000..5869e6fae --- /dev/null +++ b/src/registrar/migrations/0069_alter_contact_email_alter_contact_first_name_and_more.py @@ -0,0 +1,45 @@ +# Generated by Django 4.2.7 on 2024-02-14 21:45 + +from django.db import migrations, models +import phonenumber_field.modelfields + + +class Migration(migrations.Migration): + dependencies = [ + ("registrar", "0068_domainapplication_notes_domaininformation_notes"), + ] + + operations = [ + migrations.AlterField( + model_name="contact", + name="email", + field=models.EmailField(blank=True, db_index=True, max_length=254, null=True), + ), + migrations.AlterField( + model_name="contact", + name="first_name", + field=models.TextField(blank=True, db_index=True, null=True, verbose_name="first name / given name"), + ), + migrations.AlterField( + model_name="contact", + name="last_name", + field=models.TextField(blank=True, db_index=True, null=True, verbose_name="last name / family name"), + ), + migrations.AlterField( + model_name="contact", + name="middle_name", + field=models.TextField(blank=True, null=True), + ), + migrations.AlterField( + model_name="contact", + name="phone", + field=phonenumber_field.modelfields.PhoneNumberField( + blank=True, db_index=True, max_length=128, null=True, region=None + ), + ), + migrations.AlterField( + model_name="contact", + name="title", + field=models.TextField(blank=True, null=True, verbose_name="title or role in your organization"), + ), + ] diff --git a/src/registrar/models/contact.py b/src/registrar/models/contact.py index ff7389780..ca1ff74c4 100644 --- a/src/registrar/models/contact.py +++ b/src/registrar/models/contact.py @@ -19,38 +19,32 @@ class Contact(TimeStampedModel): first_name = models.TextField( null=True, blank=True, - help_text="First name", verbose_name="first name / given name", db_index=True, ) middle_name = models.TextField( null=True, blank=True, - help_text="Middle name (optional)", ) last_name = models.TextField( null=True, blank=True, - help_text="Last name", verbose_name="last name / family name", db_index=True, ) title = models.TextField( null=True, blank=True, - help_text="Title", verbose_name="title or role in your organization", ) email = models.EmailField( null=True, blank=True, - help_text="Email", db_index=True, ) phone = PhoneNumberField( null=True, blank=True, - help_text="Phone", db_index=True, ) From f5a1348ccb51546dad370c3ab91c58eb4fba705c Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Wed, 14 Feb 2024 17:11:55 -0500 Subject: [PATCH 27/31] updated comment --- src/djangooidc/tests/test_views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/djangooidc/tests/test_views.py b/src/djangooidc/tests/test_views.py index 462917947..0f734b80d 100644 --- a/src/djangooidc/tests/test_views.py +++ b/src/djangooidc/tests/test_views.py @@ -339,6 +339,7 @@ class ViewsTest(TestCase): with less_console_noise(): response = self.client.get(reverse("logout")) # ASSERTIONS + # Assert redirect code and url are accurate expected = ( "http://example.com/log_me_out?client_id=TEST" "&post_logout_redirect_uri=http%3A%2F%2Fexample.com%2Fback" From e5a8bb031b5f9d4f92d0d6bf07f91d0d41d25012 Mon Sep 17 00:00:00 2001 From: CocoByte Date: Wed, 14 Feb 2024 15:40:09 -0700 Subject: [PATCH 28/31] Added migration step to deploy-stable and deploy-staging --- .github/workflows/deploy-stable.yaml | 8 ++++++++ .github/workflows/deploy-staging.yaml | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/.github/workflows/deploy-stable.yaml b/.github/workflows/deploy-stable.yaml index 1e643ef9a..0ded4a3a6 100644 --- a/.github/workflows/deploy-stable.yaml +++ b/.github/workflows/deploy-stable.yaml @@ -37,3 +37,11 @@ jobs: cf_org: cisa-dotgov cf_space: stable cf_manifest: "ops/manifests/manifest-stable.yaml" + - name: Run Django migrations + uses: cloud-gov/cg-cli-tools@main + with: + cf_username: ${{ secrets.CF_STABLE_USERNAME }} + cf_password: ${{ secrets.CF_STABLE_PASSWORD }} + cf_org: cisa-dotgov + cf_space: stable + cf_command: "run-task getgov-stable --command 'python manage.py migrate' --name migrate" \ No newline at end of file diff --git a/.github/workflows/deploy-staging.yaml b/.github/workflows/deploy-staging.yaml index fa4543637..1df08f412 100644 --- a/.github/workflows/deploy-staging.yaml +++ b/.github/workflows/deploy-staging.yaml @@ -37,3 +37,11 @@ jobs: cf_org: cisa-dotgov cf_space: staging cf_manifest: "ops/manifests/manifest-staging.yaml" + - name: Run Django migrations + uses: cloud-gov/cg-cli-tools@main + with: + cf_username: ${{ secrets.CF_STAGING_USERNAME }} + cf_password: ${{ secrets.CF_STAGING_PASSWORD }} + cf_org: cisa-dotgov + cf_space: staging + cf_command: "run-task getgov-staging --command 'python manage.py migrate' --name migrate" From a66fb36432f3c028cfe5b92f342bd55973ee0103 Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Thu, 15 Feb 2024 10:52:14 -0800 Subject: [PATCH 29/31] Update function naming and length check --- src/registrar/tests/test_reports.py | 16 ++++++++-------- src/registrar/utility/csv_export.py | 15 ++++++++------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index fa5acc96d..011c60b93 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -10,7 +10,7 @@ from django.contrib.auth import get_user_model from registrar.models.user_domain_role import UserDomainRole from registrar.tests.common import MockEppLib from registrar.utility.csv_export import ( - write_body, + write_csv, get_default_start_date, get_default_end_date, ) @@ -403,7 +403,7 @@ class ExportDataTest(MockEppLib): } self.maxDiff = None # Call the export functions - write_body( + write_csv( writer, columns, sort_fields, filter_condition, get_domain_managers=False, should_write_header=True ) @@ -427,7 +427,7 @@ class ExportDataTest(MockEppLib): expected_content = expected_content.replace(",,", "").replace(",", "").replace(" ", "").strip() self.assertEqual(csv_content, expected_content) - def test_write_body(self): + def test_write_csv(self): """Test that write_body returns the existing domain, test that sort by domain name works, test that filter works""" @@ -462,7 +462,7 @@ class ExportDataTest(MockEppLib): ], } # Call the export functions - write_body( + write_csv( writer, columns, sort_fields, filter_condition, get_domain_managers=False, should_write_header=True ) # Reset the CSV file's position to the beginning @@ -512,7 +512,7 @@ class ExportDataTest(MockEppLib): ], } # Call the export functions - write_body( + write_csv( writer, columns, sort_fields, filter_condition, get_domain_managers=False, should_write_header=True ) # Reset the CSV file's position to the beginning @@ -591,7 +591,7 @@ class ExportDataTest(MockEppLib): } # Call the export functions - write_body( + write_csv( writer, columns, sort_fields, @@ -599,7 +599,7 @@ class ExportDataTest(MockEppLib): get_domain_managers=False, should_write_header=True, ) - write_body( + write_csv( writer, columns, sort_fields_for_deleted_domains, @@ -664,7 +664,7 @@ class ExportDataTest(MockEppLib): } self.maxDiff = None # Call the export functions - write_body( + write_csv( writer, columns, sort_fields, filter_condition, get_domain_managers=True, should_write_header=True ) diff --git a/src/registrar/utility/csv_export.py b/src/registrar/utility/csv_export.py index 1e4895f80..90e80f551 100644 --- a/src/registrar/utility/csv_export.py +++ b/src/registrar/utility/csv_export.py @@ -136,7 +136,7 @@ def update_columns_with_domain_managers(columns, max_dm_count): columns.append(f"Domain manager email {i}") -def write_body( +def write_csv( writer, columns, sort_fields, @@ -161,7 +161,7 @@ def write_body( # Reduce the memory overhead when performing the write operation paginator = Paginator(all_domain_infos, 1000) - if get_domain_managers: + if get_domain_managers and len(all_domain_infos) > 0: # We want to get the max amont of domain managers an # account has to set the column header dynamically max_dm_count = max(len(domain_info.domain.permissions.all()) for domain_info in all_domain_infos) @@ -179,6 +179,7 @@ def write_body( # It indicates that DomainInformation.domain is None. logger.error("csv_export -> Error when parsing row, domain was None") continue + if should_write_header: write_header(writer, columns) @@ -219,7 +220,7 @@ def export_data_type_to_csv(csv_file): Domain.State.ON_HOLD, ], } - write_body(writer, columns, sort_fields, filter_condition, get_domain_managers=True, should_write_header=True) + write_csv(writer, columns, sort_fields, filter_condition, get_domain_managers=True, should_write_header=True) def export_data_full_to_csv(csv_file): @@ -250,7 +251,7 @@ def export_data_full_to_csv(csv_file): Domain.State.ON_HOLD, ], } - write_body(writer, columns, sort_fields, filter_condition, get_domain_managers=False, should_write_header=True) + write_csv(writer, columns, sort_fields, filter_condition, get_domain_managers=False, should_write_header=True) def export_data_federal_to_csv(csv_file): @@ -282,7 +283,7 @@ def export_data_federal_to_csv(csv_file): Domain.State.ON_HOLD, ], } - write_body(writer, columns, sort_fields, filter_condition, get_domain_managers=False, should_write_header=True) + write_csv(writer, columns, sort_fields, filter_condition, get_domain_managers=False, should_write_header=True) def get_default_start_date(): @@ -349,8 +350,8 @@ def export_data_growth_to_csv(csv_file, start_date, end_date): "domain__deleted__gte": start_date_formatted, } - write_body(writer, columns, sort_fields, filter_condition, get_domain_managers=False, should_write_header=True) - write_body( + write_csv(writer, columns, sort_fields, filter_condition, get_domain_managers=False, should_write_header=True) + write_csv( writer, columns, sort_fields_for_deleted_domains, From 0e23946cf85ad74b42b14e4c84d82a8b6aa27527 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 20 Feb 2024 10:45:49 -0700 Subject: [PATCH 30/31] Bug fix --- src/registrar/models/domain_information.py | 6 ++++++ src/registrar/models/utility/domain_helper.py | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/registrar/models/domain_information.py b/src/registrar/models/domain_information.py index acaa330bb..b35f41ee4 100644 --- a/src/registrar/models/domain_information.py +++ b/src/registrar/models/domain_information.py @@ -255,6 +255,12 @@ class DomainInformation(TimeStampedModel): else: da_many_to_many_dict[field] = getattr(domain_application, field).all() + # This will not happen in normal code flow, but having some redundancy doesn't hurt. + # da_dict should not have "id" under any circumstances. + if "id" in da_dict: + logger.warning("create_from_da() -> Found attribute 'id' when trying to create") + da_dict.pop("id", None) + # Create a placeholder DomainInformation object domain_info = DomainInformation(**da_dict) diff --git a/src/registrar/models/utility/domain_helper.py b/src/registrar/models/utility/domain_helper.py index 230b23e16..9e3559676 100644 --- a/src/registrar/models/utility/domain_helper.py +++ b/src/registrar/models/utility/domain_helper.py @@ -180,8 +180,8 @@ class DomainHelper: """ # Get a list of the existing fields on model_1 and model_2 - model_1_fields = set(field.name for field in model_1._meta.get_fields() if field != "id") - model_2_fields = set(field.name for field in model_2._meta.get_fields() if field != "id") + model_1_fields = set(field.name for field in model_1._meta.get_fields() if field.name != "id") + model_2_fields = set(field.name for field in model_2._meta.get_fields() if field.name != "id") # Get the fields that exist on both DomainApplication and DomainInformation common_fields = model_1_fields & model_2_fields From 0d23007fcd316f8c4093e7e5bbf9b99b84c5fa76 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 20 Feb 2024 11:13:09 -0700 Subject: [PATCH 31/31] Add some additional information --- src/registrar/models/domain_information.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/registrar/models/domain_information.py b/src/registrar/models/domain_information.py index b35f41ee4..1a50efe2c 100644 --- a/src/registrar/models/domain_information.py +++ b/src/registrar/models/domain_information.py @@ -257,6 +257,8 @@ class DomainInformation(TimeStampedModel): # This will not happen in normal code flow, but having some redundancy doesn't hurt. # da_dict should not have "id" under any circumstances. + # If it does have it, then this indicates that common_fields is overzealous in the data + # that it is returning. Try looking in DomainHelper.get_common_fields. if "id" in da_dict: logger.warning("create_from_da() -> Found attribute 'id' when trying to create") da_dict.pop("id", None)